diff --git a/CHANGELOG.md b/CHANGELOG.md index d69567476bccc..e5f77111a401b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,63 @@ CHANGELOG Swift Next ---------- +* [SR-11298][]: + + A class-constrained protocol extension, where the extended protocol does + not impose a class constraint, will now infer the constraint implicitly. + + ```swift + protocol Foo {} + class Bar: Foo { + var someProperty: Int = 0 + } + + // Even though 'Foo' does not impose a class constraint, it is automatically + // inferred due to the Self: Bar constraint. + extension Foo where Self: Bar { + var anotherProperty: Int { + get { return someProperty } + // As a result, the setter is now implicitly nonmutating, just like it would + // be if 'Foo' had a class constraint. + set { someProperty = newValue } + } + } + ``` + + As a result, this could lead to code that currently compiles today to throw an error. + + ```swift + protocol Foo { + var someProperty: Int { get set } + } + + class Bar: Foo { + var someProperty = 0 + } + + extension Foo where Self: Bar { + var anotherProperty1: Int { + get { return someProperty } + // This will now error, because the protocol requirement + // is implicitly mutating and the setter is implicitly + // nonmutating. + set { someProperty = newValue } // Error + } + } + ``` + + **Workaround**: Define a new mutable variable inside the setter that has a reference to `self`: + + ```swift + var anotherProperty1: Int { + get { return someProperty } + set { + var mutableSelf = self + mutableSelf.someProperty = newValue // Okay + } + } +``` + * [SE-0253][]: Values of types that declare `func callAsFunction` methods can be called @@ -51,7 +108,7 @@ Swift Next * [SR-4206][]: - A method override is no longer allowed to have a generic signature with + A method override is no longer allowed to have a generic signature with requirements not imposed by the base method. For example: ``` @@ -7765,3 +7822,4 @@ Swift 1.0 [SR-8974]: [SR-9043]: [SR-9827]: +[SR-11298]: diff --git a/cmake/modules/SwiftHandleGybSources.cmake b/cmake/modules/SwiftHandleGybSources.cmake index 1d37e4ae80958..16884f61edcf5 100644 --- a/cmake/modules/SwiftHandleGybSources.cmake +++ b/cmake/modules/SwiftHandleGybSources.cmake @@ -118,10 +118,13 @@ function(handle_gyb_sources dependency_out_var_name sources_var_name arch) "${SWIFT_SOURCE_DIR}/utils/gyb_syntax_support/AttributeNodes.py" "${SWIFT_SOURCE_DIR}/utils/gyb_syntax_support/AvailabilityNodes.py" "${SWIFT_SOURCE_DIR}/utils/gyb_syntax_support/CommonNodes.py" + "${SWIFT_SOURCE_DIR}/utils/gyb_syntax_support/CompletionOnlyNodes.py" "${SWIFT_SOURCE_DIR}/utils/gyb_syntax_support/DeclNodes.py" "${SWIFT_SOURCE_DIR}/utils/gyb_syntax_support/ExprNodes.py" "${SWIFT_SOURCE_DIR}/utils/gyb_syntax_support/GenericNodes.py" + "${SWIFT_SOURCE_DIR}/utils/gyb_syntax_support/NodeSerializationCodes.py" "${SWIFT_SOURCE_DIR}/utils/gyb_syntax_support/PatternNodes.py" + "${SWIFT_SOURCE_DIR}/utils/gyb_syntax_support/SILOnlyNodes.py" "${SWIFT_SOURCE_DIR}/utils/gyb_syntax_support/StmtNodes.py" "${SWIFT_SOURCE_DIR}/utils/gyb_syntax_support/TypeNodes.py" "${SWIFT_SOURCE_DIR}/utils/gyb_syntax_support/Token.py" diff --git a/docs/CToSwiftNameTranslation.md b/docs/CToSwiftNameTranslation.md index e53e3441489df..ed3960f223d4c 100644 --- a/docs/CToSwiftNameTranslation.md +++ b/docs/CToSwiftNameTranslation.md @@ -1,6 +1,6 @@ # Name Translation from C to Swift -This document gives a high-level description of how C and Objective-C declarations are translated to Swift, with particular focus on how names are adjusted. It is not attempting to be a *complete* description of everything the compiler does except with regards to how *names* are transformed; even there, some special cases that only apply to Apple's SDKs have been omitted. +This document gives a high-level description of how C and Objective-C declarations are translated to Swift, with particular focus on how names are adjusted. It is not attempting to be a *complete* description of everything the compiler does except with regards to how *names* are transformed; even there, some special cases that only apply to Apple's SDKs have been omitted. The example code shown is for illustrative purposes and does not always include all parts of an imported API's interface. ## Word boundaries @@ -239,4 +239,208 @@ _The original intent of the `swift_private` attribute was additionally to limit _For "historical reasons", the `swift_private` attribute is ignored on factory methods with no arguments imported as initializers. This is essentially matching the behavior of older Swift compilers for source compatibility in case someone has marked such a factory method as `swift_private`._ +## Custom names + +The `swift_name` Clang attribute can be used to control how a declaration imports into Swift. If it's valid, the value of the `swift_name` attribute always overrides any other name transformation rules (prefix-stripping, underscore-prepending, etc.) + +### Types and globals + +The `swift_name` attribute can be used to give a type or a global a custom name. In the simplest form, the value of the attribute must be a valid Swift identifier. + +```objc +__attribute__((swift_name("SpacecraftCoordinates"))) +struct SPKSpacecraftCoordinates { + double x, y, z, t; // space and time, of course +}; +``` + +```swift +struct SpacecraftCoordinates { + var x, y, z, t: Double +} +``` + +### Import-as-member + +A custom name that starts with an identifier followed by a period is taken to be a member name. The identifier should be the imported Swift name of a C/Objective-C type in the same module. In this case, the type or global will be imported as a static member of the named type. + +```objc +__attribute__((swift_name("SpacecraftCoordinates.earth"))) +extern const struct SPKSpacecraftCoordinates SPKSpacecraftCoordinatesEarth; +``` + +```swift +extension SpacecraftCoordinates { + static var earth: SpacecraftCoordinates { get } +} +``` + +Note that types cannot be imported as members of protocols. + +_The "in the same module" restriction is considered a technical limitation; a forward declaration of the base type will work around it._ + + +### C functions with custom names + +The `swift_name` attribute can be used to give a C function a custom name. The value of the attribute must be a full Swift function name, including parameter labels. + +```objc +__attribute__((swift_name("doSomething(to:bar:)"))) +void doSomethingToFoo(Foo *foo, int bar); + +// Usually seen as NS_SWIFT_NAME. +``` + +```swift +func doSomething(foo: UnsafeMutablePointer, bar: Int32) +``` + +An underscore can be used in place of an empty parameter label, as in Swift. + +A C function with zero arguments and a non-`void` return type can also be imported as a computed variable by using the `getter:` prefix on the name. A function with one argument and a `void` return type can optionally serve as the setter for that variable using `setter:`. + +```objc +__attribute__((swift_name("getter:globalCounter()"))) +int getGlobalCounter(void); +__attribute__((swift_name("setter:globalCounter(_:)"))) +void setGlobalCounter(int newValue); +``` + +```swift +var globalCounter: Int32 { get set } +``` + +Note that the argument lists must still be present even though the name used is the name of the variable. (Also note the `void` parameter list to specify a C function with zero arguments. This is required!) + +Variables with setters and no getters are not supported. + + +#### Import-as-member + +Like types and globals, functions can be imported as static members of types. + +```objc +__attribute__((swift_name("NSSound.beep()"))) +void NSBeep(void); +``` + +```swift +extension NSSound { + static func beep() +} +``` + +However, by giving a parameter the label `self`, a function can also be imported as an instance member of a type __T__. In this case, the parameter labeled `self` must either have the type __T__ itself, or be a pointer to __T__. The latter is only valid if __T__ is imported as a value type; if the pointer is non-`const`, the resulting method will be `mutating`. If __T__ is a class, the function will be `final`. + +```objc +typedef struct { + int value; +} Counter; + +__attribute__((swift_name("Counter.printValue(self:)"))) +void CounterPrintValue(Counter c); +__attribute__((swift_name("Counter.printValue2(self:)"))) +void CounterPrintValue2(const Counter *c); +__attribute__((swift_name("Counter.resetValue(self:)"))) +void CounterResetValue(Counter *c); +``` + +```swift +struct Counter { + var value: Int32 { get set } +} + +extension Counter { + func printValue() + func printValue2() + mutating func resetValue() +} +``` + +This also applies to getters and setters, to be imported as instance properties. + +```objc +__attribute__((swift_name("getter:Counter.absoluteValue(self:)"))) +int CounterGetAbsoluteValue(Counter c); +``` + +```swift +extension Counter { + var absoluteValue: Int32 { get } +} +``` + +The getter/setter syntax also allows for subscripts by using the base name `subscript`. + +```objc +__attribute__((swift_name("getter:LinkedListOfInts.subscript(self:_:)"))) +int LinkedListGetAtIndex(const LinkedListOfInts *head, int index); +``` + +```swift +extension LinkedListOfInts { + subscript(_ index: Int32) -> Int32 { get } +} +``` + +Finally, functions can be imported as initializers as well by using the base name `init`. These are considered "factory" initializers and are never inherited or overridable. They must not have a `self` parameter. + +```objc +__attribute__((swift_name("Counter.init(initialValue:)"))) +Counter CounterCreateWithInitialValue(int value); +``` + +```swift +extension Counter { + /* non-inherited */ init(initialValue value: Int32) +} +``` + + +### Enumerators (enum cases) + +The `swift_name` attribute can be used to rename enumerators. As mentioned above, not only does no further prefix-stripping occur on the resulting name, but the presence of a custom name removes the enum case from the computation of a prefix for the other cases. + +``` +// Actual example from Apple's SDKs; in fact, the first shipping example of +// swift_name on an enumerator at all! +typedef NS_ENUM(NSUInteger, NSXMLNodeKind) { + NSXMLInvalidKind = 0, + NSXMLDocumentKind, + NSXMLElementKind, + NSXMLAttributeKind, + NSXMLNamespaceKind, + NSXMLProcessingInstructionKind, + NSXMLCommentKind, + NSXMLTextKind, + NSXMLDTDKind NS_SWIFT_NAME(DTDKind), + NSXMLEntityDeclarationKind, + NSXMLAttributeDeclarationKind, + NSXMLElementDeclarationKind, + NSXMLNotationDeclarationKind +}; +``` + +``` +public enum Kind : UInt { + case invalid + case document + case element + case attribute + case namespace + case processingInstruction + case comment + case text + case DTDKind + case entityDeclaration + case attributeDeclaration + case elementDeclaration + case notationDeclaration +} +``` + +Although enumerators always have global scope in C, they are often imported as members in Swift, and thus the `swift_name` attribute cannot be used to import them as members of another type unless the enum type is anonymous. + +_Currently, `swift_name` does not even allow importing an enum case as a member of the enum type itself, even if the enum is not recognized as an `@objc` enum, error code enum, or option set (i.e. the situation where a case is imported as a global constant)._ + ## More to come... diff --git a/docs/SIL.rst b/docs/SIL.rst index 5c31448f66eaf..f919cb2f46ebb 100644 --- a/docs/SIL.rst +++ b/docs/SIL.rst @@ -17,8 +17,10 @@ the Swift programming language. SIL accommodates the following use cases: such as definitive initialization of variables and constructors, code reachability, switch coverage. - High-level optimization passes, including retain/release optimization, - dynamic method devirtualization, closure inlining, memory allocation promotion, - and generic function instantiation. + dynamic method devirtualization, closure inlining, promoting heap allocations + to stack allocations, promoting stack allocations to SSA registers, scalar + replacement of aggregates (splitting aggregate allocations into multiple + smaller allocations), and generic function instantiation. - A stable distribution format that can be used to distribute "fragile" inlineable or generic code with Swift library modules, to be optimized into client binaries. diff --git a/include/swift/AST/ASTContext.h b/include/swift/AST/ASTContext.h index eb63505035286..a4d9a1213c52d 100644 --- a/include/swift/AST/ASTContext.h +++ b/include/swift/AST/ASTContext.h @@ -502,6 +502,8 @@ class ASTContext final { /// Retrieve the declaration of ObjectiveC.ObjCBool. StructDecl *getObjCBoolDecl() const; + /// Retrieve the declaration of Foundation.NSCopying. + ProtocolDecl *getNSCopyingDecl() const; /// Retrieve the declaration of Foundation.NSError. ClassDecl *getNSErrorDecl() const; /// Retrieve the declaration of Foundation.NSNumber. diff --git a/include/swift/AST/ASTScope.h b/include/swift/AST/ASTScope.h index 74f77f9fc6fca..7a6bc43b825c5 100644 --- a/include/swift/AST/ASTScope.h +++ b/include/swift/AST/ASTScope.h @@ -38,6 +38,16 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" +/// In case there's a bug in the ASTScope lookup system, suggest that the user +/// try disabling it. +/// \p message must be a string literal +#define ASTScopeAssert(predicate, message) \ + assert((predicate) && message \ + " Try compiling with '-disable-astscope-lookup'.") + +#define ASTScope_unreachable(message) \ + llvm_unreachable(message " Try compiling with '-disable-astscope-lookup'.") + namespace swift { #pragma mark Forward-references @@ -125,10 +135,10 @@ class ASTScopeImpl { /// Must clear source range change whenever this changes Children storedChildren; - /// Because expansion returns an insertion point, - /// if a scope is reexpanded, the children added NOT by expansion must be - /// rescued and reused. - unsigned childrenCountWhenLastExpanded = 0; + bool wasExpanded = false; + + /// For use-before-def, ASTAncestor scopes may be added to a BraceStmt. + unsigned astAncestorScopeCount = 0; /// Can clear storedChildren, so must remember this bool haveAddedCleanup = false; @@ -162,7 +172,7 @@ class ASTScopeImpl { void *operator new(size_t bytes, const ASTContext &ctx, unsigned alignment = alignof(ASTScopeImpl)); void *operator new(size_t Bytes, void *Mem) { - assert(Mem); + ASTScopeAssert(Mem, "Allocation failed"); return Mem; } @@ -180,12 +190,13 @@ class ASTScopeImpl { public: // for addReusedBodyScopes void addChild(ASTScopeImpl *child, ASTContext &); - std::vector rescueYoungestChildren(unsigned count); + std::vector rescueASTAncestorScopesForReuseFromMe(); /// When reexpanding, do we always create a new body? - virtual NullablePtr getParentOfRescuedScopes(); - std::vector rescueScopesToReuse(); - void addReusedScopes(ArrayRef); + virtual NullablePtr getParentOfASTAncestorScopesToBeRescued(); + std::vector + rescueASTAncestorScopesForReuseFromMeOrDescendants(); + void replaceASTAncestorScopes(ArrayRef); private: void removeChildren(); @@ -196,6 +207,8 @@ class ASTScopeImpl { public: void preOrderDo(function_ref); + /// Like preorderDo but without myself. + void preOrderChildrenDo(function_ref); void postOrderDo(function_ref); #pragma mark - source ranges @@ -219,6 +232,12 @@ class ASTScopeImpl { bool doesRangeMatch(unsigned start, unsigned end, StringRef file = "", StringRef className = ""); + unsigned countDescendants() const; + + /// Make sure that when the argument is executed, there are as many + /// descendants after as before. + void assertThatTreeDoesNotShrink(function_ref); + private: SourceRange computeSourceRangeOfScope(bool omitAssertions = false) const; SourceRange @@ -253,6 +272,8 @@ class ASTScopeImpl { void ensureSourceRangesAreCorrectWhenAddingDescendants(function_ref); public: // public for debugging + /// Returns source range of this node alone, without factoring in any + /// children. virtual SourceRange getSourceRangeOfThisASTNode(bool omitAssertions = false) const = 0; @@ -314,10 +335,17 @@ class ASTScopeImpl { /// Return the scope into which to place subsequent decls ASTScopeImpl *expandAndBeCurrent(ScopeCreator &); + unsigned getASTAncestorScopeCount() const { return astAncestorScopeCount; } + bool getWasExpanded() const { return wasExpanded; } + protected: + void resetASTAncestorScopeCount() { astAncestorScopeCount = 0; } + void increaseASTAncestorScopeCount(unsigned c) { astAncestorScopeCount += c; } + void setWasExpanded() { wasExpanded = true; } virtual ASTScopeImpl *expandSpecifically(ScopeCreator &) = 0; virtual void beCurrent(); - virtual bool isCurrent() const; + bool isCurrent() const; + virtual bool isCurrentIfWasExpanded() const; private: /// Compare the pre-expasion range with the post-expansion range and return @@ -328,6 +356,8 @@ class ASTScopeImpl { /// Some scopes can be expanded lazily. /// Such scopes must: not change their source ranges after expansion, and /// their expansion must return an insertion point outside themselves. + /// After a node is expanded, its source range (getSourceRangeofThisASTNode + /// union children's ranges) must be same as this. virtual NullablePtr insertionPointForDeferredExpansion(); virtual SourceRange sourceRangeForDeferredExpansion() const; @@ -356,9 +386,6 @@ class ASTScopeImpl { virtual ScopeCreator &getScopeCreator(); -protected: - void setChildrenCountWhenLastExpanded(); - #pragma mark - - creation queries public: virtual bool isThisAnAbstractStorageDecl() const { return false; } @@ -506,6 +533,7 @@ class ASTSourceFileScope final : public ASTScopeImpl { /// The number of \c Decls in the \c SourceFile that were already seen. /// Since parsing can be interleaved with type-checking, on every /// lookup, look at creating scopes for any \c Decls beyond this number. + /// rdar://55562483 Unify with numberOfChildrenWhenLastExpanded int numberOfDeclsAlreadySeen = 0; ASTSourceFileScope(SourceFile *SF, ScopeCreator *scopeCreator); @@ -521,7 +549,9 @@ class ASTSourceFileScope final : public ASTScopeImpl { NullablePtr getDeclContext() const override; void addNewDeclsToScopeTree(); - void buildScopeTreeEagerly(); + void buildFullyExpandedTree(); + void + buildEnoughOfTreeForTopLevelExpressionsButDontRequestGenericsOrExtendedNominals(); const SourceFile *getSourceFile() const override; NullablePtr addressForPrinting() const override { return SF; } @@ -552,7 +582,7 @@ class Portion { void *operator new(size_t bytes, const ASTContext &ctx, unsigned alignment = alignof(ASTScopeImpl)); void *operator new(size_t Bytes, void *Mem) { - assert(Mem); + ASTScopeAssert(Mem, "Allocation failed"); return Mem; } @@ -575,12 +605,12 @@ class Portion { virtual const Decl * getReferrentOfScope(const GenericTypeOrExtensionScope *s) const; - virtual void beCurrent(IterableTypeScope *) const; - virtual bool isCurrent(const IterableTypeScope *) const; + virtual void beCurrent(IterableTypeScope *) const = 0; + virtual bool isCurrentIfWasExpanded(const IterableTypeScope *) const = 0; virtual NullablePtr - insertionPointForDeferredExpansion(IterableTypeScope *) const; + insertionPointForDeferredExpansion(IterableTypeScope *) const = 0; virtual SourceRange - sourceRangeForDeferredExpansion(const IterableTypeScope *) const; + sourceRangeForDeferredExpansion(const IterableTypeScope *) const = 0; }; // For the whole Decl scope of a GenericType or an Extension @@ -601,6 +631,24 @@ class Portion { const Decl * getReferrentOfScope(const GenericTypeOrExtensionScope *s) const override; + + /// Make whole portion lazy to avoid circularity in lookup of generic + /// parameters of extensions. When \c bindExtension is called, it needs to + /// unqualifed-lookup the type being extended. That causes an \c + /// ExtensionScope + /// (\c GenericTypeOrExtensionWholePortion) to be built. + /// The building process needs the generic parameters, but that results in a + /// request for the extended nominal type of the \c ExtensionDecl, which is + /// an endless recursion. Although we only need to make \c ExtensionScope + /// lazy, might as well do it for all \c IterableTypeScopes. + + void beCurrent(IterableTypeScope *) const override; + bool isCurrentIfWasExpanded(const IterableTypeScope *) const override; + + NullablePtr + insertionPointForDeferredExpansion(IterableTypeScope *) const override; + SourceRange + sourceRangeForDeferredExpansion(const IterableTypeScope *) const override; }; /// GenericTypeOrExtension = GenericType or Extension @@ -639,6 +687,14 @@ class GenericTypeOrExtensionWherePortion final SourceRange getChildlessSourceRangeOf(const GenericTypeOrExtensionScope *, bool omitAssertions) const override; + + void beCurrent(IterableTypeScope *) const override; + bool isCurrentIfWasExpanded(const IterableTypeScope *) const override; + + NullablePtr + insertionPointForDeferredExpansion(IterableTypeScope *) const override; + SourceRange + sourceRangeForDeferredExpansion(const IterableTypeScope *) const override; }; /// Behavior specific to representing the Body of a NominalTypeDecl or @@ -655,7 +711,7 @@ class IterableTypeBodyPortion final bool omitAssertions) const override; void beCurrent(IterableTypeScope *) const override; - bool isCurrent(const IterableTypeScope *) const override; + bool isCurrentIfWasExpanded(const IterableTypeScope *) const override; NullablePtr insertionPointForDeferredExpansion(IterableTypeScope *) const override; SourceRange @@ -694,6 +750,17 @@ class GenericTypeOrExtensionScope : public ASTScopeImpl { SourceRange getSourceRangeOfThisASTNode(bool omitAssertions = false) const override; + /// \c tryBindExtension needs to get the extended nominal, and the DeclContext + /// is the parent of the \c ExtensionDecl. If the \c SourceRange of an \c + /// ExtensionScope were to start where the \c ExtensionDecl says, the lookup + /// source locaiton would fall within the \c ExtensionScope. This inclusion + /// would cause the lazy \c ExtensionScope to be expanded which would ask for + /// its generic parameters in order to create those sub-scopes. That request + /// would cause a cycle because it would ask for the extended nominal. So, + /// move the source range of an \c ExtensionScope *past* the extended nominal + /// type, which is not in-scope there anyway. + virtual SourceRange moveStartPastExtendedNominal(SourceRange) const = 0; + virtual GenericContext *getGenericContext() const = 0; std::string getClassName() const override; virtual std::string declKindName() const = 0; @@ -732,6 +799,8 @@ class GenericTypeScope : public GenericTypeOrExtensionScope { public: GenericTypeScope(const Portion *p) : GenericTypeOrExtensionScope(p) {} virtual ~GenericTypeScope() {} + SourceRange moveStartPastExtendedNominal(SourceRange) const override; + protected: NullablePtr genericParams() const override; }; @@ -753,9 +822,11 @@ class IterableTypeScope : public GenericTypeScope { protected: void beCurrent() override; - bool isCurrent() const override; + bool isCurrentIfWasExpanded() const override; public: + void makeWholeCurrent(); + bool isWholeCurrent() const; void makeBodyCurrent(); bool isBodyCurrent() const; NullablePtr insertionPointForDeferredExpansion() override; @@ -804,6 +875,7 @@ class ExtensionScope final : public IterableTypeScope { NullablePtr getCorrespondingNominalTypeDecl() const override; std::string declKindName() const override { return "Extension"; } SourceRange getBraces() const override; + SourceRange moveStartPastExtendedNominal(SourceRange) const override; ASTScopeImpl *createTrailingWhereClauseScope(ASTScopeImpl *parent, ScopeCreator &) override; void createBodyScope(ASTScopeImpl *leaf, ScopeCreator &) override; @@ -984,7 +1056,7 @@ class AbstractFunctionBodyScope : public ASTScopeImpl { protected: ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override; void beCurrent() override; - bool isCurrent() const override; + bool isCurrentIfWasExpanded() const override; private: void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &); @@ -1000,7 +1072,7 @@ class AbstractFunctionBodyScope : public ASTScopeImpl { Decl *getDecl() const { return decl; } static bool isAMethod(const AbstractFunctionDecl *); - NullablePtr getParentOfRescuedScopes() override; + NullablePtr getParentOfASTAncestorScopesToBeRescued() override; protected: bool lookupLocalsOrMembers(ArrayRef, @@ -1076,11 +1148,14 @@ class AttachedPropertyWrapperScope final : public ASTScopeImpl { /// false positives, that that doesn't hurt anything. However, the result of /// the conservative source range computation doesn't seem to be stable. So /// keep the original here, and use it for source range queries. + /// rdar://55263708 + const SourceRange sourceRangeWhenCreated; AttachedPropertyWrapperScope(VarDecl *e) : decl(e), sourceRangeWhenCreated(getSourceRangeOfVarDecl(e)) { - assert(sourceRangeWhenCreated.isValid()); + ASTScopeAssert(sourceRangeWhenCreated.isValid(), + "VarDecls must have ranges to be looked-up"); } virtual ~AttachedPropertyWrapperScope() {} @@ -1157,7 +1232,7 @@ class PatternEntryDeclScope final : public AbstractPatternEntryScope { protected: ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override; void beCurrent() override; - bool isCurrent() const override; + bool isCurrentIfWasExpanded() const override; private: AnnotatedInsertionPoint @@ -1331,7 +1406,7 @@ class WholeClosureScope final : public AbstractClosureScope { protected: ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override; void beCurrent() override; - bool isCurrent() const override; + bool isCurrentIfWasExpanded() const override; private: void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &); @@ -1402,7 +1477,7 @@ class TopLevelCodeScope final : public ASTScopeImpl { protected: ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override; void beCurrent() override; - bool isCurrent() const override; + bool isCurrentIfWasExpanded() const override; private: AnnotatedInsertionPoint @@ -1420,7 +1495,7 @@ class TopLevelCodeScope final : public ASTScopeImpl { Decl *getDecl() const { return decl; } NullablePtr getReferrent() const override; - NullablePtr getParentOfRescuedScopes() override; + NullablePtr getParentOfASTAncestorScopesToBeRescued() override; }; /// The \c _@specialize attribute. @@ -1456,6 +1531,44 @@ class SpecializeAttributeScope final : public ASTScopeImpl { DeclConsumer) const override; }; +// SWIFT_ENABLE_TENSORFLOW +/// A `@differentiable` attribute scope. +/// This exists because `@differentiable` attribute may have a where clause +/// referring to generic parameters from some generic context. +class DifferentiableAttributeScope final : public ASTScopeImpl { +public: + DifferentiableAttr *const differentiableAttr; + ValueDecl *const attributedDeclaration; + + DifferentiableAttributeScope(DifferentiableAttr *diffAttr, + ValueDecl *decl) + : differentiableAttr(diffAttr), attributedDeclaration(decl) { + } + virtual ~DifferentiableAttributeScope() {} + + std::string getClassName() const override; + SourceRange + getSourceRangeOfThisASTNode(bool omitAssertions = false) const override; + NullablePtr addressForPrinting() const override { + return differentiableAttr; + } + + NullablePtr + getEnclosingAbstractStorageDecl() const override; + + NullablePtr getDeclAttributeIfAny() const override { + return differentiableAttr; + } + NullablePtr getReferrent() const override; + +protected: + ASTScopeImpl *expandSpecifically(ScopeCreator &) override; + bool lookupLocalsOrMembers(ArrayRef, + DeclConsumer) const override; + bool doesContextMatchStartingContext(const DeclContext *) const override; +}; +// SWIFT_ENABLE_TENSORFLOW END + class SubscriptDeclScope final : public ASTScopeImpl { public: SubscriptDecl *const decl; diff --git a/include/swift/AST/Builtins.def b/include/swift/AST/Builtins.def index a784b60504b48..eaa6217c5c151 100644 --- a/include/swift/AST/Builtins.def +++ b/include/swift/AST/Builtins.def @@ -51,30 +51,98 @@ BUILTIN_CAST_OR_BITCAST_OPERATION(SExtOrBitCast, "sextOrBitCast", "n") #undef BUILTIN_CAST_OR_BITCAST_OPERATION /// Binary operations have type (T,T) -> T. +/// +/// We define two different sorts of operations varying when T is static, +/// specifically: +/// +/// 1. Overloaded statically typed operations. E.x: +/// +/// builtin "add_Vec4xInt32"(Vec4xInt32, Vec4xInt32) : Vec4xInt32. +/// +/// 2. Polymorphic typed operations that are valid only in raw SIL. By the time +/// diagnostic constant propagation runs, these must have as its operand a +/// fully specialized type. If the builtin has a type that is not one of its +/// overloaded types, diagnostic constant propagation will emit a diagnostic +/// saying the builtin's type has not been fully resolved. Otherwise, +/// diagnostic constant propagation will transform the builtin to the +/// relevant static overloaded builtin form. E.x.: +/// +/// builtin "add"(Self, Self) : Self // *error* +/// +/// OR +/// +/// builtin "generic_add"(Vec4xInt32, Vec4xInt32) : Vec4xInt32 +/// -> +/// builtin "add_Vec4xInt32"(Vec4xInt32, Vec4xInt32) : Vec4xInt32 +/// +/// NOTE: If a polymorphic typed operation is not static by the time guaranteed +/// constant propagation runs, we emit a diagnostic to inform the user (who is +/// assumed to be an expert user) to tell them the value was unspecialized. The +/// typical way this specialization occurs today is via transparent inlining +/// since the transparent inliner devirtualizes and specializes as it goes. Of +/// course this means mandatory inlining must /always/ occur before diagnostic +/// constant propagation. +/// +/// NOTE: Often times the builtin infrastructure wants to treat all +/// binary operation builtins generic or not the same way. To ensure +/// we support all use cases in the compiler, we do not declare the +/// operations as part of this builtin since often times this macro is +/// used to generic code. Instead, we stamp this out using the +/// overloaded_static, polymorphic, and all suffixed operations. #ifndef BUILTIN_BINARY_OPERATION -#define BUILTIN_BINARY_OPERATION(Id, Name, Attrs, Overload) \ - BUILTIN(Id, Name, Attrs) +#define BUILTIN_BINARY_OPERATION(Id, Name, Attrs) BUILTIN(Id, Name, Attrs) #endif -BUILTIN_BINARY_OPERATION(Add, "add", "n", IntegerOrVector) -BUILTIN_BINARY_OPERATION(FAdd, "fadd", "n", FloatOrVector) -BUILTIN_BINARY_OPERATION(And, "and", "n", IntegerOrVector) -BUILTIN_BINARY_OPERATION(AShr, "ashr", "n", IntegerOrVector) -BUILTIN_BINARY_OPERATION(LShr, "lshr", "n", IntegerOrVector) -BUILTIN_BINARY_OPERATION(Or, "or", "n", IntegerOrVector) -BUILTIN_BINARY_OPERATION(FDiv, "fdiv", "n", FloatOrVector) -BUILTIN_BINARY_OPERATION(Mul, "mul", "n", IntegerOrVector) -BUILTIN_BINARY_OPERATION(FMul, "fmul", "n", FloatOrVector) -BUILTIN_BINARY_OPERATION(SDiv, "sdiv", "n", IntegerOrVector) -BUILTIN_BINARY_OPERATION(ExactSDiv, "sdiv_exact", "n", IntegerOrVector) -BUILTIN_BINARY_OPERATION(Shl, "shl", "n", IntegerOrVector) -BUILTIN_BINARY_OPERATION(SRem, "srem", "n", IntegerOrVector) -BUILTIN_BINARY_OPERATION(Sub, "sub", "n", IntegerOrVector) -BUILTIN_BINARY_OPERATION(FSub, "fsub", "n", FloatOrVector) -BUILTIN_BINARY_OPERATION(UDiv, "udiv", "n", IntegerOrVector) -BUILTIN_BINARY_OPERATION(ExactUDiv, "udiv_exact", "n", IntegerOrVector) -BUILTIN_BINARY_OPERATION(URem, "urem", "n", Integer) -BUILTIN_BINARY_OPERATION(FRem, "frem", "n", FloatOrVector) -BUILTIN_BINARY_OPERATION(Xor, "xor", "n", IntegerOrVector) + +#ifdef BUILTIN_BINARY_OPERATION_GENERIC_HELPER_STR +#error "Do not define BUILTIN_BINARY_OPERATION_GENERIC_HELPER_STR before including this .def file" +#endif + +#define BUILTIN_BINARY_OPERATION_GENERIC_HELPER_STR(NAME) #NAME + +#ifndef BUILTIN_BINARY_OPERATION_OVERLOADED_STATIC +#define BUILTIN_BINARY_OPERATION_OVERLOADED_STATIC(Id, Name, Attrs, Overload) \ + BUILTIN_BINARY_OPERATION(Id, Name, Attrs) +#endif + +#ifndef BUILTIN_BINARY_OPERATION_POLYMORPHIC +#define BUILTIN_BINARY_OPERATION_POLYMORPHIC(Id, Name, Attrs) \ + BUILTIN_BINARY_OPERATION(Id, Name, Attrs) +#endif + +// TODO: This needs a better name. We stringify generic_ in *_{OVERLOADED_STATIC,POLYMORPHIC} +#ifndef BUILTIN_BINARY_OPERATION_ALL +#define BUILTIN_BINARY_OPERATION_ALL(Id, Name, Attrs, Overload) \ + BUILTIN_BINARY_OPERATION_OVERLOADED_STATIC(Id, BUILTIN_BINARY_OPERATION_GENERIC_HELPER_STR(Name), Attrs, Overload) \ + BUILTIN_BINARY_OPERATION_POLYMORPHIC(Generic##Id, BUILTIN_BINARY_OPERATION_GENERIC_HELPER_STR(generic_##Name), Attrs) +#endif + +// NOTE: Here we need our name field to be bare. We stringify them as +// appropriately in BUILTIN_BINARY_OPERATION_{OVERLOADED_STATIC,POLYMORPHIC}. +BUILTIN_BINARY_OPERATION_ALL(Add, add, "n", IntegerOrVector) +BUILTIN_BINARY_OPERATION_ALL(FAdd, fadd, "n", FloatOrVector) +BUILTIN_BINARY_OPERATION_ALL(And, and, "n", IntegerOrVector) +BUILTIN_BINARY_OPERATION_ALL(AShr, ashr, "n", IntegerOrVector) +BUILTIN_BINARY_OPERATION_ALL(LShr, lshr, "n", IntegerOrVector) +BUILTIN_BINARY_OPERATION_ALL(Or, or, "n", IntegerOrVector) +BUILTIN_BINARY_OPERATION_ALL(FDiv, fdiv, "n", FloatOrVector) +BUILTIN_BINARY_OPERATION_ALL(Mul, mul, "n", IntegerOrVector) +BUILTIN_BINARY_OPERATION_ALL(FMul, fmul, "n", FloatOrVector) +BUILTIN_BINARY_OPERATION_ALL(SDiv, sdiv, "n", IntegerOrVector) +BUILTIN_BINARY_OPERATION_ALL(ExactSDiv, sdiv_exact, "n", IntegerOrVector) +BUILTIN_BINARY_OPERATION_ALL(Shl, shl, "n", IntegerOrVector) +BUILTIN_BINARY_OPERATION_ALL(SRem, srem, "n", IntegerOrVector) +BUILTIN_BINARY_OPERATION_ALL(Sub, sub, "n", IntegerOrVector) +BUILTIN_BINARY_OPERATION_ALL(FSub, fsub, "n", FloatOrVector) +BUILTIN_BINARY_OPERATION_ALL(UDiv, udiv, "n", IntegerOrVector) +BUILTIN_BINARY_OPERATION_ALL(ExactUDiv, udiv_exact, "n", IntegerOrVector) +BUILTIN_BINARY_OPERATION_ALL(URem, urem, "n", Integer) +BUILTIN_BINARY_OPERATION_ALL(FRem, frem, "n", FloatOrVector) +BUILTIN_BINARY_OPERATION_ALL(Xor, xor, "n", IntegerOrVector) +BUILTIN_BINARY_OPERATION_OVERLOADED_STATIC(Expect, "int_expect", "n", Integer) +#undef BUILTIN_BINARY_OPERATION_ALL +#undef BUILTIN_BINARY_OPERATION_POLYMORPHIC +#undef BUILTIN_BINARY_OPERATION_OVERLOADED_STATIC +#undef BUILTIN_BINARY_OPERATION_GENERIC_HELPER_STR #undef BUILTIN_BINARY_OPERATION /// These builtins are analogous the similarly named llvm intrinsics. The diff --git a/include/swift/AST/Builtins.h b/include/swift/AST/Builtins.h index 0928509774755..e162d46247364 100644 --- a/include/swift/AST/Builtins.h +++ b/include/swift/AST/Builtins.h @@ -83,6 +83,11 @@ enum class BuiltinValueKind { #include "swift/AST/Builtins.def" }; +/// Returns true if this is a polymorphic builtin that is only valid +/// in raw sil and thus must be resolved to have concrete types by the +/// time we are in canonical SIL. +bool isPolymorphicBuiltin(BuiltinValueKind Id); + /// Decode the type list of a builtin (e.g. mul_Int32) and return the base /// name (e.g. "mul"). StringRef getBuiltinBaseName(ASTContext &C, StringRef Name, @@ -126,7 +131,10 @@ class IntrinsicInfo { /// Turn a string like "release" into the LLVM enum. llvm::AtomicOrdering decodeLLVMAtomicOrdering(StringRef O); - + +/// Returns true if the builtin with ID \p ID has a defined static overload for +/// the type \p Ty. +bool canBuiltinBeOverloadedForType(BuiltinValueKind ID, Type Ty); } #endif diff --git a/include/swift/AST/CaptureInfo.h b/include/swift/AST/CaptureInfo.h index d8e699ed6c99a..1eeaecd27f8a0 100644 --- a/include/swift/AST/CaptureInfo.h +++ b/include/swift/AST/CaptureInfo.h @@ -14,11 +14,13 @@ #define SWIFT_AST_CAPTURE_INFO_H #include "swift/Basic/LLVM.h" +#include "swift/Basic/OptionSet.h" #include "swift/Basic/SourceLoc.h" #include "swift/AST/TypeAlignments.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/PointerUnion.h" +#include "llvm/Support/TrailingObjects.h" #include namespace swift { @@ -114,31 +116,63 @@ class DynamicSelfType; /// Stores information about captured variables. class CaptureInfo { - const CapturedValue *Captures; - DynamicSelfType *DynamicSelf; - OpaqueValueExpr *OpaqueValue; - unsigned Count = 0; - bool GenericParamCaptures : 1; - bool Computed : 1; + class CaptureInfoStorage final + : public llvm::TrailingObjects { + + DynamicSelfType *DynamicSelf; + OpaqueValueExpr *OpaqueValue; + unsigned Count; + public: + explicit CaptureInfoStorage(unsigned count, DynamicSelfType *dynamicSelf, + OpaqueValueExpr *opaqueValue) + : DynamicSelf(dynamicSelf), OpaqueValue(opaqueValue), Count(count) { } + + ArrayRef getCaptures() const { + return llvm::makeArrayRef(this->getTrailingObjects(), + Count); + } + + DynamicSelfType *getDynamicSelfType() const { + return DynamicSelf; + } + + OpaqueValueExpr *getOpaqueValue() const { + return OpaqueValue; + } + }; + + enum class Flags : unsigned { + HasGenericParamCaptures = 1 << 0 + }; + + llvm::PointerIntPair> + StorageAndFlags; public: - CaptureInfo() - : Captures(nullptr), DynamicSelf(nullptr), OpaqueValue(nullptr), Count(0), - GenericParamCaptures(0), Computed(0) { } + /// The default-constructed CaptureInfo is "not yet computed". + CaptureInfo() = default; + CaptureInfo(ASTContext &ctx, ArrayRef captures, + DynamicSelfType *dynamicSelf, OpaqueValueExpr *opaqueValue, + bool genericParamCaptures); - bool hasBeenComputed() const { return Computed; } + /// A CaptureInfo representing no captures at all. + static CaptureInfo empty(); + + bool hasBeenComputed() const { + return StorageAndFlags.getPointer(); + } bool isTrivial() const { - return Count == 0 && !GenericParamCaptures && !DynamicSelf && !OpaqueValue; + return getCaptures().empty() && !hasGenericParamCaptures() && + !hasDynamicSelfCapture() && !hasOpaqueValueCapture(); } ArrayRef getCaptures() const { - return llvm::makeArrayRef(Captures, Count); - } - void setCaptures(ArrayRef C) { - Captures = C.data(); - Computed = true; - Count = C.size(); + // FIXME: Ideally, everywhere that synthesizes a function should include + // its capture info. + if (!hasBeenComputed()) + return None; + return StorageAndFlags.getPointer()->getCaptures(); } /// Return a filtered list of the captures for this function, @@ -152,37 +186,37 @@ class CaptureInfo { /// \returns true if the function captures any generic type parameters. bool hasGenericParamCaptures() const { - return GenericParamCaptures; - } - - void setGenericParamCaptures(bool genericParamCaptures) { - GenericParamCaptures = genericParamCaptures; + // FIXME: Ideally, everywhere that synthesizes a function should include + // its capture info. + if (!hasBeenComputed()) + return false; + return StorageAndFlags.getInt().contains(Flags::HasGenericParamCaptures); } /// \returns true if the function captures the dynamic Self type. bool hasDynamicSelfCapture() const { - return DynamicSelf != nullptr; + return getDynamicSelfType() != nullptr; } /// \returns the captured dynamic Self type, if any. DynamicSelfType *getDynamicSelfType() const { - return DynamicSelf; - } - - void setDynamicSelfType(DynamicSelfType *dynamicSelf) { - DynamicSelf = dynamicSelf; + // FIXME: Ideally, everywhere that synthesizes a function should include + // its capture info. + if (!hasBeenComputed()) + return nullptr; + return StorageAndFlags.getPointer()->getDynamicSelfType(); } bool hasOpaqueValueCapture() const { - return OpaqueValue != nullptr; + return getOpaqueValue() != nullptr; } OpaqueValueExpr *getOpaqueValue() const { - return OpaqueValue; - } - - void setOpaqueValue(OpaqueValueExpr *OVE) { - OpaqueValue = OVE; + // FIXME: Ideally, everywhere that synthesizes a function should include + // its capture info. + if (!hasBeenComputed()) + return nullptr; + return StorageAndFlags.getPointer()->getOpaqueValue(); } void dump() const; diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index 81db532787dec..096e4b66a679b 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -279,7 +279,6 @@ class alignas(1 << DeclAlignInBits) Decl { enum class ValidationState { Unchecked, Checking, - CheckingWithValidSignature, Checked, }; @@ -850,19 +849,11 @@ class alignas(1 << DeclAlignInBits) Decl { case ValidationState::Checked: return false; case ValidationState::Checking: - case ValidationState::CheckingWithValidSignature: return true; } llvm_unreachable("Unknown ValidationState"); } - /// Update the validation state for the declaration to allow access to the - /// generic signature. - void setSignatureIsValidated() { - assert(getValidationState() == ValidationState::Checking); - setValidationState(ValidationState::CheckingWithValidSignature); - } - bool hasValidationStarted() const { return getValidationState() > ValidationState::Unchecked; } @@ -1505,12 +1496,13 @@ class alignas(8) _GenericContext { TrailingWhereClause *TrailingWhere = nullptr; /// The generic signature of this declaration. - GenericSignature *GenericSig = nullptr; + llvm::PointerIntPair GenericSigAndBit; }; class GenericContext : private _GenericContext, public DeclContext { friend class GenericParamListRequest; - + friend class GenericSignatureRequest; + protected: GenericContext(DeclContextKind Kind, DeclContext *Parent, GenericParamList *Params); @@ -1534,7 +1526,9 @@ class GenericContext : private _GenericContext, public DeclContext { /// } /// \endcode bool isGeneric() const { return getGenericParams() != nullptr; } - + bool hasComputedGenericSignature() const; + bool isComputingGenericSignature() const; + /// Retrieve the trailing where clause for this extension, if any. TrailingWhereClause *getTrailingWhereClause() const { return TrailingWhere; @@ -1766,11 +1760,6 @@ class ExtensionDecl final : public GenericContext, public Decl, void setInherited(MutableArrayRef i) { Inherited = i; } - /// Whether we have fully checked the extension signature. - bool hasValidSignature() const { - return getValidationState() > ValidationState::CheckingWithValidSignature; - } - bool hasDefaultAccessLevel() const { return Bits.ExtensionDecl.DefaultAndMaxAccessLevel != 0; } @@ -2605,8 +2594,6 @@ class ValueDecl : public Decl { /// Set the interface type for the given value. void setInterfaceType(Type type); - - bool hasValidSignature() const; /// isInstanceMember - Determine whether this value is an instance member /// of an enum or protocol. @@ -2945,6 +2932,8 @@ class OpaqueTypeDecl : public GenericTypeDecl { /// TypeAliasDecl's always have 'MetatypeType' type. /// class TypeAliasDecl : public GenericTypeDecl { + friend class UnderlyingTypeRequest; + /// The location of the 'typealias' keyword SourceLoc TypeAliasLoc; @@ -2972,20 +2961,28 @@ class TypeAliasDecl : public GenericTypeDecl { void setTypeEndLoc(SourceLoc e) { TypeEndLoc = e; } - TypeLoc &getUnderlyingTypeLoc() { - return UnderlyingTy; + /// Retrieve the TypeRepr corresponding to the parsed underlying type. + TypeRepr *getUnderlyingTypeRepr() const { + return UnderlyingTy.getTypeRepr(); } - const TypeLoc &getUnderlyingTypeLoc() const { - return UnderlyingTy; + void setUnderlyingTypeRepr(TypeRepr *repr) { + UnderlyingTy = repr; } - + + /// Retrieve the interface type of the underlying type. + Type getUnderlyingType() const; void setUnderlyingType(Type type); /// For generic typealiases, return the unbound generic type. UnboundGenericType *getUnboundGenericType() const; + /// Retrieve a sugared interface type containing the structure of the interface + /// type before any semantic validation has occured. Type getStructuralType() const; + /// Set the interface type of this typealias declaration from the underlying type. + void computeType(); + bool isCompatibilityAlias() const { return Bits.TypeAliasDecl.IsCompatibilityAlias; } @@ -5186,6 +5183,7 @@ class ParamDecl : public VarDecl { PointerUnion DefaultArg; Initializer *InitContext = nullptr; StringRef StringRepresentation; + CaptureInfo Captures; }; enum class Flags : uint8_t { @@ -5271,6 +5269,13 @@ class ParamDecl : public VarDecl { void setDefaultArgumentInitContext(Initializer *initContext); + const CaptureInfo &getDefaultArgumentCaptureInfo() const { + assert(DefaultValueAndFlags.getPointer()); + return DefaultValueAndFlags.getPointer()->Captures; + } + + void setDefaultArgumentCaptureInfo(const CaptureInfo &captures); + /// Extracts the text of the default argument attached to the provided /// ParamDecl, removing all inactive #if clauses and providing only the /// text of active #if clauses. diff --git a/include/swift/AST/DeclContext.h b/include/swift/AST/DeclContext.h index 77364a3c28d7c..4b3eee00d0c61 100644 --- a/include/swift/AST/DeclContext.h +++ b/include/swift/AST/DeclContext.h @@ -261,7 +261,10 @@ class alignas(1 << DeclContextAlignInBits) DeclContext { /// Returns the kind of context this is. DeclContextKind getContextKind() const; - + + /// Returns whether this context has value semantics. + bool hasValueSemantics() const; + /// Determines whether this context is itself a local scope in a /// code block. A context that appears in such a scope, like a /// local type declaration, does not itself become a local context. diff --git a/include/swift/AST/DiagnosticsSIL.def b/include/swift/AST/DiagnosticsSIL.def index 18475889e92ef..05ac8cb913d52 100644 --- a/include/swift/AST/DiagnosticsSIL.def +++ b/include/swift/AST/DiagnosticsSIL.def @@ -365,27 +365,32 @@ ERROR(pound_assert_failure,none, NOTE(constexpr_unknown_reason_default,none, "cannot evaluate expression as constant here", ()) NOTE(constexpr_unevaluable_operation,none, - "cannot constant evaluate operation", ()) + "cannot constant evaluate operation%select{| used by this call}0", (bool)) NOTE(constexpr_too_many_instructions,none, "exceeded instruction limit: %0 when evaluating the expression " "at compile time", (unsigned)) -NOTE(constexpr_limit_exceeding_instruction,none, "limit exceeded here", ()) +NOTE(constexpr_limit_exceeding_instruction,none, "limit exceeded " + "%select{here|during this call}0", (bool)) NOTE(constexpr_loop_found_note,none, "control-flow loop found during evaluation ", ()) -NOTE(constexpr_loop_instruction,none, "found loop here", ()) +NOTE(constexpr_loop_instruction,none, "found loop " + "%select{here|inside this call}0", (bool)) NOTE(constexpr_overflow,none, "integer overflow detected", ()) -NOTE(constexpr_overflow_operation,none, "operation overflows", ()) +NOTE(constexpr_overflow_operation,none, "operation" + "%select{| performed during this call}0 overflows", (bool)) -NOTE(constexpr_trap,none, "trap detected", ()) -NOTE(constexpr_trap_operation,none, "operation traps", ()) +NOTE(constexpr_trap, none, "%0", (StringRef)) +NOTE(constexpr_trap_operation, none, "operation" + "%select{| performed during this call}0 traps", (bool)) NOTE(constexpr_invalid_operand_seen, none, "operation with invalid operands encountered during evaluation",()) NOTE(constexpr_operand_invalid_here, none, - "operation with invalid operands encountered here",()) + "operation with invalid operands encountered " + "%select{here|during this call}0", (bool)) NOTE(constexpr_value_unknown_at_top_level,none, "cannot evaluate top-level value as constant here",()) @@ -393,19 +398,31 @@ NOTE(constexpr_multiple_writers_found_at_top_level,none, "top-level value has multiple assignments",()) NOTE(constexpr_unsupported_instruction_found, none, - "encountered operation not supported by the evaluator", ()) -NOTE(constexpr_unsupported_instruction_found_here,none, - "operation not supported by the evaluator", ()) + "encountered operation not supported by the evaluator: %0", (StringRef)) +NOTE(constexpr_unsupported_instruction_found_here,none, "operation" + "%select{| used by this call is}0 not supported by the evaluator", (bool)) -NOTE(constexpr_unknown_function_called, none, - "encountered call to a function whose body is not available", ()) -NOTE(constexpr_unknown_function_called_here, none, - "call to a function whose body is not available", ()) +NOTE(constexpr_found_callee_with_no_body, none, + "encountered call to '%0' whose body is not available. " + "Imported functions must be marked '@inlinable' to constant evaluate.", + (StringRef)) +NOTE(constexpr_callee_with_no_body, none, + "%select{|calls a }0function whose body is not available", (bool)) NOTE(constexpr_untracked_sil_value_use_found, none, "encountered use of a variable not tracked by the evaluator", ()) NOTE(constexpr_untracked_sil_value_used_here, none, - "untracked variable used here", ()) + "untracked variable used %select{here|by this call}0", (bool)) + +NOTE(constexpr_unresolvable_witness_call, none, + "encountered unresolvable witness method call: '%0'", (StringRef)) +NOTE(constexpr_no_witness_table_entry, none, "cannot find witness table entry " + "%select{for this call|for a witness-method invoked during this call}0", + (bool)) +NOTE(constexpr_witness_call_with_no_conformance, none, + "cannot find concrete conformance " + "%select{for this call|for a witness-method invoked during this call}0", + (bool)) NOTE(constexpr_witness_call_with_no_conformance_found, none, "cannot find concrete conformance for a witness method call", ()) @@ -413,6 +430,18 @@ NOTE(constexpr_witness_call_with_no_target_found, none, "cannot resolve a witness method call to a concrete function", ()) NOTE(constexpr_witness_call_found_here, none, "witness method call found here", ()) + +NOTE(constexpr_unknown_control_flow_due_to_skip,none, "branch depends on " + "non-constant value produced by an unevaluated instructions", ()) +NOTE(constexpr_returned_by_unevaluated_instruction,none, + "return value of an unevaluated instruction is not a constant", ()) +NOTE(constexpr_mutated_by_unevaluated_instruction,none, "value mutable by an " + "unevaluated instruction is not a constant", ()) + +ERROR(not_constant_evaluable, none, "not constant evaluable", ()) +ERROR(constexpr_imported_func_not_onone, none, "imported constant evaluable " + "function '%0' must be annotated '@_optimize(none)'", (StringRef)) + // Automatic differentiation diagnostics ERROR(autodiff_internal_swift_not_imported,none, "AD internal error: the Swift module is not imported", ()) @@ -492,13 +521,6 @@ NOTE(autodiff_class_property_not_supported,none, NOTE(autodiff_missing_return,none, "missing return for differentiation", ()) -NOTE(constexpr_unknown_control_flow_due_to_skip,none, "branch depends on " - "non-constant value produced by an unevaluated instructions", ()) -NOTE(constexpr_returned_by_unevaluated_instruction,none, - "return value of an unevaluated instruction is not a constant", ()) -NOTE(constexpr_mutated_by_unevaluated_instruction,none, "value mutable by an " - "unevaluated instruction is not a constant", ()) - ERROR(non_physical_addressof,none, "addressof only works with purely physical lvalues; " "use `withUnsafePointer` or `withUnsafeBytes` unless you're implementing " @@ -591,6 +613,16 @@ ERROR(oslog_property_not_constant, none, "'OSLogInterpolation.%0' is not a " ERROR(global_string_pointer_on_non_constant, none, "globalStringTablePointer " "builtin must used only on string literals", ()) +ERROR(polymorphic_builtin_passed_non_trivial_non_builtin_type, none, "Argument " + "of type %0 can not be passed as an argument to a Polymorphic " + "builtin. Polymorphic builtins can only be passed arguments that are " + "trivial builtin typed", (Type)) + +ERROR(polymorphic_builtin_passed_type_without_static_overload, none, "Static" + " overload %0 does not exist for polymorphic builtin '%1'. Static " + "overload implied by passing argument of type %2", + (Identifier, StringRef, Type)) + #ifndef DIAG_NO_UNDEF # if defined(DIAG) # undef DIAG diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 208d85c1a6419..7998497359785 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -384,6 +384,15 @@ NOTE(candidate_has_invalid_argument_at_position,none, "candidate expects value of type %0 at position #%1", (Type, unsigned)) +ERROR(cannot_convert_array_to_variadic,none, + "cannot pass array of type %0 as variadic arguments of type %1", + (Type,Type)) +NOTE(candidate_would_match_array_to_variadic,none, + "candidate would match if array elements were passed as" + " variadic arguments of type %0", (Type)) +NOTE(suggest_pass_elements_directly,none, + "remove brackets to pass array elements directly", ()) + ERROR(cannot_convert_argument_value_generic,none, "cannot convert value of type %0 (%1) to expected argument type %2 (%3)", (Type, StringRef, Type, StringRef)) @@ -396,6 +405,12 @@ ERROR(cannot_convert_partial_argument_value_protocol,none, ERROR(cannot_convert_argument_value_nil,none, "'nil' is not compatible with expected argument type %0", (Type)) +ERROR(cannot_convert_condition_value,none, + "cannot convert value of type %0 to expected condition type %1", + (Type, Type)) +ERROR(cannot_convert_condition_value_nil,none, + "'nil' is not compatible with expected condition type %0", (Type)) + ERROR(cannot_yield_rvalue_by_reference_same_type,none, "cannot yield immutable value of type %0 as an inout yield", (Type)) ERROR(cannot_yield_rvalue_by_reference,none, @@ -1672,10 +1687,19 @@ ERROR(cannot_use_nil_with_this_type,none, ERROR(use_of_equal_instead_of_equality,none, "use of '=' in a boolean context, did you mean '=='?", ()) +ERROR(type_cannot_conform, none, + "%select{|value of protocol }0type %1 cannot conform to %2; " + "only struct/enum/class types can conform to protocols", + (bool, Type, Type)) +NOTE(required_by_opaque_return,none, + "required by opaque return type of %0 %1", (DescriptiveDeclKind, DeclName)) +NOTE(required_by_decl,none, + "required by %0 %1 where %2 = %3", + (DescriptiveDeclKind, DeclName, Type, Type)) +NOTE(required_by_decl_ref,none, + "required by referencing %0 %1 on %2 where %3 = %4", + (DescriptiveDeclKind, DeclName, Type, Type, Type)) -ERROR(protocol_does_not_conform_objc,none, - "protocol type %0 cannot conform to %1 because only concrete " - "types can conform to protocols", (Type, Type)) ERROR(protocol_does_not_conform_static,none, "%0 cannot be used as a type conforming to protocol %1 because %1 " "has static requirements", @@ -2683,6 +2707,8 @@ ERROR(dynamic_self_invalid_method,none, "covariant 'Self' can only appear at the top level of method result type", ()) ERROR(dynamic_self_stored_property_init,none, "covariant 'Self' type cannot be referenced from a stored property initializer", ()) +ERROR(dynamic_self_default_arg,none, + "covariant 'Self' type cannot be referenced from a default argument expression", ()) //------------------------------------------------------------------------------ // MARK: Type Check Attributes diff --git a/include/swift/AST/FileUnit.h b/include/swift/AST/FileUnit.h new file mode 100644 index 0000000000000..388c46446fd2e --- /dev/null +++ b/include/swift/AST/FileUnit.h @@ -0,0 +1,365 @@ +//===--- FileUnit.h - The contents of a module ------------------*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2019 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 +// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_AST_FILEUNIT_H +#define SWIFT_AST_FILEUNIT_H + +#include "swift/AST/Module.h" + +namespace swift { +static inline unsigned alignOfFileUnit(); + +/// A container for module-scope declarations that itself provides a scope; the +/// smallest unit of code organization. +/// +/// FileUnit is an abstract base class; its subclasses represent different +/// sorts of containers that can each provide a set of decls, e.g. a source +/// file. A module can contain several file-units. +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wnon-virtual-dtor" +class FileUnit : public DeclContext { +#pragma clang diagnostic pop + virtual void anchor(); + + // FIXME: Stick this in a PointerIntPair. + const FileUnitKind Kind; + +protected: + FileUnit(FileUnitKind kind, ModuleDecl &M) + : DeclContext(DeclContextKind::FileUnit, &M), Kind(kind) { + } + +public: + FileUnitKind getKind() const { + return Kind; + } + + /// Look up a (possibly overloaded) value set at top-level scope + /// (but with the specified access path, which may come from an import decl) + /// within this file. + /// + /// This does a simple local lookup, not recursively looking through imports. + virtual void lookupValue(DeclName name, NLKind lookupKind, + SmallVectorImpl &result) const = 0; + + /// Look up a local type declaration by its mangled name. + /// + /// This does a simple local lookup, not recursively looking through imports. + virtual TypeDecl *lookupLocalType(StringRef MangledName) const { + return nullptr; + } + + /// Look up an opaque return type by the mangled name of the declaration + /// that defines it. + virtual OpaqueTypeDecl *lookupOpaqueResultType(StringRef MangledName, + LazyResolver *resolver) { + return nullptr; + } + + /// Directly look for a nested type declared within this module inside the + /// given nominal type (including any extensions). + /// + /// This is a fast-path hack to avoid circular dependencies in deserialization + /// and the Clang importer. + /// + /// Private and fileprivate types should not be returned by this lookup. + virtual TypeDecl *lookupNestedType(Identifier name, + const NominalTypeDecl *parent) const { + return nullptr; + } + + /// Find ValueDecls in the module and pass them to the given consumer object. + /// + /// This does a simple local lookup, not recursively looking through imports. + virtual void lookupVisibleDecls(ModuleDecl::AccessPathTy accessPath, + VisibleDeclConsumer &consumer, + NLKind lookupKind) const {} + + /// Finds all class members defined in this file. + /// + /// This does a simple local lookup, not recursively looking through imports. + virtual void lookupClassMembers(ModuleDecl::AccessPathTy accessPath, + VisibleDeclConsumer &consumer) const {} + + /// Finds class members defined in this file with the given name. + /// + /// This does a simple local lookup, not recursively looking through imports. + virtual void lookupClassMember(ModuleDecl::AccessPathTy accessPath, + DeclName name, + SmallVectorImpl &results) const {} + + /// Find all Objective-C methods with the given selector. + virtual void lookupObjCMethods( + ObjCSelector selector, + SmallVectorImpl &results) const = 0; + + /// Returns the comment attached to the given declaration. + /// + /// This function is an implementation detail for comment serialization. + /// If you just want to get a comment attached to a decl, use + /// \c Decl::getRawComment() or \c Decl::getBriefComment(). + virtual Optional + getCommentForDecl(const Decl *D) const { + return None; + } + + virtual Optional + getGroupNameForDecl(const Decl *D) const { + return None; + } + + virtual Optional + getSourceFileNameForDecl(const Decl *D) const { + return None; + } + + virtual Optional + getSourceOrderForDecl(const Decl *D) const { + return None; + } + + virtual Optional + getGroupNameByUSR(StringRef USR) const { + return None; + } + + virtual void collectAllGroups(std::vector &Names) const {} + + /// Returns an implementation-defined "discriminator" for \p D, which + /// distinguishes \p D from other declarations in the same module with the + /// same name. + /// + /// Since this value is used in name mangling, it should be a valid ASCII-only + /// identifier. + virtual Identifier + getDiscriminatorForPrivateValue(const ValueDecl *D) const = 0; + + /// Finds all top-level 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 getTopLevelDecls(SmallVectorImpl &results) const {} + + + /// Finds all precedence group 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 + getPrecedenceGroups(SmallVectorImpl &Results) const {} + + /// Finds all local type 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 getLocalTypeDecls(SmallVectorImpl &results) const {} + + virtual void + getOpaqueReturnTypeDecls(SmallVectorImpl &results) const {} + + /// Adds all top-level decls to the given vector. + /// + /// This includes all decls that should be displayed to clients of the module. + /// The order of the results is not guaranteed to be meaningful. + /// + /// This can differ from \c getTopLevelDecls, e.g. it returns decls from a + /// shadowed clang module. + virtual void getDisplayDecls(SmallVectorImpl &results) const { + getTopLevelDecls(results); + } + + /// Looks up which modules are imported by this file. + /// + /// \p filter controls whether public, private, or any imports are included + /// in this list. + virtual void + getImportedModules(SmallVectorImpl &imports, + ModuleDecl::ImportFilter filter) const {} + + /// \see ModuleDecl::getImportedModulesForLookup + virtual void getImportedModulesForLookup( + SmallVectorImpl &imports) const { + return getImportedModules(imports, ModuleDecl::ImportFilterKind::Public); + } + + /// Generates the list of libraries needed to link this file, based on its + /// imports. + virtual void + collectLinkLibraries(ModuleDecl::LinkLibraryCallback callback) const {} + + /// True if this file contains the main class for the module. + bool hasMainClass() const { + return getMainClass(); + } + virtual ClassDecl *getMainClass() const { + assert(hasEntryPoint()); + return nullptr; + } + virtual bool hasEntryPoint() const { + return false; + } + + /// Returns the associated clang module if one exists. + virtual const clang::Module *getUnderlyingClangModule() const { + return nullptr; + } + + /// Returns the name to use when referencing entities in this file. + /// + /// Usually this is the module name itself, but certain Clang features allow + /// substituting another name instead. + virtual StringRef getExportedModuleName() const { + return getParentModule()->getName().str(); + } + + /// Traverse the decls within this file. + /// + /// \returns true if traversal was aborted, false if it completed + /// successfully. + virtual bool walk(ASTWalker &walker); + + // Efficiency override for DeclContext::getParentModule(). + ModuleDecl *getParentModule() const { + return const_cast(cast(getParent())); + } + + static bool classof(const DeclContext *DC) { + return DC->getContextKind() == DeclContextKind::FileUnit; + } + +private: + // Make placement new and vanilla new/delete illegal for FileUnits. + void *operator new(size_t Bytes) throw() = delete; + void *operator new(size_t Bytes, void *Mem) throw() = delete; + void operator delete(void *Data) throw() = delete; + +public: + // Only allow allocation of FileUnits using the allocator in ASTContext + // or by doing a placement new. + void *operator new(size_t Bytes, ASTContext &C, + unsigned Alignment = alignOfFileUnit()); +}; + +static inline unsigned alignOfFileUnit() { + return alignof(FileUnit&); +} + +/// This represents the compiler's implicitly generated declarations in the +/// Builtin module. +class BuiltinUnit final : public FileUnit { +public: + class LookupCache; + +private: + std::unique_ptr Cache; + LookupCache &getCache() const; + + friend ASTContext; + ~BuiltinUnit() = default; + +public: + explicit BuiltinUnit(ModuleDecl &M); + + virtual void lookupValue(DeclName name, NLKind lookupKind, + SmallVectorImpl &result) const override; + + /// Find all Objective-C methods with the given selector. + void lookupObjCMethods( + ObjCSelector selector, + SmallVectorImpl &results) const override; + + Identifier + getDiscriminatorForPrivateValue(const ValueDecl *D) const override { + llvm_unreachable("no private values in the Builtin module"); + } + + static bool classof(const FileUnit *file) { + return file->getKind() == FileUnitKind::Builtin; + } + + static bool classof(const DeclContext *DC) { + return isa(DC) && classof(cast(DC)); + } +}; + +/// Represents an externally-loaded file of some kind. +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wnon-virtual-dtor" +class LoadedFile : public FileUnit { +#pragma clang diagnostic pop +protected: + LoadedFile(FileUnitKind Kind, ModuleDecl &M) noexcept + : FileUnit(Kind, M) { + assert(classof(this) && "invalid kind"); + } +public: + /// Returns an arbitrary string representing the storage backing this file. + /// + /// This is usually a filesystem path. + virtual StringRef getFilename() const; + + virtual StringRef getFilenameForPrivateDecl(const ValueDecl *decl) const { + return StringRef(); + } + + /// Look up an operator declaration. + /// + /// \param name The operator name ("+", ">>", etc.) + /// + /// \param fixity One of PrefixOperator, InfixOperator, or PostfixOperator. + virtual OperatorDecl *lookupOperator(Identifier name, DeclKind fixity) const { + return nullptr; + } + + /// Look up a precedence group. + /// + /// \param name The precedence group name. + virtual PrecedenceGroupDecl *lookupPrecedenceGroup(Identifier name) const { + return nullptr; + } + + /// Returns the Swift module that overlays a Clang module. + virtual ModuleDecl *getOverlayModule() const { return nullptr; } + + virtual bool isSystemModule() const { return false; } + + /// Retrieve the set of generic signatures stored within this module. + /// + /// \returns \c true if this module file supports retrieving all of the + /// generic signatures, \c false otherwise. + virtual bool getAllGenericSignatures( + SmallVectorImpl &genericSignatures) { + return false; + } + + static bool classof(const FileUnit *file) { + return file->getKind() == FileUnitKind::SerializedAST || + file->getKind() == FileUnitKind::ClangModule || + file->getKind() == FileUnitKind::DWARFModule; + } + static bool classof(const DeclContext *DC) { + return isa(DC) && classof(cast(DC)); + } +}; + + +inline FileUnit &ModuleDecl::getMainFile(FileUnitKind expectedKind) const { + assert(expectedKind != FileUnitKind::Source && + "must use specific source kind; see getMainSourceFile"); + assert(!Files.empty() && "No files added yet"); + assert(Files.front()->getKind() == expectedKind); + return *Files.front(); +} + +} // end namespace swift + +#endif diff --git a/include/swift/AST/KnownFoundationEntities.def b/include/swift/AST/KnownFoundationEntities.def index 70303855bdae4..b9a589f443588 100644 --- a/include/swift/AST/KnownFoundationEntities.def +++ b/include/swift/AST/KnownFoundationEntities.def @@ -20,7 +20,6 @@ #endif FOUNDATION_ENTITY(NSArray) -FOUNDATION_ENTITY(NSCopying) FOUNDATION_ENTITY(NSDictionary) FOUNDATION_ENTITY(NSError) FOUNDATION_ENTITY(NSErrorPointer) diff --git a/include/swift/AST/KnownProtocols.def b/include/swift/AST/KnownProtocols.def index f1ac943d7ffed..7c3a45c71eccb 100644 --- a/include/swift/AST/KnownProtocols.def +++ b/include/swift/AST/KnownProtocols.def @@ -11,7 +11,8 @@ //===----------------------------------------------------------------------===// // // This file defines macros used for macro-metaprogramming with compiler-known -// protocols. +// protocols. Note that this mechanism does not look through an overlay into its +// underlying module, so it typically cannot find Objective-C protocols. // //===----------------------------------------------------------------------===// diff --git a/include/swift/AST/LazyResolver.h b/include/swift/AST/LazyResolver.h index 9a6b298a40265..970cb7ccfa26d 100644 --- a/include/swift/AST/LazyResolver.h +++ b/include/swift/AST/LazyResolver.h @@ -60,15 +60,6 @@ class LazyResolver { /// consistency and provides the value a type. virtual void resolveDeclSignature(ValueDecl *VD) = 0; - /// Resolve the generic environment of the given protocol. - virtual void resolveProtocolEnvironment(ProtocolDecl *proto) = 0; - - /// Resolve the type of an extension. - /// - /// This can be called to ensure that the members of an extension can be - /// considered to be members of the extended type. - virtual void resolveExtension(ExtensionDecl *ext) = 0; - /// Resolve any implicitly-declared constructors within the given nominal. virtual void resolveImplicitConstructors(NominalTypeDecl *nominal) = 0; diff --git a/include/swift/AST/Module.h b/include/swift/AST/Module.h index 00eeae9bc274c..801fa0caef36a 100644 --- a/include/swift/AST/Module.h +++ b/include/swift/AST/Module.h @@ -219,29 +219,12 @@ class ModuleDecl : public DeclContext, public TypeDecl { public: EntryPointInfoTy() = default; - FileUnit *getEntryPointFile() const { - return storage.getPointer(); - } - void setEntryPointFile(FileUnit *file) { - assert(!storage.getPointer()); - storage.setPointer(file); - } - - bool hasEntryPoint() const { - return storage.getPointer(); - } - - bool markDiagnosedMultipleMainClasses() { - bool res = storage.getInt().contains(Flags::DiagnosedMultipleMainClasses); - storage.setInt(storage.getInt() | Flags::DiagnosedMultipleMainClasses); - return !res; - } + FileUnit *getEntryPointFile() const; + void setEntryPointFile(FileUnit *file); + bool hasEntryPoint() const; - bool markDiagnosedMainClassWithScript() { - bool res = storage.getInt().contains(Flags::DiagnosedMainClassWithScript); - storage.setInt(storage.getInt() | Flags::DiagnosedMainClassWithScript); - return !res; - } + bool markDiagnosedMultipleMainClasses(); + bool markDiagnosedMainClassWithScript(); }; /// Information about the file responsible for the module's entry point, @@ -597,791 +580,6 @@ class ModuleDecl : public DeclContext, public TypeDecl { unsigned Alignment = alignof(ModuleDecl)); }; -static inline unsigned alignOfFileUnit(); - -/// A container for module-scope declarations that itself provides a scope; the -/// smallest unit of code organization. -/// -/// FileUnit is an abstract base class; its subclasses represent different -/// sorts of containers that can each provide a set of decls, e.g. a source -/// file. A module can contain several file-units. -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wnon-virtual-dtor" -class FileUnit : public DeclContext { -#pragma clang diagnostic pop - virtual void anchor(); - - // FIXME: Stick this in a PointerIntPair. - const FileUnitKind Kind; - -protected: - FileUnit(FileUnitKind kind, ModuleDecl &M) - : DeclContext(DeclContextKind::FileUnit, &M), Kind(kind) { - } - -public: - FileUnitKind getKind() const { - return Kind; - } - - /// Look up a (possibly overloaded) value set at top-level scope - /// (but with the specified access path, which may come from an import decl) - /// within this file. - /// - /// This does a simple local lookup, not recursively looking through imports. - virtual void lookupValue(DeclName name, NLKind lookupKind, - SmallVectorImpl &result) const = 0; - - /// Look up a local type declaration by its mangled name. - /// - /// This does a simple local lookup, not recursively looking through imports. - virtual TypeDecl *lookupLocalType(StringRef MangledName) const { - return nullptr; - } - - /// Look up an opaque return type by the mangled name of the declaration - /// that defines it. - virtual OpaqueTypeDecl *lookupOpaqueResultType(StringRef MangledName, - LazyResolver *resolver) { - return nullptr; - } - - /// Directly look for a nested type declared within this module inside the - /// given nominal type (including any extensions). - /// - /// This is a fast-path hack to avoid circular dependencies in deserialization - /// and the Clang importer. - /// - /// Private and fileprivate types should not be returned by this lookup. - virtual TypeDecl *lookupNestedType(Identifier name, - const NominalTypeDecl *parent) const { - return nullptr; - } - - /// Find ValueDecls in the module and pass them to the given consumer object. - /// - /// This does a simple local lookup, not recursively looking through imports. - virtual void lookupVisibleDecls(ModuleDecl::AccessPathTy accessPath, - VisibleDeclConsumer &consumer, - NLKind lookupKind) const {} - - /// Finds all class members defined in this file. - /// - /// This does a simple local lookup, not recursively looking through imports. - virtual void lookupClassMembers(ModuleDecl::AccessPathTy accessPath, - VisibleDeclConsumer &consumer) const {} - - /// Finds class members defined in this file with the given name. - /// - /// This does a simple local lookup, not recursively looking through imports. - virtual void lookupClassMember(ModuleDecl::AccessPathTy accessPath, - DeclName name, - SmallVectorImpl &results) const {} - - /// Find all Objective-C methods with the given selector. - virtual void lookupObjCMethods( - ObjCSelector selector, - SmallVectorImpl &results) const = 0; - - /// Returns the comment attached to the given declaration. - /// - /// This function is an implementation detail for comment serialization. - /// If you just want to get a comment attached to a decl, use - /// \c Decl::getRawComment() or \c Decl::getBriefComment(). - virtual Optional - getCommentForDecl(const Decl *D) const { - return None; - } - - virtual Optional - getGroupNameForDecl(const Decl *D) const { - return None; - } - - virtual Optional - getSourceFileNameForDecl(const Decl *D) const { - return None; - } - - virtual Optional - getSourceOrderForDecl(const Decl *D) const { - return None; - } - - virtual Optional - getGroupNameByUSR(StringRef USR) const { - return None; - } - - virtual void collectAllGroups(std::vector &Names) const {} - - /// Returns an implementation-defined "discriminator" for \p D, which - /// distinguishes \p D from other declarations in the same module with the - /// same name. - /// - /// Since this value is used in name mangling, it should be a valid ASCII-only - /// identifier. - virtual Identifier - getDiscriminatorForPrivateValue(const ValueDecl *D) const = 0; - - /// Finds all top-level 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 getTopLevelDecls(SmallVectorImpl &results) const {} - - - /// Finds all precedence group 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 - getPrecedenceGroups(SmallVectorImpl &Results) const {} - - /// Finds all local type 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 getLocalTypeDecls(SmallVectorImpl &results) const {} - - virtual void - getOpaqueReturnTypeDecls(SmallVectorImpl &results) const {} - - /// Adds all top-level decls to the given vector. - /// - /// This includes all decls that should be displayed to clients of the module. - /// The order of the results is not guaranteed to be meaningful. - /// - /// This can differ from \c getTopLevelDecls, e.g. it returns decls from a - /// shadowed clang module. - virtual void getDisplayDecls(SmallVectorImpl &results) const { - getTopLevelDecls(results); - } - - /// Looks up which modules are imported by this file. - /// - /// \p filter controls whether public, private, or any imports are included - /// in this list. - virtual void - getImportedModules(SmallVectorImpl &imports, - ModuleDecl::ImportFilter filter) const {} - - /// \see ModuleDecl::getImportedModulesForLookup - virtual void getImportedModulesForLookup( - SmallVectorImpl &imports) const { - return getImportedModules(imports, ModuleDecl::ImportFilterKind::Public); - } - - /// Generates the list of libraries needed to link this file, based on its - /// imports. - virtual void - collectLinkLibraries(ModuleDecl::LinkLibraryCallback callback) const {} - - /// True if this file contains the main class for the module. - bool hasMainClass() const { - return getMainClass(); - } - virtual ClassDecl *getMainClass() const { - assert(hasEntryPoint()); - return nullptr; - } - virtual bool hasEntryPoint() const { - return false; - } - - /// Returns the associated clang module if one exists. - virtual const clang::Module *getUnderlyingClangModule() const { - return nullptr; - } - - /// Returns the name to use when referencing entities in this file. - /// - /// Usually this is the module name itself, but certain Clang features allow - /// substituting another name instead. - virtual StringRef getExportedModuleName() const { - return getParentModule()->getName().str(); - } - - /// Traverse the decls within this file. - /// - /// \returns true if traversal was aborted, false if it completed - /// successfully. - virtual bool walk(ASTWalker &walker); - - // Efficiency override for DeclContext::getParentModule(). - ModuleDecl *getParentModule() const { - return const_cast(cast(getParent())); - } - - static bool classof(const DeclContext *DC) { - return DC->getContextKind() == DeclContextKind::FileUnit; - } - -private: - // Make placement new and vanilla new/delete illegal for FileUnits. - void *operator new(size_t Bytes) throw() = delete; - void *operator new(size_t Bytes, void *Mem) throw() = delete; - void operator delete(void *Data) throw() = delete; - -public: - // Only allow allocation of FileUnits using the allocator in ASTContext - // or by doing a placement new. - void *operator new(size_t Bytes, ASTContext &C, - unsigned Alignment = alignOfFileUnit()); -}; - -static inline unsigned alignOfFileUnit() { - return alignof(FileUnit&); -} - -/// A file containing Swift source code. -/// -/// This is a .swift or .sil file (or a virtual file, such as the contents of -/// the REPL). Since it contains raw source, it must be parsed and name-bound -/// before being used for anything; a full type-check is also necessary for -/// IR generation. -class SourceFile final : public FileUnit { -public: - class Impl; - struct SourceFileSyntaxInfo; - - /// The implicit module import that the SourceFile should get. - enum class ImplicitModuleImportKind { - None, - Builtin, - Stdlib - }; - - /// Possible attributes for imports in source files. - enum class ImportFlags { - /// The imported module is exposed to anyone who imports the parent module. - Exported = 0x1, - - /// This source file has access to testable declarations in the imported - /// module. - Testable = 0x2, - - /// This source file has access to private declarations in the imported - /// module. - PrivateImport = 0x4, - - /// The imported module is an implementation detail of this file and should - /// not be required to be present if the main module is ever imported - /// elsewhere. - /// - /// Mutually exclusive with Exported. - ImplementationOnly = 0x8 - }; - - /// \see ImportFlags - using ImportOptions = OptionSet; - - struct ImportedModuleDesc { - ModuleDecl::ImportedModule module; - ImportOptions importOptions; - StringRef filename; - - ImportedModuleDesc(ModuleDecl::ImportedModule module, ImportOptions options, - StringRef filename = {}) - : module(module), importOptions(options), filename(filename) { - assert(!(importOptions.contains(ImportFlags::Exported) && - importOptions.contains(ImportFlags::ImplementationOnly))); - } - }; - -private: - std::unique_ptr Cache; - SourceLookupCache &getCache() const; - - /// This is the list of modules that are imported by this module. - /// - /// This is filled in by the Name Binding phase. - ArrayRef Imports; - - /// A unique identifier representing this file; used to mark private decls - /// within the file to keep them from conflicting with other files in the - /// same module. - mutable Identifier PrivateDiscriminator; - - /// The root TypeRefinementContext for this SourceFile. - /// - /// This is set during type checking. - TypeRefinementContext *TRC = nullptr; - - /// If non-null, used to track name lookups that happen within this file. - Optional ReferencedNames; - - /// The class in this file marked \@NS/UIApplicationMain. - ClassDecl *MainClass = nullptr; - - /// The source location of the main class. - SourceLoc MainClassDiagLoc; - - /// A hash of all interface-contributing tokens that have been lexed for - /// this source file so far. - /// We only collect interface hash for primary input files. - llvm::Optional InterfaceHash; - - /// The ID for the memory buffer containing this file's source. - /// - /// May be -1, to indicate no association with a buffer. - int BufferID; - - /// Does this source file have any implementation-only imports? - /// If not, we can fast-path module checks. - bool HasImplementationOnlyImports = false; - - /// The scope map that describes this source file. - std::unique_ptr Scope; - - friend ASTContext; - friend Impl; -public: - /// The list of top-level declarations in the source file. - std::vector Decls; - - /// A cache of syntax nodes that can be reused when creating the syntax tree - /// for this file. - SyntaxParsingCache *SyntaxParsingCache = nullptr; - - /// The list of local type declarations in the source file. - llvm::SetVector LocalTypeDecls; - - /// The set of validated opaque return type decls in the source file. - llvm::SmallVector OpaqueReturnTypes; - llvm::StringMap ValidatedOpaqueReturnTypes; - /// The set of parsed decls with opaque return types that have not yet - /// been validated. - llvm::DenseSet UnvalidatedDeclsWithOpaqueReturnTypes; - - /// A set of special declaration attributes which require the - /// Foundation module to be imported to work. If the foundation - /// module is still not imported by the time type checking is - /// complete, we diagnose. - llvm::SetVector AttrsRequiringFoundation; - - /// A set of synthesized declarations that need to be type checked. - llvm::SmallVector SynthesizedDecls; - - /// We might perform type checking on the same source file more than once, - /// if its the main file or a REPL instance, so keep track of the last - /// checked synthesized declaration to avoid duplicating work. - unsigned LastCheckedSynthesizedDecl = 0; - - /// A mapping from Objective-C selectors to the methods that have - /// those selectors. - llvm::DenseMap> - ObjCMethods; - - /// List of Objective-C methods, which is used for checking unintended - /// Objective-C overrides. - std::vector ObjCMethodList; - - /// An unsatisfied, optional @objc requirement in a protocol conformance. - using ObjCUnsatisfiedOptReq = std::pair; - - /// List of optional @objc protocol requirements that have gone - /// unsatisfied, which might conflict with other Objective-C methods. - std::vector ObjCUnsatisfiedOptReqs; - - using ObjCMethodConflict = std::tuple; - - /// 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; - - enum ASTStage_t { - /// Parsing is underway. - Parsing, - /// Parsing has completed. - Parsed, - /// Name binding has completed. - NameBound, - /// Type checking has completed. - TypeChecked - }; - - /// Defines what phases of parsing and semantic analysis are complete for a - /// source file. - /// - /// Only files that have been fully processed (i.e. type-checked) will be - /// forwarded on to IRGen. - ASTStage_t ASTStage = Parsing; - - SourceFile(ModuleDecl &M, SourceFileKind K, Optional bufferID, - ImplicitModuleImportKind ModImpKind, bool KeepParsedTokens = false, - bool KeepSyntaxTree = false); - - ~SourceFile(); - - void addImports(ArrayRef IM); - - enum ImportQueryKind { - /// Return the results for testable or private imports. - TestableAndPrivate, - /// Return the results only for testable imports. - TestableOnly, - /// Return the results only for private imports. - PrivateOnly - }; - - bool - hasTestableOrPrivateImport(AccessLevel accessLevel, const ValueDecl *ofDecl, - ImportQueryKind kind = TestableAndPrivate) const; - - bool hasImplementationOnlyImports() const { - return HasImplementationOnlyImports; - } - - bool isImportedImplementationOnly(const ModuleDecl *module) const; - - /// This is a hack for 'main' file parsing and the integrated REPL. - /// - /// FIXME: Refactor main file parsing to not pump the parser incrementally. - /// FIXME: Remove the integrated REPL. - void clearLookupCache(); - - void cacheVisibleDecls(SmallVectorImpl &&globals) const; - const SmallVectorImpl &getCachedVisibleDecls() const; - - // SWIFT_ENABLE_TENSORFLOW - void addVisibleDecl(ValueDecl *decl); - - virtual void lookupValue(DeclName name, NLKind lookupKind, - SmallVectorImpl &result) const override; - - virtual void lookupVisibleDecls(ModuleDecl::AccessPathTy accessPath, - VisibleDeclConsumer &consumer, - NLKind lookupKind) const override; - - virtual void lookupClassMembers(ModuleDecl::AccessPathTy accessPath, - VisibleDeclConsumer &consumer) const override; - virtual void - lookupClassMember(ModuleDecl::AccessPathTy accessPath, DeclName name, - SmallVectorImpl &results) const override; - - void lookupObjCMethods( - ObjCSelector selector, - SmallVectorImpl &results) const override; - - virtual void getTopLevelDecls(SmallVectorImpl &results) const override; - - virtual void - getPrecedenceGroups(SmallVectorImpl &results) const override; - - virtual TypeDecl *lookupLocalType(llvm::StringRef MangledName) const override; - - virtual void - getLocalTypeDecls(SmallVectorImpl &results) const override; - virtual void - getOpaqueReturnTypeDecls(SmallVectorImpl &results) const override; - - virtual void - getImportedModules(SmallVectorImpl &imports, - ModuleDecl::ImportFilter filter) const override; - - virtual void - collectLinkLibraries(ModuleDecl::LinkLibraryCallback callback) const override; - - Identifier getDiscriminatorForPrivateValue(const ValueDecl *D) const override; - Identifier getPrivateDiscriminator() const { return PrivateDiscriminator; } - - virtual bool walk(ASTWalker &walker) override; - - /// @{ - - /// Look up the given operator in this file. - /// - /// The file must be name-bound already. If the operator is not found, or if - /// there is an ambiguity, returns null. - /// - /// \param isCascading If true, the lookup of this operator may affect - /// downstream files. - InfixOperatorDecl *lookupInfixOperator(Identifier name, bool isCascading, - SourceLoc diagLoc = {}); - PrefixOperatorDecl *lookupPrefixOperator(Identifier name, bool isCascading, - SourceLoc diagLoc = {}); - PostfixOperatorDecl *lookupPostfixOperator(Identifier name, bool isCascading, - SourceLoc diagLoc = {}); - PrecedenceGroupDecl *lookupPrecedenceGroup(Identifier name, bool isCascading, - SourceLoc diagLoc = {}); - /// @} - - ReferencedNameTracker *getReferencedNameTracker() { - return ReferencedNames ? ReferencedNames.getPointer() : nullptr; - } - const ReferencedNameTracker *getReferencedNameTracker() const { - return ReferencedNames ? ReferencedNames.getPointer() : nullptr; - } - - void createReferencedNameTracker(); - - /// The buffer ID for the file that was imported, or None if there - /// is no associated buffer. - Optional getBufferID() const { - if (BufferID == -1) - return None; - return BufferID; - } - - /// If this buffer corresponds to a file on disk, returns the path. - /// Otherwise, return an empty string. - StringRef getFilename() const; - - /// Retrieve the scope that describes this source file. - ASTScope &getScope(); - - void dump() const; - void dump(raw_ostream &os) const; - - /// Pretty-print the contents of this source file. - /// - /// \param Printer The AST printer used for printing the contents. - /// \param PO Options controlling the printing process. - void print(ASTPrinter &Printer, const PrintOptions &PO); - void print(raw_ostream &OS, const PrintOptions &PO); - - static bool classof(const FileUnit *file) { - return file->getKind() == FileUnitKind::Source; - } - static bool classof(const DeclContext *DC) { - return isa(DC) && classof(cast(DC)); - } - - /// True if this is a "script mode" source file that admits top-level code. - bool isScriptMode() const { - switch (Kind) { - case SourceFileKind::Main: - case SourceFileKind::REPL: - return true; - - case SourceFileKind::Library: - case SourceFileKind::Interface: - case SourceFileKind::SIL: - return false; - } - llvm_unreachable("bad SourceFileKind"); - } - - ClassDecl *getMainClass() const override { - return MainClass; - } - SourceLoc getMainClassDiagLoc() const { - assert(hasMainClass()); - return MainClassDiagLoc; - } - - /// Register a "main" class for the module, complaining if there is more than - /// one. - /// - /// Should only be called during type-checking. - bool registerMainClass(ClassDecl *mainClass, SourceLoc diagLoc); - - /// True if this source file has an application entry point. - /// - /// This is true if the source file either is in script mode or contains - /// a designated main class. - bool hasEntryPoint() const override { - return isScriptMode() || hasMainClass(); - } - - /// Get the root refinement context for the file. The root context may be - /// null if the context hierarchy has not been built yet. Use - /// TypeChecker::getOrBuildTypeRefinementContext() to get a built - /// root of the hierarchy. - TypeRefinementContext *getTypeRefinementContext(); - - /// Set the root refinement context for the file. - void setTypeRefinementContext(TypeRefinementContext *TRC); - - void enableInterfaceHash() { - assert(!hasInterfaceHash()); - InterfaceHash.emplace(); - } - - bool hasInterfaceHash() const { - return InterfaceHash.hasValue(); - } - - void recordInterfaceToken(StringRef token) { - assert(!token.empty()); - InterfaceHash->update(token); - // Add null byte to separate tokens. - uint8_t a[1] = {0}; - InterfaceHash->update(a); - } - - void getInterfaceHash(llvm::SmallString<32> &str) { - llvm::MD5::MD5Result result; - InterfaceHash->final(result); - llvm::MD5::stringifyResult(result, str); - } - - void dumpInterfaceHash(llvm::raw_ostream &out) { - llvm::SmallString<32> str; - getInterfaceHash(str); - out << str << '\n'; - } - - std::vector &getTokenVector(); - - ArrayRef getAllTokens() const; - - bool shouldCollectToken() const; - - bool shouldBuildSyntaxTree() const; - - bool canBeParsedInFull() const; - - bool isSuitableForASTScopes() const { return canBeParsedInFull(); } - - syntax::SourceFileSyntax getSyntaxRoot() const; - void setSyntaxRoot(syntax::SourceFileSyntax &&Root); - bool hasSyntaxRoot() const; - - OpaqueTypeDecl *lookupOpaqueResultType(StringRef MangledName, - LazyResolver *resolver) override; - - void addUnvalidatedDeclWithOpaqueResultType(ValueDecl *vd) { - UnvalidatedDeclsWithOpaqueReturnTypes.insert(vd); - } - - void markDeclWithOpaqueResultTypeAsValidated(ValueDecl *vd); - -private: - - /// If not None, the underlying vector should contain tokens of this source file. - Optional> AllCorrectedTokens; - - std::unique_ptr SyntaxInfo; -}; - - -/// This represents the compiler's implicitly generated declarations in the -/// Builtin module. -class BuiltinUnit final : public FileUnit { -public: - class LookupCache; - -private: - std::unique_ptr Cache; - LookupCache &getCache() const; - - friend ASTContext; - ~BuiltinUnit() = default; - -public: - explicit BuiltinUnit(ModuleDecl &M); - - virtual void lookupValue(DeclName name, NLKind lookupKind, - SmallVectorImpl &result) const override; - - /// Find all Objective-C methods with the given selector. - void lookupObjCMethods( - ObjCSelector selector, - SmallVectorImpl &results) const override; - - Identifier - getDiscriminatorForPrivateValue(const ValueDecl *D) const override { - llvm_unreachable("no private values in the Builtin module"); - } - - static bool classof(const FileUnit *file) { - return file->getKind() == FileUnitKind::Builtin; - } - - static bool classof(const DeclContext *DC) { - return isa(DC) && classof(cast(DC)); - } -}; - -/// Represents an externally-loaded file of some kind. -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wnon-virtual-dtor" -class LoadedFile : public FileUnit { -#pragma clang diagnostic pop -protected: - LoadedFile(FileUnitKind Kind, ModuleDecl &M) noexcept - : FileUnit(Kind, M) { - assert(classof(this) && "invalid kind"); - } -public: - /// Returns an arbitrary string representing the storage backing this file. - /// - /// This is usually a filesystem path. - virtual StringRef getFilename() const; - - virtual StringRef getFilenameForPrivateDecl(const ValueDecl *decl) const { - return StringRef(); - } - - /// Look up an operator declaration. - /// - /// \param name The operator name ("+", ">>", etc.) - /// - /// \param fixity One of PrefixOperator, InfixOperator, or PostfixOperator. - virtual OperatorDecl *lookupOperator(Identifier name, DeclKind fixity) const { - return nullptr; - } - - /// Look up a precedence group. - /// - /// \param name The precedence group name. - virtual PrecedenceGroupDecl *lookupPrecedenceGroup(Identifier name) const { - return nullptr; - } - - /// Returns the Swift module that overlays a Clang module. - virtual ModuleDecl *getOverlayModule() const { return nullptr; } - - virtual bool isSystemModule() const { return false; } - - /// Retrieve the set of generic signatures stored within this module. - /// - /// \returns \c true if this module file supports retrieving all of the - /// generic signatures, \c false otherwise. - virtual bool getAllGenericSignatures( - SmallVectorImpl &genericSignatures) { - return false; - } - - static bool classof(const FileUnit *file) { - return file->getKind() == FileUnitKind::SerializedAST || - file->getKind() == FileUnitKind::ClangModule || - file->getKind() == FileUnitKind::DWARFModule; - } - static bool classof(const DeclContext *DC) { - return isa(DC) && classof(cast(DC)); - } -}; - - -inline SourceFile & -ModuleDecl::getMainSourceFile(SourceFileKind expectedKind) const { - assert(!Files.empty() && "No files added yet"); - assert(cast(Files.front())->Kind == expectedKind); - return *cast(Files.front()); -} - -inline FileUnit &ModuleDecl::getMainFile(FileUnitKind expectedKind) const { - assert(expectedKind != FileUnitKind::Source && - "must use specific source kind; see getMainSourceFile"); - assert(!Files.empty() && "No files added yet"); - assert(Files.front()->getKind() == expectedKind); - return *Files.front(); -} - /// Wraps either a swift module or a clang one. /// FIXME: Should go away once swift modules can support submodules natively. class ModuleEntity { diff --git a/include/swift/AST/NameLookup.h b/include/swift/AST/NameLookup.h index 770f045f0f83c..367018f5ac2e8 100644 --- a/include/swift/AST/NameLookup.h +++ b/include/swift/AST/NameLookup.h @@ -592,9 +592,11 @@ class ASTScope { public: ASTScope(SourceFile *); - /// Cannot be lazy during type-checking because it mutates the AST. - /// So build eagerly before type-checking - void buildScopeTreeEagerly(); + void + buildEnoughOfTreeForTopLevelExpressionsButDontRequestGenericsOrExtendedNominals(); + + /// Flesh out the tree for dumping + void buildFullyExpandedTree(); /// \return the scopes traversed static llvm::SmallVector diff --git a/include/swift/AST/SourceFile.h b/include/swift/AST/SourceFile.h new file mode 100644 index 0000000000000..043ada7b7cc57 --- /dev/null +++ b/include/swift/AST/SourceFile.h @@ -0,0 +1,486 @@ +//===--- SourceFile.h - The contents of a source file -----------*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2019 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 +// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_AST_SOURCEFILE_H +#define SWIFT_AST_SOURCEFILE_H + +#include "swift/AST/FileUnit.h" + +namespace swift { + +/// A file containing Swift source code. +/// +/// This is a .swift or .sil file (or a virtual file, such as the contents of +/// the REPL). Since it contains raw source, it must be parsed and name-bound +/// before being used for anything; a full type-check is also necessary for +/// IR generation. +class SourceFile final : public FileUnit { +public: + class Impl; + struct SourceFileSyntaxInfo; + + /// The implicit module import that the SourceFile should get. + enum class ImplicitModuleImportKind { + None, + Builtin, + Stdlib + }; + + /// Possible attributes for imports in source files. + enum class ImportFlags { + /// The imported module is exposed to anyone who imports the parent module. + Exported = 0x1, + + /// This source file has access to testable declarations in the imported + /// module. + Testable = 0x2, + + /// This source file has access to private declarations in the imported + /// module. + PrivateImport = 0x4, + + /// The imported module is an implementation detail of this file and should + /// not be required to be present if the main module is ever imported + /// elsewhere. + /// + /// Mutually exclusive with Exported. + ImplementationOnly = 0x8 + }; + + /// \see ImportFlags + using ImportOptions = OptionSet; + + struct ImportedModuleDesc { + ModuleDecl::ImportedModule module; + ImportOptions importOptions; + StringRef filename; + + ImportedModuleDesc(ModuleDecl::ImportedModule module, ImportOptions options, + StringRef filename = {}) + : module(module), importOptions(options), filename(filename) { + assert(!(importOptions.contains(ImportFlags::Exported) && + importOptions.contains(ImportFlags::ImplementationOnly))); + } + }; + +private: + std::unique_ptr Cache; + SourceLookupCache &getCache() const; + + /// This is the list of modules that are imported by this module. + /// + /// This is filled in by the Name Binding phase. + ArrayRef Imports; + + /// A unique identifier representing this file; used to mark private decls + /// within the file to keep them from conflicting with other files in the + /// same module. + mutable Identifier PrivateDiscriminator; + + /// The root TypeRefinementContext for this SourceFile. + /// + /// This is set during type checking. + TypeRefinementContext *TRC = nullptr; + + /// If non-null, used to track name lookups that happen within this file. + Optional ReferencedNames; + + /// The class in this file marked \@NS/UIApplicationMain. + ClassDecl *MainClass = nullptr; + + /// The source location of the main class. + SourceLoc MainClassDiagLoc; + + /// A hash of all interface-contributing tokens that have been lexed for + /// this source file so far. + /// We only collect interface hash for primary input files. + llvm::Optional InterfaceHash; + + /// The ID for the memory buffer containing this file's source. + /// + /// May be -1, to indicate no association with a buffer. + int BufferID; + + /// Does this source file have any implementation-only imports? + /// If not, we can fast-path module checks. + bool HasImplementationOnlyImports = false; + + /// The scope map that describes this source file. + std::unique_ptr Scope; + + friend ASTContext; + friend Impl; +public: + /// The list of top-level declarations in the source file. + std::vector Decls; + + /// A cache of syntax nodes that can be reused when creating the syntax tree + /// for this file. + SyntaxParsingCache *SyntaxParsingCache = nullptr; + + /// The list of local type declarations in the source file. + llvm::SetVector LocalTypeDecls; + + /// The set of validated opaque return type decls in the source file. + llvm::SmallVector OpaqueReturnTypes; + llvm::StringMap ValidatedOpaqueReturnTypes; + /// The set of parsed decls with opaque return types that have not yet + /// been validated. + llvm::DenseSet UnvalidatedDeclsWithOpaqueReturnTypes; + + /// A set of special declaration attributes which require the + /// Foundation module to be imported to work. If the foundation + /// module is still not imported by the time type checking is + /// complete, we diagnose. + llvm::SetVector AttrsRequiringFoundation; + + /// A set of synthesized declarations that need to be type checked. + llvm::SmallVector SynthesizedDecls; + + /// We might perform type checking on the same source file more than once, + /// if its the main file or a REPL instance, so keep track of the last + /// checked synthesized declaration to avoid duplicating work. + unsigned LastCheckedSynthesizedDecl = 0; + + /// A mapping from Objective-C selectors to the methods that have + /// those selectors. + llvm::DenseMap> + ObjCMethods; + + /// List of Objective-C methods, which is used for checking unintended + /// Objective-C overrides. + std::vector ObjCMethodList; + + /// An unsatisfied, optional @objc requirement in a protocol conformance. + using ObjCUnsatisfiedOptReq = std::pair; + + /// List of optional @objc protocol requirements that have gone + /// unsatisfied, which might conflict with other Objective-C methods. + std::vector ObjCUnsatisfiedOptReqs; + + using ObjCMethodConflict = std::tuple; + + /// 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; + + enum ASTStage_t { + /// Parsing is underway. + Parsing, + /// Parsing has completed. + Parsed, + /// Name binding has completed. + NameBound, + /// Type checking has completed. + TypeChecked + }; + + /// Defines what phases of parsing and semantic analysis are complete for a + /// source file. + /// + /// Only files that have been fully processed (i.e. type-checked) will be + /// forwarded on to IRGen. + ASTStage_t ASTStage = Parsing; + + SourceFile(ModuleDecl &M, SourceFileKind K, Optional bufferID, + ImplicitModuleImportKind ModImpKind, bool KeepParsedTokens = false, + bool KeepSyntaxTree = false); + + ~SourceFile(); + + void addImports(ArrayRef IM); + + enum ImportQueryKind { + /// Return the results for testable or private imports. + TestableAndPrivate, + /// Return the results only for testable imports. + TestableOnly, + /// Return the results only for private imports. + PrivateOnly + }; + + bool + hasTestableOrPrivateImport(AccessLevel accessLevel, const ValueDecl *ofDecl, + ImportQueryKind kind = TestableAndPrivate) const; + + bool hasImplementationOnlyImports() const { + return HasImplementationOnlyImports; + } + + bool isImportedImplementationOnly(const ModuleDecl *module) const; + + /// This is a hack for 'main' file parsing and the integrated REPL. + /// + /// FIXME: Refactor main file parsing to not pump the parser incrementally. + /// FIXME: Remove the integrated REPL. + void clearLookupCache(); + + void cacheVisibleDecls(SmallVectorImpl &&globals) const; + const SmallVectorImpl &getCachedVisibleDecls() const; + + // SWIFT_ENABLE_TENSORFLOW + void addVisibleDecl(ValueDecl *decl); + + virtual void lookupValue(DeclName name, NLKind lookupKind, + SmallVectorImpl &result) const override; + + virtual void lookupVisibleDecls(ModuleDecl::AccessPathTy accessPath, + VisibleDeclConsumer &consumer, + NLKind lookupKind) const override; + + virtual void lookupClassMembers(ModuleDecl::AccessPathTy accessPath, + VisibleDeclConsumer &consumer) const override; + virtual void + lookupClassMember(ModuleDecl::AccessPathTy accessPath, DeclName name, + SmallVectorImpl &results) const override; + + void lookupObjCMethods( + ObjCSelector selector, + SmallVectorImpl &results) const override; + + virtual void getTopLevelDecls(SmallVectorImpl &results) const override; + + virtual void + getPrecedenceGroups(SmallVectorImpl &results) const override; + + virtual TypeDecl *lookupLocalType(llvm::StringRef MangledName) const override; + + virtual void + getLocalTypeDecls(SmallVectorImpl &results) const override; + virtual void + getOpaqueReturnTypeDecls(SmallVectorImpl &results) const override; + + virtual void + getImportedModules(SmallVectorImpl &imports, + ModuleDecl::ImportFilter filter) const override; + + virtual void + collectLinkLibraries(ModuleDecl::LinkLibraryCallback callback) const override; + + Identifier getDiscriminatorForPrivateValue(const ValueDecl *D) const override; + Identifier getPrivateDiscriminator() const { return PrivateDiscriminator; } + + virtual bool walk(ASTWalker &walker) override; + + /// @{ + + /// Look up the given operator in this file. + /// + /// The file must be name-bound already. If the operator is not found, or if + /// there is an ambiguity, returns null. + /// + /// \param isCascading If true, the lookup of this operator may affect + /// downstream files. + InfixOperatorDecl *lookupInfixOperator(Identifier name, bool isCascading, + SourceLoc diagLoc = {}); + PrefixOperatorDecl *lookupPrefixOperator(Identifier name, bool isCascading, + SourceLoc diagLoc = {}); + PostfixOperatorDecl *lookupPostfixOperator(Identifier name, bool isCascading, + SourceLoc diagLoc = {}); + PrecedenceGroupDecl *lookupPrecedenceGroup(Identifier name, bool isCascading, + SourceLoc diagLoc = {}); + /// @} + + ReferencedNameTracker *getReferencedNameTracker() { + return ReferencedNames ? ReferencedNames.getPointer() : nullptr; + } + const ReferencedNameTracker *getReferencedNameTracker() const { + return ReferencedNames ? ReferencedNames.getPointer() : nullptr; + } + + void createReferencedNameTracker(); + + /// The buffer ID for the file that was imported, or None if there + /// is no associated buffer. + Optional getBufferID() const { + if (BufferID == -1) + return None; + return BufferID; + } + + /// If this buffer corresponds to a file on disk, returns the path. + /// Otherwise, return an empty string. + StringRef getFilename() const; + + /// Retrieve the scope that describes this source file. + ASTScope &getScope(); + + void dump() const; + void dump(raw_ostream &os) const; + + /// Pretty-print the contents of this source file. + /// + /// \param Printer The AST printer used for printing the contents. + /// \param PO Options controlling the printing process. + void print(ASTPrinter &Printer, const PrintOptions &PO); + void print(raw_ostream &OS, const PrintOptions &PO); + + static bool classof(const FileUnit *file) { + return file->getKind() == FileUnitKind::Source; + } + static bool classof(const DeclContext *DC) { + return isa(DC) && classof(cast(DC)); + } + + /// True if this is a "script mode" source file that admits top-level code. + bool isScriptMode() const { + switch (Kind) { + case SourceFileKind::Main: + case SourceFileKind::REPL: + return true; + + case SourceFileKind::Library: + case SourceFileKind::Interface: + case SourceFileKind::SIL: + return false; + } + llvm_unreachable("bad SourceFileKind"); + } + + ClassDecl *getMainClass() const override { + return MainClass; + } + SourceLoc getMainClassDiagLoc() const { + assert(hasMainClass()); + return MainClassDiagLoc; + } + + /// Register a "main" class for the module, complaining if there is more than + /// one. + /// + /// Should only be called during type-checking. + bool registerMainClass(ClassDecl *mainClass, SourceLoc diagLoc); + + /// True if this source file has an application entry point. + /// + /// This is true if the source file either is in script mode or contains + /// a designated main class. + bool hasEntryPoint() const override { + return isScriptMode() || hasMainClass(); + } + + /// Get the root refinement context for the file. The root context may be + /// null if the context hierarchy has not been built yet. Use + /// TypeChecker::getOrBuildTypeRefinementContext() to get a built + /// root of the hierarchy. + TypeRefinementContext *getTypeRefinementContext(); + + /// Set the root refinement context for the file. + void setTypeRefinementContext(TypeRefinementContext *TRC); + + void enableInterfaceHash() { + assert(!hasInterfaceHash()); + InterfaceHash.emplace(); + } + + bool hasInterfaceHash() const { + return InterfaceHash.hasValue(); + } + + void recordInterfaceToken(StringRef token) { + assert(!token.empty()); + InterfaceHash->update(token); + // Add null byte to separate tokens. + uint8_t a[1] = {0}; + InterfaceHash->update(a); + } + + void getInterfaceHash(llvm::SmallString<32> &str) { + llvm::MD5::MD5Result result; + InterfaceHash->final(result); + llvm::MD5::stringifyResult(result, str); + } + + void dumpInterfaceHash(llvm::raw_ostream &out) { + llvm::SmallString<32> str; + getInterfaceHash(str); + out << str << '\n'; + } + + std::vector &getTokenVector(); + + ArrayRef getAllTokens() const; + + bool shouldCollectToken() const; + + bool shouldBuildSyntaxTree() const; + + bool canBeParsedInFull() const; + + bool isSuitableForASTScopes() const { return canBeParsedInFull(); } + + syntax::SourceFileSyntax getSyntaxRoot() const; + void setSyntaxRoot(syntax::SourceFileSyntax &&Root); + bool hasSyntaxRoot() const; + + OpaqueTypeDecl *lookupOpaqueResultType(StringRef MangledName, + LazyResolver *resolver) override; + + void addUnvalidatedDeclWithOpaqueResultType(ValueDecl *vd) { + UnvalidatedDeclsWithOpaqueReturnTypes.insert(vd); + } + + void markDeclWithOpaqueResultTypeAsValidated(ValueDecl *vd); + +private: + + /// If not None, the underlying vector should contain tokens of this source file. + Optional> AllCorrectedTokens; + + std::unique_ptr SyntaxInfo; +}; + +inline SourceFile & +ModuleDecl::getMainSourceFile(SourceFileKind expectedKind) const { + assert(!Files.empty() && "No files added yet"); + assert(cast(Files.front())->Kind == expectedKind); + return *cast(Files.front()); +} + +inline FileUnit *ModuleDecl::EntryPointInfoTy::getEntryPointFile() const { + return storage.getPointer(); +} +inline void ModuleDecl::EntryPointInfoTy::setEntryPointFile(FileUnit *file) { + assert(!storage.getPointer()); + storage.setPointer(file); +} + +inline bool ModuleDecl::EntryPointInfoTy::hasEntryPoint() const { + return storage.getPointer(); +} + +inline bool ModuleDecl::EntryPointInfoTy::markDiagnosedMultipleMainClasses() { + bool res = storage.getInt().contains(Flags::DiagnosedMultipleMainClasses); + storage.setInt(storage.getInt() | Flags::DiagnosedMultipleMainClasses); + return !res; +} + +inline bool ModuleDecl::EntryPointInfoTy::markDiagnosedMainClassWithScript() { + bool res = storage.getInt().contains(Flags::DiagnosedMainClassWithScript); + storage.setInt(storage.getInt() | Flags::DiagnosedMainClassWithScript); + return !res; +} + +} // end namespace swift + +#endif diff --git a/include/swift/AST/TypeCheckRequests.h b/include/swift/AST/TypeCheckRequests.h index 2ded805fbf86e..1df99c4070cf1 100644 --- a/include/swift/AST/TypeCheckRequests.h +++ b/include/swift/AST/TypeCheckRequests.h @@ -441,6 +441,9 @@ class RequirementRequest : // Source location SourceLoc getNearestLoc() const; + // Cycle handling. + void noteCycleStep(DiagnosticEngine &diags) const; + // Separate caching. bool isCached() const; Optional getCachedResult() const; @@ -1127,6 +1130,9 @@ class InferredGenericSignatureRequest : SourceLoc getNearestLoc() const { return SourceLoc(); } + + // Cycle handling. + void noteCycleStep(DiagnosticEngine &diags) const; }; void simple_display(llvm::raw_ostream &out, const TypeLoc source); @@ -1167,6 +1173,49 @@ class FunctionOperatorRequest : bool isCached() const { return true; } }; +class GenericSignatureRequest : + public SimpleRequest { +public: + using SimpleRequest::SimpleRequest; + +private: + friend SimpleRequest; + + // Evaluation. + llvm::Expected + evaluate(Evaluator &evaluator, GenericContext *value) const; + +public: + // Separate caching. + bool isCached() const { return true; } + Optional getCachedResult() const; + void cacheResult(GenericSignature *value) const; +}; + +/// Compute the interface type of the underlying definition type of a typealias declaration. +class UnderlyingTypeRequest : + public SimpleRequest { +public: + using SimpleRequest::SimpleRequest; + +private: + friend SimpleRequest; + + // Evaluation. + llvm::Expected evaluate(Evaluator &evaluator, + TypeAliasDecl *decl) const; + +public: + // Caching. + bool isCached() const { return true; } + Optional getCachedResult() const; + void cacheResult(Type value) 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 c600565126102..366f11d775700 100644 --- a/include/swift/AST/TypeCheckerTypeIDZone.def +++ b/include/swift/AST/TypeCheckerTypeIDZone.def @@ -49,6 +49,9 @@ SWIFT_REQUEST(TypeChecker, FunctionBuilderTypeRequest, Type(ValueDecl *), Cached, NoLocationInfo) SWIFT_REQUEST(TypeChecker, FunctionOperatorRequest, OperatorDecl *(FuncDecl *), Cached, NoLocationInfo) +SWIFT_REQUEST(NameLookup, GenericSignatureRequest, + GenericSignature *(GenericContext *), + SeparatelyCached, NoLocationInfo) SWIFT_REQUEST(TypeChecker, InferredGenericSignatureRequest, GenericSignature *(ModuleDecl *, GenericSignature *, SmallVector, @@ -129,5 +132,7 @@ SWIFT_REQUEST(TypeChecker, SynthesizeAccessorRequest, SeparatelyCached, NoLocationInfo) SWIFT_REQUEST(TypeChecker, TypeCheckFunctionBodyUntilRequest, bool(AbstractFunctionDecl *, SourceLoc), Cached, NoLocationInfo) +SWIFT_REQUEST(TypeChecker, UnderlyingTypeRequest, Type(TypeAliasDecl *), + SeparatelyCached, NoLocationInfo) SWIFT_REQUEST(TypeChecker, USRGenerationRequest, std::string(const ValueDecl *), Cached, NoLocationInfo) diff --git a/include/swift/Basic/LangOptions.h b/include/swift/Basic/LangOptions.h index b1d6ab3dd8f21..27a075a669f77 100644 --- a/include/swift/Basic/LangOptions.h +++ b/include/swift/Basic/LangOptions.h @@ -248,13 +248,13 @@ namespace swift { /// Default is in \c ParseLangArgs /// /// This is a staging flag; eventually it will be removed. - bool EnableASTScopeLookup = false; + bool EnableASTScopeLookup = true; /// Someday, ASTScopeLookup will supplant lookup in the parser bool DisableParserLookup = false; /// Should we compare to ASTScope-based resolution for debugging? - bool CompareToASTScopeLookup = false; + bool CrosscheckUnqualifiedLookup = false; /// Should we stress ASTScope-based resolution for debugging? bool StressASTScopeLookup = false; diff --git a/include/swift/ClangImporter/ClangModule.h b/include/swift/ClangImporter/ClangModule.h index 0e25a2afe1cd1..baa65c5551ebf 100644 --- a/include/swift/ClangImporter/ClangModule.h +++ b/include/swift/ClangImporter/ClangModule.h @@ -16,7 +16,7 @@ #ifndef SWIFT_CLANGIMPORTER_CLANGMODULE_H #define SWIFT_CLANGIMPORTER_CLANGMODULE_H -#include "swift/AST/Module.h" +#include "swift/AST/FileUnit.h" #include "swift/ClangImporter/ClangImporter.h" #include "clang/AST/ExternalASTSource.h" diff --git a/include/swift/Frontend/Frontend.h b/include/swift/Frontend/Frontend.h index f02499381f35b..be9ab9390f66d 100644 --- a/include/swift/Frontend/Frontend.h +++ b/include/swift/Frontend/Frontend.h @@ -25,6 +25,7 @@ #include "swift/AST/Module.h" #include "swift/AST/SILOptions.h" #include "swift/AST/SearchPathOptions.h" +#include "swift/AST/SourceFile.h" #include "swift/Basic/DiagnosticOptions.h" #include "swift/Basic/LangOptions.h" #include "swift/Basic/SourceManager.h" diff --git a/include/swift/IDE/CodeCompletion.h b/include/swift/IDE/CodeCompletion.h index 427013647a6c8..e6b2d63290a49 100644 --- a/include/swift/IDE/CodeCompletion.h +++ b/include/swift/IDE/CodeCompletion.h @@ -498,7 +498,6 @@ enum class CompletionKind { AttributeBegin, AttributeDeclParen, PoundAvailablePlatform, - AssignmentRHS, CallArg, ReturnStmtExpr, YieldStmtExpr, diff --git a/include/swift/IDE/IDERequests.h b/include/swift/IDE/IDERequests.h index ef3d0ea079696..2247fe65afade 100644 --- a/include/swift/IDE/IDERequests.h +++ b/include/swift/IDE/IDERequests.h @@ -19,6 +19,7 @@ #include "swift/AST/ASTTypeIDs.h" #include "swift/AST/Evaluator.h" #include "swift/AST/SimpleRequest.h" +#include "swift/AST/SourceFile.h" #include "swift/IDE/Utils.h" #include "swift/IDE/IDETypeIDs.h" diff --git a/include/swift/Migrator/ASTMigratorPass.h b/include/swift/Migrator/ASTMigratorPass.h index 7b8f96473f024..847791d2e98c2 100644 --- a/include/swift/Migrator/ASTMigratorPass.h +++ b/include/swift/Migrator/ASTMigratorPass.h @@ -19,6 +19,7 @@ #define SWIFT_MIGRATOR_ASTMIGRATORPASS_H #include "swift/AST/ASTContext.h" +#include "swift/AST/SourceFile.h" #include "swift/Migrator/EditorAdapter.h" namespace swift { diff --git a/include/swift/Option/FrontendOptions.td b/include/swift/Option/FrontendOptions.td index 4277f7725fa54..25509ee0a8676 100644 --- a/include/swift/Option/FrontendOptions.td +++ b/include/swift/Option/FrontendOptions.td @@ -86,6 +86,10 @@ def tbd_compatibility_version def tbd_compatibility_version_EQ : Joined<["-"], "tbd-compatibility-version=">, Alias; +def tbd_is_installapi: Flag<["-"], "tbd-is-installapi">, + HelpText<"If the TBD file should indicate it's being generated during " + "InstallAPI">; + def verify : Flag<["-"], "verify">, HelpText<"Verify diagnostics against expected-{error|warning|note} " "annotations">; @@ -122,8 +126,8 @@ def disable_target_os_checking : Flag<["-"], "disable-target-os-checking">, HelpText<"Disable checking the target OS of serialized modules">; -def compare_to_astscope_lookup : Flag<["-"], "compare-to-astscope-lookup">, - HelpText<"Compare legacy to ASTScope-based unqualified name lookup (for debugging)">; +def crosscheck_unqualified_lookup : Flag<["-"], "crosscheck-unqualified-lookup">, + HelpText<"Compare legacy DeclContext- to ASTScope-based unqualified name lookup (for debugging)">; def stress_astscope_lookup : Flag<["-"], "stress-astscope-lookup">, HelpText<"Stress ASTScope-based unqualified name lookup (for testing)">; diff --git a/include/swift/Option/Options.td b/include/swift/Option/Options.td index 9e48a376b62e5..5a817c641d1fc 100644 --- a/include/swift/Option/Options.td +++ b/include/swift/Option/Options.td @@ -517,14 +517,9 @@ def no_static_stdlib: Flag<["-"], "no-static-stdlib">, def toolchain_stdlib_rpath: Flag<["-"], "toolchain-stdlib-rpath">, Flags<[HelpHidden,DoesNotAffectIncrementalBuild]>, HelpText<"Add an rpath entry for the toolchain's standard library, rather than the OS's">; -// SWIFT_ENABLE_TENSORFLOW -// NOTE(TF-797): The default for `toolchain_stdlib_rpath` is set to true to -// prevent TensorFlow linker errors. Thus, the `no_toolchain_stdlib_rpath` flag -// is necessary to opt out of the default behavior. def no_toolchain_stdlib_rpath: Flag<["-"], "no-toolchain-stdlib-rpath">, Flags<[HelpHidden,DoesNotAffectIncrementalBuild]>, - HelpText<"Do not add an rpath entry for the toolchain's standard library, rather than the OS's">; -// SWIFT_ENABLE_TENSORFLOW END + HelpText<"Do not add an rpath entry for the toolchain's standard library (default)">; def no_stdlib_rpath: Flag<["-"], "no-stdlib-rpath">, Flags<[HelpHidden,DoesNotAffectIncrementalBuild]>, HelpText<"Don't add any rpath entries.">; diff --git a/include/swift/Parse/ASTGen.h b/include/swift/Parse/ASTGen.h index 4f29a8bb3a8b0..7cec25cbea816 100644 --- a/include/swift/Parse/ASTGen.h +++ b/include/swift/Parse/ASTGen.h @@ -22,96 +22,157 @@ namespace swift { /// Generates AST nodes from Syntax nodes. +class Parser; class ASTGen { ASTContext &Context; /// Type cache to prevent multiple transformations of the same syntax node. llvm::DenseMap TypeCache; - PersistentParserState **ParserState; + Parser &P; - // FIXME: remove when Syntax can represent all types and ASTGen can handle them + // FIXME: remove when Syntax can represent all types and ASTGen can handle + // them /// Types that cannot be represented by Syntax or generated by ASTGen. llvm::DenseMap Types; + llvm::DenseMap ParsedDeclAttrs; + public: - ASTGen(ASTContext &Context, PersistentParserState **ParserState) - : Context(Context), ParserState(ParserState) {} - - SourceLoc generate(syntax::TokenSyntax Tok, SourceLoc &Loc); - - Expr *generate(syntax::IntegerLiteralExprSyntax &Expr, SourceLoc &Loc); - Expr *generate(syntax::FloatLiteralExprSyntax &Expr, SourceLoc &Loc); - Expr *generate(syntax::NilLiteralExprSyntax &Expr, SourceLoc &Loc); - Expr *generate(syntax::BooleanLiteralExprSyntax &Expr, SourceLoc &Loc); - Expr *generate(syntax::PoundFileExprSyntax &Expr, SourceLoc &Loc); - Expr *generate(syntax::PoundLineExprSyntax &Expr, SourceLoc &Loc); - Expr *generate(syntax::PoundColumnExprSyntax &Expr, SourceLoc &Loc); - Expr *generate(syntax::PoundFunctionExprSyntax &Expr, SourceLoc &Loc); - Expr *generate(syntax::PoundDsohandleExprSyntax &Expr, SourceLoc &Loc); - Expr *generate(syntax::UnknownExprSyntax &Expr, SourceLoc &Loc); - - TypeRepr *generate(syntax::TypeSyntax Type, SourceLoc &Loc); - TypeRepr *generate(syntax::SomeTypeSyntax Type, SourceLoc &Loc); - TypeRepr *generate(syntax::CompositionTypeSyntax Type, SourceLoc &Loc); - TypeRepr *generate(syntax::SimpleTypeIdentifierSyntax Type, SourceLoc &Loc); - TypeRepr *generate(syntax::MemberTypeIdentifierSyntax Type, SourceLoc &Loc); - TypeRepr *generate(syntax::DictionaryTypeSyntax Type, SourceLoc &Loc); - TypeRepr *generate(syntax::ArrayTypeSyntax Type, SourceLoc &Loc); - TypeRepr *generate(syntax::TupleTypeSyntax Type, SourceLoc &Loc); - TypeRepr *generate(syntax::AttributedTypeSyntax Type, SourceLoc &Loc); - TypeRepr *generate(syntax::FunctionTypeSyntax Type, SourceLoc &Loc); - TypeRepr *generate(syntax::MetatypeTypeSyntax Type, SourceLoc &Loc); - TypeRepr *generate(syntax::OptionalTypeSyntax Type, SourceLoc &Loc); - TypeRepr *generate(syntax::ImplicitlyUnwrappedOptionalTypeSyntax Type, SourceLoc &Loc); - TypeRepr *generate(syntax::UnknownTypeSyntax Type, SourceLoc &Loc); - - TypeRepr *generate(syntax::GenericArgumentSyntax Arg, SourceLoc &Loc); - llvm::SmallVector - generate(syntax::GenericArgumentListSyntax Args, SourceLoc &Loc); + ASTGen(ASTContext &Context, Parser &P) : Context(Context), P(P) {} - /// Copy a numeric literal value into AST-owned memory, stripping underscores - /// so the semantic part of the value can be parsed by APInt/APFloat parsers. - static StringRef copyAndStripUnderscores(StringRef Orig, ASTContext &Context); + SourceLoc generate(const syntax::TokenSyntax &Tok, const SourceLoc Loc); + +public: + //===--------------------------------------------------------------------===// + // Expressions. + + Expr *generate(const syntax::IntegerLiteralExprSyntax &Expr, + const SourceLoc Loc); + Expr *generate(const syntax::FloatLiteralExprSyntax &Expr, + const SourceLoc Loc); + Expr *generate(const syntax::NilLiteralExprSyntax &Expr, const SourceLoc Loc); + Expr *generate(const syntax::BooleanLiteralExprSyntax &Expr, + const SourceLoc Loc); + Expr *generate(const syntax::PoundFileExprSyntax &Expr, const SourceLoc Loc); + Expr *generate(const syntax::PoundLineExprSyntax &Expr, const SourceLoc Loc); + Expr *generate(const syntax::PoundColumnExprSyntax &Expr, + const SourceLoc Loc); + Expr *generate(const syntax::PoundFunctionExprSyntax &Expr, + const SourceLoc Loc); + Expr *generate(const syntax::PoundDsohandleExprSyntax &Expr, + const SourceLoc Loc); + Expr *generate(const syntax::UnknownExprSyntax &Expr, const SourceLoc Loc); private: - Expr *generateMagicIdentifierLiteralExpression(syntax::TokenSyntax PoundToken, - SourceLoc &Loc); + Expr *generateMagicIdentifierLiteralExpression( + const syntax::TokenSyntax &PoundToken, const SourceLoc Loc); - TupleTypeRepr *generateTuple(syntax::TokenSyntax LParen, - syntax::TupleTypeElementListSyntax Elements, - syntax::TokenSyntax RParen, SourceLoc &Loc, - bool IsFunction = false); + static MagicIdentifierLiteralExpr::Kind + getMagicIdentifierLiteralKind(tok Kind); + +public: + //===--------------------------------------------------------------------===// + // Types. + + TypeRepr *generate(const syntax::TypeSyntax &Type, const SourceLoc Loc); + TypeRepr *generate(const syntax::SomeTypeSyntax &Type, const SourceLoc Loc); + TypeRepr *generate(const syntax::CompositionTypeSyntax &Type, + const SourceLoc Loc); + TypeRepr *generate(const syntax::SimpleTypeIdentifierSyntax &Type, + const SourceLoc Loc); + TypeRepr *generate(const syntax::MemberTypeIdentifierSyntax &Type, + const SourceLoc Loc); + TypeRepr *generate(const syntax::DictionaryTypeSyntax &Type, + const SourceLoc Loc); + TypeRepr *generate(const syntax::ArrayTypeSyntax &Type, const SourceLoc Loc); + TypeRepr *generate(const syntax::TupleTypeSyntax &Type, const SourceLoc Loc); + TypeRepr *generate(const syntax::AttributedTypeSyntax &Type, + const SourceLoc Loc); + TypeRepr *generate(const syntax::FunctionTypeSyntax &Type, + const SourceLoc Loc); + TypeRepr *generate(const syntax::MetatypeTypeSyntax &Type, + const SourceLoc Loc); + TypeRepr *generate(const syntax::OptionalTypeSyntax &Type, + const SourceLoc Loc); + TypeRepr *generate(const syntax::ImplicitlyUnwrappedOptionalTypeSyntax &Type, + const SourceLoc Loc); + TypeRepr *generate(const syntax::CodeCompletionTypeSyntax &Type, + const SourceLoc Loc); + TypeRepr *generate(const syntax::UnknownTypeSyntax &Type, + const SourceLoc Loc); + +private: + TupleTypeRepr * + generateTuple(const syntax::TokenSyntax &LParen, + const syntax::TupleTypeElementListSyntax &Elements, + const syntax::TokenSyntax &RParen, const SourceLoc Loc, + bool IsFunction = false); void gatherTypeIdentifierComponents( - syntax::TypeSyntax Component, SourceLoc &Loc, + const syntax::TypeSyntax &Component, const SourceLoc Loc, llvm::SmallVectorImpl &Components); template - TypeRepr *generateSimpleOrMemberIdentifier(T Type, SourceLoc &Loc); + TypeRepr *generateSimpleOrMemberIdentifier(const T &Type, + const SourceLoc Loc); template - ComponentIdentTypeRepr *generateIdentifier(T Type, SourceLoc &Loc); + ComponentIdentTypeRepr *generateIdentifier(const T &Type, + const SourceLoc Loc); + +public: + //===--------------------------------------------------------------------===// + // Generics. + TypeRepr *generate(const syntax::GenericArgumentSyntax &Arg, + const SourceLoc Loc); + llvm::SmallVector + generate(const syntax::GenericArgumentListSyntax &Args, const SourceLoc Loc); + + GenericParamList * + generate(const syntax::GenericParameterClauseListSyntax &clause, + const SourceLoc Loc); + GenericParamList *generate(const syntax::GenericParameterClauseSyntax &clause, + const SourceLoc Loc); + Optional + generate(const syntax::GenericRequirementSyntax &req, const SourceLoc Loc); + LayoutConstraint generate(const syntax::LayoutConstraintSyntax &req, + const SourceLoc Loc); + +public: + //===--------------------------------------------------------------------===// + // Utilities. + + /// Copy a numeric literal value into AST-owned memory, stripping underscores + /// so the semantic part of the value can be parsed by APInt/APFloat parsers. + static StringRef copyAndStripUnderscores(StringRef Orig, ASTContext &Context); + +private: StringRef copyAndStripUnderscores(StringRef Orig); + /// Advance \p Loc to the first token of the \p Node. + /// \p Loc must be the leading trivia of the first token in the tree in which + /// \p Node resides. static SourceLoc advanceLocBegin(const SourceLoc &Loc, const syntax::Syntax &Node); - static MagicIdentifierLiteralExpr::Kind getMagicIdentifierLiteralKind(tok Kind); - ValueDecl *lookupInScope(DeclName Name); + void addToScope(ValueDecl *D, bool diagnoseRedefinitions = true); + TypeRepr *cacheType(syntax::TypeSyntax Type, TypeRepr *TypeAST); TypeRepr *lookupType(syntax::TypeSyntax Type); public: - TypeRepr *addType(TypeRepr *Type, const SourceLoc &Loc); - - bool hasType(const SourceLoc &Loc) const; + void addType(TypeRepr *Type, const SourceLoc Loc); + bool hasType(const SourceLoc Loc) const; + TypeRepr *getType(const SourceLoc Loc) const; - TypeRepr *getType(const SourceLoc &Loc) const; + void addDeclAttributes(DeclAttributes attrs, const SourceLoc Loc); + bool hasDeclAttributes(SourceLoc Loc) const; + DeclAttributes getDeclAttributes(const SourceLoc Loc) const; }; } // namespace swift diff --git a/include/swift/Parse/CodeCompletionCallbacks.h b/include/swift/Parse/CodeCompletionCallbacks.h index 6117ea5d9a2a9..b221f772ce539 100644 --- a/include/swift/Parse/CodeCompletionCallbacks.h +++ b/include/swift/Parse/CodeCompletionCallbacks.h @@ -40,6 +40,8 @@ class CodeCompletionCallbacks { /// completion. This declaration contained the code completion token. Decl *ParsedDecl = nullptr; + TypeLoc ParsedTypeLoc; + /// True if code completion is done inside a raw value expression of an enum /// case. bool InEnumElementRawValue = false; @@ -76,6 +78,10 @@ class CodeCompletionCallbacks { ParsedDecl = D; } + void setParsedTypeLoc(TypeLoc TyLoc) { + ParsedTypeLoc = TyLoc; + } + void setLeadingSequenceExprs(ArrayRef exprs) { leadingSequenceExprs.assign(exprs.begin(), exprs.end()); } @@ -159,10 +165,10 @@ class CodeCompletionCallbacks { virtual void completeTypeSimpleBeginning() {}; /// Complete a given type-identifier after we have consumed the dot. - virtual void completeTypeIdentifierWithDot(IdentTypeRepr *ITR) {}; + virtual void completeTypeIdentifierWithDot() {}; /// Complete a given type-identifier when there is no trailing dot. - virtual void completeTypeIdentifierWithoutDot(IdentTypeRepr *ITR) {}; + virtual void completeTypeIdentifierWithoutDot() {}; /// Complete the beginning of a case statement at the top of switch stmt. virtual void completeCaseStmtKeyword() {}; @@ -200,8 +206,6 @@ class CodeCompletionCallbacks { virtual void completeUnresolvedMember(CodeCompletionExpr *E, SourceLoc DotLoc) {}; - virtual void completeAssignmentRHS(AssignExpr *E) {}; - virtual void completeCallArg(CodeCompletionExpr *E, bool isFirst) {}; virtual void completeReturnStmt(CodeCompletionExpr *E) {}; diff --git a/include/swift/Parse/Lexer.h b/include/swift/Parse/Lexer.h index 8441a12dc17d4..2849c41f1eca3 100644 --- a/include/swift/Parse/Lexer.h +++ b/include/swift/Parse/Lexer.h @@ -200,8 +200,8 @@ class Lexer { ParsedTrivia &TrailingTriviaResult) { Result = NextToken; if (TriviaRetention == TriviaRetentionMode::WithTrivia) { - LeadingTriviaResult = {LeadingTrivia}; - TrailingTriviaResult = {TrailingTrivia}; + std::swap(LeadingTriviaResult, LeadingTrivia); + std::swap(TrailingTriviaResult, TrailingTrivia); } if (Result.isNot(tok::eof)) lexImpl(); diff --git a/include/swift/Parse/ParsedSyntaxBuilders.h.gyb b/include/swift/Parse/ParsedSyntaxBuilders.h.gyb index 90aba5e9eb212..ac51c8ce91017 100644 --- a/include/swift/Parse/ParsedSyntaxBuilders.h.gyb +++ b/include/swift/Parse/ParsedSyntaxBuilders.h.gyb @@ -30,7 +30,7 @@ namespace swift { class ParsedRawSyntaxRecorder; class SyntaxParsingContext; -% for node in SYNTAX_NODES: +% for node in SYNTAX_NODES + PARSEONLY_NODES: % if node.is_buildable(): % child_count = len(node.children) class Parsed${node.name}Builder { diff --git a/include/swift/Parse/ParsedSyntaxNodes.h.gyb b/include/swift/Parse/ParsedSyntaxNodes.h.gyb index 5bbc07321f49d..36d3cc1dd1177 100644 --- a/include/swift/Parse/ParsedSyntaxNodes.h.gyb +++ b/include/swift/Parse/ParsedSyntaxNodes.h.gyb @@ -28,20 +28,20 @@ namespace swift { % # Emit the non-collection classes first, then emit the collection classes % # that reference these classes. -% for node in SYNTAX_NODES: +% for node in SYNTAX_NODES + PARSEONLY_NODES: % if not node.is_syntax_collection(): class Parsed${node.name}; % end % end -% for node in SYNTAX_NODES: +% for node in SYNTAX_NODES + PARSEONLY_NODES: % if node.is_syntax_collection(): using Parsed${node.name} = ParsedSyntaxCollection; % end % end -% for node in SYNTAX_NODES: +% for node in SYNTAX_NODES + PARSEONLY_NODES: % if not node.is_syntax_collection(): % qualifier = "" if node.is_base() else "final" % for line in dedented_lines(node.description): diff --git a/include/swift/Parse/ParsedSyntaxRecorder.h.gyb b/include/swift/Parse/ParsedSyntaxRecorder.h.gyb index 51b56c73aea07..713d8b9b7c949 100644 --- a/include/swift/Parse/ParsedSyntaxRecorder.h.gyb +++ b/include/swift/Parse/ParsedSyntaxRecorder.h.gyb @@ -31,7 +31,7 @@ class SyntaxParsingContext; struct ParsedSyntaxRecorder { -% for node in SYNTAX_NODES: +% for node in SYNTAX_NODES + PARSEONLY_NODES: % if node.children: % child_params = [] % for child in node.children: diff --git a/include/swift/Parse/Parser.h b/include/swift/Parse/Parser.h index 20677925f85cd..350da14a08399 100644 --- a/include/swift/Parse/Parser.h +++ b/include/swift/Parse/Parser.h @@ -695,11 +695,19 @@ class Parser { /// plain Tok.is(T1) check). bool skipUntilTokenOrEndOfLine(tok T1); + //-------------------------------------------------------------------------// + // Ignore token APIs. + // This is used when we skip gabage text in the source text. + + /// Ignore the current single token. void ignoreToken(); void ignoreToken(tok Kind) { + /// Ignore the current single token asserting its kind. assert(Tok.is(Kind)); ignoreToken(); } + /// Conditionally ignore the current single token if it matches with the \p + /// Kind. bool ignoreIf(tok Kind) { if (!Tok.is(Kind)) return false; @@ -868,7 +876,7 @@ class Parser { /// /// If the input is malformed, this emits the specified error diagnostic. bool parseToken(tok K, SourceLoc &TokLoc, const Diagnostic &D); - llvm::Optional parseTokenSyntax(tok K, + llvm::Optional parseTokenSyntax(tok K, SourceLoc &TokLoc, const Diagnostic &D); template @@ -895,7 +903,8 @@ class Parser { const Diagnostic &D); llvm::Optional - parseMatchingTokenSyntax(tok K, Diag<> ErrorDiag, SourceLoc OtherLoc); + parseMatchingTokenSyntax(tok K, SourceLoc &TokLoc, Diag<> ErrorDiag, + SourceLoc OtherLoc); /// Returns the proper location for a missing right brace, parenthesis, etc. SourceLoc getLocForMissingMatchingToken() const; @@ -1209,7 +1218,8 @@ class Parser { using TypeASTResult = ParserResult; using TypeResult = ParsedSyntaxResult; - LayoutConstraint parseLayoutConstraint(Identifier LayoutConstraintID); + ParsedSyntaxResult + parseLayoutConstraintSyntax(); TypeResult parseTypeSyntax(); TypeResult parseTypeSyntax(Diag<> MessageID, bool HandleCodeCompletion = true, @@ -1656,8 +1666,19 @@ class Parser { //===--------------------------------------------------------------------===// // Generics Parsing + ParserResult parseSILGenericParams(); + + ParserStatus parseSILGenericParamsSyntax( + Optional &result); + + ParsedSyntaxResult + parseGenericParameterClauseSyntax(); + + ParsedSyntaxResult + parseGenericWhereClauseSyntax(bool &FirstTypeInComplete, + bool AllowLayoutConstraints = false); + ParserResult parseGenericParameters(); - ParserResult parseGenericParameters(SourceLoc LAngleLoc); ParserStatus parseGenericParametersBeforeWhere(SourceLoc LAngleLoc, SmallVectorImpl &GenericParams); ParserResult maybeParseGenericParams(); diff --git a/include/swift/Reflection/Records.h b/include/swift/Reflection/Records.h index 42b671bf78831..c6f2fe7299b49 100644 --- a/include/swift/Reflection/Records.h +++ b/include/swift/Reflection/Records.h @@ -80,14 +80,12 @@ class FieldRecord { return MangledTypeName; } - StringRef getMangledTypeName(uintptr_t Offset) const { - return Demangle::makeSymbolicMangledNameStringRef( - (const char *)((uintptr_t)MangledTypeName.get() + Offset)); + StringRef getMangledTypeName() const { + return Demangle::makeSymbolicMangledNameStringRef(MangledTypeName.get()); } - StringRef getFieldName(uintptr_t Offset, uintptr_t Low, - uintptr_t High) const { - uintptr_t nameAddr = (uintptr_t)FieldName.get() + Offset; + StringRef getFieldName(uintptr_t Low, uintptr_t High) const { + uintptr_t nameAddr = (uintptr_t)FieldName.get(); if (nameAddr < Low || nameAddr > High) return ""; return (const char *)nameAddr; @@ -216,18 +214,16 @@ class FieldDescriptor { return MangledTypeName; } - StringRef getMangledTypeName(uintptr_t Offset) const { - return Demangle::makeSymbolicMangledNameStringRef( - (const char *)((uintptr_t)MangledTypeName.get() + Offset)); + StringRef getMangledTypeName() const { + return Demangle::makeSymbolicMangledNameStringRef(MangledTypeName.get()); } bool hasSuperclass() const { return Superclass; } - StringRef getSuperclass(uintptr_t Offset) const { - return Demangle::makeSymbolicMangledNameStringRef( - (const char*)((uintptr_t)Superclass.get() + Offset)); + StringRef getSuperclass() const { + return Demangle::makeSymbolicMangledNameStringRef(Superclass.get()); } }; @@ -271,13 +267,13 @@ class AssociatedTypeRecord { const RelativeDirectPointer SubstitutedTypeName; public: - StringRef getName(uintptr_t Offset) const { - return (const char*)((uintptr_t)Name.get() + Offset); + StringRef getName() const { + return Name.get(); } - StringRef getMangledSubstitutedTypeName(uintptr_t Offset) const { + StringRef getMangledSubstitutedTypeName() const { return Demangle::makeSymbolicMangledNameStringRef( - (const char*)((uintptr_t)SubstitutedTypeName.get() + Offset)); + SubstitutedTypeName.get()); } }; @@ -352,14 +348,12 @@ struct AssociatedTypeDescriptor { return const_iterator { End, End }; } - StringRef getMangledProtocolTypeName(uintptr_t Offset) const { - return Demangle::makeSymbolicMangledNameStringRef( - (const char*)((uintptr_t)ProtocolTypeName.get() + Offset)); + StringRef getMangledProtocolTypeName() const { + return Demangle::makeSymbolicMangledNameStringRef(ProtocolTypeName.get()); } - StringRef getMangledConformingTypeName(uintptr_t Offset) const { - return Demangle::makeSymbolicMangledNameStringRef( - (const char*)((uintptr_t)ConformingTypeName.get() + Offset)); + StringRef getMangledConformingTypeName() const { + return Demangle::makeSymbolicMangledNameStringRef(ConformingTypeName.get()); } }; @@ -425,9 +419,8 @@ class BuiltinTypeDescriptor { return TypeName; } - StringRef getMangledTypeName(uintptr_t Offset) const { - return Demangle::makeSymbolicMangledNameStringRef( - (const char*)((uintptr_t)TypeName.get() + Offset)); + StringRef getMangledTypeName() const { + return Demangle::makeSymbolicMangledNameStringRef(TypeName.get()); } }; @@ -473,9 +466,8 @@ class CaptureTypeRecord { return MangledTypeName; } - StringRef getMangledTypeName(uintptr_t Offset) const { - return Demangle::makeSymbolicMangledNameStringRef( - (const char*)((uintptr_t)MangledTypeName.get() + Offset)); + StringRef getMangledTypeName() const { + return Demangle::makeSymbolicMangledNameStringRef(MangledTypeName.get()); } }; @@ -520,18 +512,17 @@ class MetadataSourceRecord { return MangledTypeName; } - StringRef getMangledTypeName(uintptr_t Offset) const { - return Demangle::makeSymbolicMangledNameStringRef( - (const char*)((uintptr_t)MangledTypeName.get() + Offset)); + StringRef getMangledTypeName() const { + return Demangle::makeSymbolicMangledNameStringRef(MangledTypeName.get()); } bool hasMangledMetadataSource() const { return MangledMetadataSource; } - StringRef getMangledMetadataSource(uintptr_t Offset) const { + StringRef getMangledMetadataSource() const { return Demangle::makeSymbolicMangledNameStringRef( - (const char*)((uintptr_t)MangledMetadataSource.get() + Offset)); + MangledMetadataSource.get()); } }; diff --git a/include/swift/Reflection/ReflectionContext.h b/include/swift/Reflection/ReflectionContext.h index 9ea52b185dac9..be51f67928b81 100644 --- a/include/swift/Reflection/ReflectionContext.h +++ b/include/swift/Reflection/ReflectionContext.h @@ -123,7 +123,6 @@ class ReflectionContext return sizeof(StoredPointer) * 2; } -#if defined(__APPLE__) && defined(__MACH__) template bool readMachOSections(RemoteAddress ImageStart) { auto Buf = this->getReader().readBytes(ImageStart, sizeof(typename T::Header)); @@ -242,12 +241,12 @@ class ReflectionContext auto RemoteStartAddress = static_cast(RangeStart); ReflectionInfo info = { - {{FieldMdSec.first, FieldMdSec.second}, 0}, - {{AssocTySec.first, AssocTySec.second}, 0}, - {{BuiltinTySec.first, BuiltinTySec.second}, 0}, - {{CaptureSec.first, CaptureSec.second}, 0}, - {{TypeRefMdSec.first, TypeRefMdSec.second}, 0}, - {{ReflStrMdSec.first, ReflStrMdSec.second}, 0}, + {FieldMdSec.first, FieldMdSec.second}, + {AssocTySec.first, AssocTySec.second}, + {BuiltinTySec.first, BuiltinTySec.second}, + {CaptureSec.first, CaptureSec.second}, + {TypeRefMdSec.first, TypeRefMdSec.second}, + {ReflStrMdSec.first, ReflStrMdSec.second}, LocalStartAddress, RemoteStartAddress}; @@ -277,22 +276,6 @@ class ReflectionContext return true; } - bool addImage(RemoteAddress ImageStart) { - // We start reading 4 bytes. The first 4 bytes are supposed to be - // the magic, so we understand whether this is a 32-bit executable or - // a 64-bit one. - auto Buf = this->getReader().readBytes(ImageStart, sizeof(uint32_t)); - if (!Buf) - return false; - auto HeaderMagic = reinterpret_cast(Buf.get()); - if (*HeaderMagic == llvm::MachO::MH_MAGIC) - return readMachOSections>(ImageStart); - if (*HeaderMagic == llvm::MachO::MH_MAGIC_64) - return readMachOSections>(ImageStart); - return false; - } - -#elif defined(_WIN32) bool readPECOFFSections(RemoteAddress ImageStart) { auto DOSHdrBuf = this->getReader().readBytes( ImageStart, sizeof(llvm::object::dos_header)); @@ -372,27 +355,25 @@ class ReflectionContext static_cast(ImageStart.getAddressData()); ReflectionInfo Info = { - {{FieldMdSec.first, FieldMdSec.second}, 0}, - {{AssocTySec.first, AssocTySec.second}, 0}, - {{BuiltinTySec.first, BuiltinTySec.second}, 0}, - {{CaptureSec.first, CaptureSec.second}, 0}, - {{TypeRefMdSec.first, TypeRefMdSec.second}, 0}, - {{ReflStrMdSec.first, ReflStrMdSec.second}, 0}, + {FieldMdSec.first, FieldMdSec.second}, + {AssocTySec.first, AssocTySec.second}, + {BuiltinTySec.first, BuiltinTySec.second}, + {CaptureSec.first, CaptureSec.second}, + {TypeRefMdSec.first, TypeRefMdSec.second}, + {ReflStrMdSec.first, ReflStrMdSec.second}, LocalStartAddress, RemoteStartAddress}; this->addReflectionInfo(Info); return true; } - bool addImage(RemoteAddress ImageStart) { + bool readPECOFF(RemoteAddress ImageStart) { auto Buf = this->getReader().readBytes(ImageStart, sizeof(llvm::object::dos_header)); if (!Buf) return false; auto DOSHdr = reinterpret_cast(Buf.get()); - if (!(DOSHdr->Magic[0] == 'M' && DOSHdr->Magic[1] == 'Z')) - return false; auto PEHeaderAddress = ImageStart.getAddressData() + DOSHdr->AddressOfNewExeHeader; @@ -407,7 +388,7 @@ class ReflectionContext return readPECOFFSections(ImageStart); } -#else // ELF platforms. + template bool readELFSections(RemoteAddress ImageStart) { auto Buf = this->getReader().readBytes(ImageStart, sizeof(typename T::Header)); @@ -492,12 +473,12 @@ class ReflectionContext static_cast(ImageStart.getAddressData()); ReflectionInfo info = { - {{FieldMdSec.first, FieldMdSec.second}, 0}, - {{AssocTySec.first, AssocTySec.second}, 0}, - {{BuiltinTySec.first, BuiltinTySec.second}, 0}, - {{CaptureSec.first, CaptureSec.second}, 0}, - {{TypeRefMdSec.first, TypeRefMdSec.second}, 0}, - {{ReflStrMdSec.first, ReflStrMdSec.second}, 0}, + {FieldMdSec.first, FieldMdSec.second}, + {AssocTySec.first, AssocTySec.second}, + {BuiltinTySec.first, BuiltinTySec.second}, + {CaptureSec.first, CaptureSec.second}, + {TypeRefMdSec.first, TypeRefMdSec.second}, + {ReflStrMdSec.first, ReflStrMdSec.second}, LocalStartAddress, RemoteStartAddress}; @@ -506,8 +487,8 @@ class ReflectionContext savedBuffers.push_back(std::move(Buf)); return true; } - - bool addImage(RemoteAddress ImageStart) { + + bool readELF(RemoteAddress ImageStart) { auto Buf = this->getReader().readBytes(ImageStart, sizeof(llvm::ELF::Elf64_Ehdr)); @@ -527,12 +508,48 @@ class ReflectionContext return false; } } -#endif + + bool addImage(RemoteAddress ImageStart) { + // Read the first few bytes to look for a magic header. + auto Magic = this->getReader().readBytes(ImageStart, sizeof(uint32_t)); + if (!Magic) + return false; + + uint32_t MagicWord; + memcpy(&MagicWord, Magic.get(), sizeof(MagicWord)); + + // 32- and 64-bit Mach-O. + if (MagicWord == llvm::MachO::MH_MAGIC) { + return readMachOSections>(ImageStart); + } + + if (MagicWord == llvm::MachO::MH_MAGIC_64) { + return readMachOSections>(ImageStart); + } + + // PE. (This just checks for the DOS header; `readPECOFF` will further + // validate the existence of the PE header.) + auto MagicBytes = (const char*)Magic.get(); + if (MagicBytes[0] == 'M' && MagicBytes[1] == 'Z') { + return readPECOFF(ImageStart); + } + + // ELF. + if (MagicBytes[0] == llvm::ELF::ElfMagic[0] + && MagicBytes[1] == llvm::ELF::ElfMagic[1] + && MagicBytes[2] == llvm::ELF::ElfMagic[2] + && MagicBytes[3] == llvm::ELF::ElfMagic[3]) { + return readELF(ImageStart); + } + + // We don't recognize the format. + return false; + } void addReflectionInfo(ReflectionInfo I) { getBuilder().addReflectionInfo(I); } - + bool ownsObject(RemoteAddress ObjectAddress) { auto MetadataAddress = readMetadataFromInstance(ObjectAddress.getAddressData()); if (!MetadataAddress) @@ -621,7 +638,7 @@ class ReflectionContext if (CD == nullptr) return nullptr; - auto Info = getBuilder().getClosureContextInfo(*CD, 0); + auto Info = getBuilder().getClosureContextInfo(*CD); return getClosureContextInfo(ObjectAddress, Info); } diff --git a/include/swift/Reflection/TypeRefBuilder.h b/include/swift/Reflection/TypeRefBuilder.h index 7b8d3d828127c..083946331540f 100644 --- a/include/swift/Reflection/TypeRefBuilder.h +++ b/include/swift/Reflection/TypeRefBuilder.h @@ -80,35 +80,12 @@ using CaptureSection = ReflectionSection; using GenericSection = ReflectionSection; struct ReflectionInfo { - struct { - FieldSection Metadata; - uint64_t SectionOffset; - } Field; - - struct { - AssociatedTypeSection Metadata; - uint64_t SectionOffset; - } AssociatedType; - - struct { - BuiltinTypeSection Metadata; - uint64_t SectionOffset; - } Builtin; - - struct { - CaptureSection Metadata; - uint64_t SectionOffset; - } Capture; - - struct { - GenericSection Metadata; - uint64_t SectionOffset; - } TypeReference; - - struct { - GenericSection Metadata; - uint64_t SectionOffset; - } ReflectionString; + FieldSection Field; + AssociatedTypeSection AssociatedType; + BuiltinTypeSection Builtin; + CaptureSection Capture; + GenericSection TypeReference; + GenericSection ReflectionString; uint64_t LocalStartAddress; uint64_t RemoteStartAddress; @@ -531,8 +508,8 @@ class TypeRefBuilder { // underlying type if available. if (context->getKind() == ContextDescriptorKind::OpaqueType) { return Dem.createNode( - Node::Kind::OpaqueTypeDescriptorSymbolicReference, - (uintptr_t)context.getAddress()); + Node::Kind::OpaqueTypeDescriptorSymbolicReference, + context.getAddressData()); } return reader.buildContextMangling(context, Dem); @@ -580,8 +557,7 @@ class TypeRefBuilder { const CaptureDescriptor *getCaptureDescriptor(uint64_t RemoteAddress); /// Get the unsubstituted capture types for a closure context. - ClosureContextInfo getClosureContextInfo(const CaptureDescriptor &CD, - uint64_t Offset); + ClosureContextInfo getClosureContextInfo(const CaptureDescriptor &CD); /// /// Dumping typerefs, field declarations, associated types diff --git a/include/swift/Remote/MetadataReader.h b/include/swift/Remote/MetadataReader.h index 95a9bf0d1d9da..beaeb8dfded43 100644 --- a/include/swift/Remote/MetadataReader.h +++ b/include/swift/Remote/MetadataReader.h @@ -43,13 +43,10 @@ using TypeDecoder = swift::Demangle::TypeDecoder; /// A pointer to the local buffer of an object that also remembers the /// address at which it was stored remotely. -template +template class RemoteRef { -public: - using StoredPointer = typename Runtime::StoredPointer; - private: - StoredPointer Address; + uint64_t Address; const T *LocalBuffer; public: @@ -57,13 +54,14 @@ class RemoteRef { RemoteRef(std::nullptr_t _) : Address(0), LocalBuffer(nullptr) {} + template explicit RemoteRef(StoredPointer address, const T *localBuffer) - : Address(address), LocalBuffer(localBuffer) {} + : Address((uint64_t)address), LocalBuffer(localBuffer) {} - StoredPointer getAddress() const { + uint64_t getAddressData() const { return Address; } - + const T *getLocalBuffer() const { return LocalBuffer; } @@ -76,6 +74,36 @@ class RemoteRef { assert(LocalBuffer); return LocalBuffer; } + + bool operator==(RemoteRef other) const { + return Address == other.Address; + } + + bool operator!=(RemoteRef other) const { + return !operator==(other); + } + + /// Project a reference for a field. The field must be projected from the same + /// LocalBuffer pointer as this RemoteRef. + template + RemoteRef getField(U &field) const { + auto offset = (intptr_t)&field - (intptr_t)LocalBuffer; + return RemoteRef((uint64_t)(Address + (int64_t)offset), &field); + } + + /// Resolve the remote address of a relative offset stored at the remote address. + uint64_t resolveRelativeAddressData() const { + int32_t offset; + memcpy(&offset, LocalBuffer, sizeof(int32_t)); + if (offset == 0) + return 0; + return Address + (int64_t)offset; + } + + template + uint64_t resolveRelativeFieldData(U &field) const { + return getField(field).resolveRelativeAddressData(); + } }; /// A structure, designed for use with std::unique_ptr, which destroys @@ -127,8 +155,7 @@ class MetadataReader { /// A cache of built types, keyed by the address of the type. std::unordered_map TypeCache; - using MetadataRef = - RemoteRef>; + using MetadataRef = RemoteRef>; using OwnedMetadataRef = std::unique_ptr, delete_with_free>; @@ -136,8 +163,7 @@ class MetadataReader { std::unordered_map MetadataCache; - using ContextDescriptorRef = - RemoteRef>; + using ContextDescriptorRef = RemoteRef>; using OwnedContextDescriptorRef = std::unique_ptr, delete_with_free>; @@ -1068,14 +1094,13 @@ class MetadataReader { return ClassMetadataBounds::forSwiftRootClass(); auto rawSuperclass = - resolveNullableRelativeField(subclassRef, - subclass->getResilientSuperclass()); + resolveRelativeField(subclassRef, subclass->getResilientSuperclass()); if (!rawSuperclass) { return ClassMetadataBounds::forSwiftRootClass(); } return forTypeReference( - subclass->getResilientSuperclassReferenceKind(), *rawSuperclass, + subclass->getResilientSuperclassReferenceKind(), rawSuperclass, [&](ContextDescriptorRef superclass) -> Optional { if (!isa>(superclass)) @@ -1166,7 +1191,7 @@ class MetadataReader { return None; auto addressOfGenericArgAddress = - (Meta.getAddress() + + (getAddress(Meta) + *offsetToGenericArgs * sizeof(StoredPointer) + index * sizeof(StoredPointer)); @@ -1237,31 +1262,6 @@ class MetadataReader { } protected: - template - StoredPointer resolveRelativeOffset(StoredPointer targetAddress) { - Offset relative; - if (!Reader->readInteger(RemoteAddress(targetAddress), &relative)) - return 0; - using SignedOffset = typename std::make_signed::type; - using SignedPointer = typename std::make_signed::type; - auto signext = (SignedPointer)(SignedOffset)relative; - return targetAddress + signext; - } - - template - Optional - resolveNullableRelativeOffset(StoredPointer targetAddress) { - Offset relative; - if (!Reader->readInteger(RemoteAddress(targetAddress), &relative)) - return None; - if (relative == 0) - return 0; - using SignedOffset = typename std::make_signed::type; - using SignedPointer = typename std::make_signed::type; - auto signext = (SignedPointer)(SignedOffset)relative; - return targetAddress + signext; - } - template Optional resolveNullableRelativeIndirectableOffset(StoredPointer targetAddress) { @@ -1290,31 +1290,44 @@ class MetadataReader { return resultAddress; } - template - StoredPointer resolveRelativeField( - RemoteRef base, const Field &field) { - // Map the offset from within our local buffer to the remote address. - auto distance = (intptr_t)&field - (intptr_t)base.getLocalBuffer(); - return resolveRelativeOffset(base.getAddress() + distance); + template + StoredPointer getAddress(RemoteRef base) { + return (StoredPointer)base.getAddressData(); } template - Optional resolveNullableRelativeField( - RemoteRef base, const Field &field) { - // Map the offset from within our local buffer to the remote address. - auto distance = (intptr_t)&field - (intptr_t)base.getLocalBuffer(); - - return resolveNullableRelativeOffset(base.getAddress() + distance); + StoredPointer resolveRelativeField( + RemoteRef base, const Field &field) { + return (StoredPointer)base.resolveRelativeFieldData(field); } - + template - Optional resolveNullableRelativeIndirectableField( - RemoteRef base, const Field &field) { - // Map the offset from within our local buffer to the remote address. - auto distance = (intptr_t)&field - (intptr_t)base.getLocalBuffer(); + Optional resolveRelativeIndirectableField( + RemoteRef base, const Field &field) { + auto fieldRef = base.getField(field); + int32_t offset; + memcpy(&offset, fieldRef.getLocalBuffer(), sizeof(int32_t)); - return resolveNullableRelativeIndirectableOffset( - base.getAddress() + distance); + if (offset == 0) + return 0; + bool indirect = offset & 1; + offset &= ~1u; + + using SignedPointer = typename std::make_signed::type; + + StoredPointer resultAddress = getAddress(fieldRef) + (SignedPointer)offset; + + // Low bit set in the offset indicates that the offset leads to the absolute + // address in memory. + if (indirect) { + if (!Reader->readBytes(RemoteAddress(resultAddress), + (uint8_t *)&resultAddress, + sizeof(StoredPointer))) { + return None; + } + } + + return resultAddress; } /// Given a pointer to an Objective-C class, try to read its class name. @@ -1521,8 +1534,7 @@ class MetadataReader { /// Returns None if there was an error reading the parent descriptor. Optional readParentContextDescriptor(ContextDescriptorRef base) { - auto parentAddress = - resolveNullableRelativeIndirectableField(base, base->Parent); + auto parentAddress = resolveRelativeIndirectableField(base, base->Parent); if (!parentAddress) return None; if (!*parentAddress) @@ -1838,7 +1850,7 @@ class MetadataReader { const RelativeTargetProtocolDescriptorPointer &protocol) { // Map the offset from within our local buffer to the remote address. auto distance = (intptr_t)&protocol - (intptr_t)descriptor.getLocalBuffer(); - StoredPointer targetAddress(descriptor.getAddress() + distance); + StoredPointer targetAddress(getAddress(descriptor) + distance); // Read the relative offset. int32_t relative; @@ -2071,7 +2083,7 @@ class MetadataReader { // address. auto distance = (intptr_t)&req.Layout - (intptr_t)descriptor.getLocalBuffer(); - StoredPointer targetAddress(descriptor.getAddress() + distance); + StoredPointer targetAddress(getAddress(descriptor) + distance); GenericRequirementLayoutKind kind; if (!Reader->readBytes(RemoteAddress(targetAddress), @@ -2106,7 +2118,7 @@ class MetadataReader { // Use the remote address to identify the anonymous context. char addressBuf[18]; snprintf(addressBuf, sizeof(addressBuf), "$%" PRIx64, - (uint64_t)descriptor.getAddress()); + (uint64_t)descriptor.getAddressData()); auto anonNode = dem.createNode(Node::Kind::AnonymousContext); CharVector addressStr; addressStr.append(addressBuf, dem); @@ -2269,7 +2281,7 @@ class MetadataReader { if (!offsetToGenericArgs) return {}; - auto genericArgsAddr = metadata.getAddress() + auto genericArgsAddr = getAddress(metadata) + sizeof(StoredPointer) * *offsetToGenericArgs; std::vector builtSubsts; @@ -2326,9 +2338,8 @@ class MetadataReader { // If we've skipped an artificial subclasses, check the cache at // the superclass. (This also protects against recursion.) - if (skipArtificialSubclasses && - metadata.getAddress() != origMetadata.getAddress()) { - auto it = TypeCache.find(metadata.getAddress()); + if (skipArtificialSubclasses && metadata != origMetadata) { + auto it = TypeCache.find(getAddress(metadata)); if (it != TypeCache.end()) return it->second; } @@ -2358,13 +2369,12 @@ class MetadataReader { if (!nominal) return BuiltType(); - TypeCache[metadata.getAddress()] = nominal; + TypeCache[getAddress(metadata)] = nominal; // If we've skipped an artificial subclass, remove the // recursion-protection entry we made for it. - if (skipArtificialSubclasses && - metadata.getAddress() != origMetadata.getAddress()) { - TypeCache.erase(origMetadata.getAddress()); + if (skipArtificialSubclasses && metadata != origMetadata) { + TypeCache.erase(getAddress(origMetadata)); } return nominal; @@ -2377,7 +2387,8 @@ class MetadataReader { return readNominalTypeFromMetadata(origMetadata, skipArtificialSubclasses); std::string className; - if (!readObjCClassName(origMetadata.getAddress(), className)) + auto origMetadataPtr = getAddress(origMetadata); + if (!readObjCClassName(origMetadataPtr, className)) return BuiltType(); BuiltType BuiltObjCClass = Builder.createObjCClassType(std::move(className)); @@ -2390,7 +2401,7 @@ class MetadataReader { skipArtificialSubclasses); } - TypeCache[origMetadata.getAddress()] = BuiltObjCClass; + TypeCache[origMetadataPtr] = BuiltObjCClass; return BuiltObjCClass; } @@ -2583,11 +2594,11 @@ class MetadataReader { } // end namespace swift namespace llvm { - template - struct simplify_type> { + template + struct simplify_type> { using SimpleType = const T *; static SimpleType - getSimplifiedValue(swift::remote::RemoteRef value) { + getSimplifiedValue(swift::remote::RemoteRef value) { return value.getLocalBuffer(); } }; diff --git a/include/swift/SIL/ApplySite.h b/include/swift/SIL/ApplySite.h index e13069f481cb1..b441a2af2c2fb 100644 --- a/include/swift/SIL/ApplySite.h +++ b/include/swift/SIL/ApplySite.h @@ -130,8 +130,13 @@ class ApplySite { llvm_unreachable("covered switch"); \ } while (0) + /// Return the callee operand as a value. + SILValue getCallee() const { return getCalleeOperand()->get(); } + /// Return the callee operand. - SILValue getCallee() const { FOREACH_IMPL_RETURN(getCallee()); } + const Operand *getCalleeOperand() const { + FOREACH_IMPL_RETURN(getCalleeOperand()); + } /// Return the callee value by looking through function conversions until we /// find a function_ref, partial_apply, or unrecognized callee value. diff --git a/include/swift/SIL/BranchPropagatedUser.h b/include/swift/SIL/BranchPropagatedUser.h index c726693200620..5e00ebf4ab9b5 100644 --- a/include/swift/SIL/BranchPropagatedUser.h +++ b/include/swift/SIL/BranchPropagatedUser.h @@ -13,6 +13,7 @@ #ifndef SWIFT_SIL_BRANCHPROPAGATEDUSER_H #define SWIFT_SIL_BRANCHPROPAGATEDUSER_H +#include "swift/Basic/LLVM.h" #include "swift/SIL/SILBasicBlock.h" #include "swift/SIL/SILInstruction.h" #include "llvm/ADT/DenseMap.h" @@ -27,74 +28,98 @@ namespace swift { /// BranchPropagatedUser and friends break all such critical edges. class BranchPropagatedUser { using InnerTy = llvm::PointerIntPair; - InnerTy User; + InnerTy user; public: - BranchPropagatedUser(SILInstruction *I) : User(I) { - assert(!isa(I)); - } - - BranchPropagatedUser(CondBranchInst *I) : User(I) {} - - BranchPropagatedUser(CondBranchInst *I, unsigned SuccessorIndex) - : User(I, SuccessorIndex) { - assert(SuccessorIndex == CondBranchInst::TrueIdx || - SuccessorIndex == CondBranchInst::FalseIdx); + BranchPropagatedUser(Operand *op) : user() { + auto *opUser = op->getUser(); + auto *cbi = dyn_cast(opUser); + if (!cbi) { + user = InnerTy(opUser, 0); + return; + } + unsigned operandIndex = op->getOperandNumber(); + if (cbi->isConditionOperandIndex(operandIndex)) { + // TODO: Is this correct? + user = InnerTy(cbi, CondBranchInst::TrueIdx); + return; + } + bool isTrueOperand = cbi->isTrueOperandIndex(operandIndex); + if (isTrueOperand) { + user = InnerTy(cbi, CondBranchInst::TrueIdx); + } else { + user = InnerTy(cbi, CondBranchInst::FalseIdx); + } } + BranchPropagatedUser(const Operand *op) + : BranchPropagatedUser(const_cast(op)) {} - BranchPropagatedUser(const BranchPropagatedUser &Other) : User(Other.User) {} - BranchPropagatedUser &operator=(const BranchPropagatedUser &Other) { - User = Other.User; + BranchPropagatedUser(const BranchPropagatedUser &other) : user(other.user) {} + BranchPropagatedUser &operator=(const BranchPropagatedUser &other) { + user = other.user; return *this; } - operator SILInstruction *() { return User.getPointer(); } - operator const SILInstruction *() const { return User.getPointer(); } + operator SILInstruction *() { return user.getPointer(); } + operator const SILInstruction *() const { return user.getPointer(); } - SILInstruction *getInst() const { return User.getPointer(); } + SILInstruction *getInst() const { return user.getPointer(); } SILBasicBlock *getParent() const { if (!isCondBranchUser()) { return getInst()->getParent(); } - auto *CBI = cast(getInst()); - unsigned Number = getCondBranchSuccessorID(); - if (Number == CondBranchInst::TrueIdx) - return CBI->getTrueBB(); - return CBI->getFalseBB(); + auto *cbi = cast(getInst()); + unsigned number = getCondBranchSuccessorID(); + if (number == CondBranchInst::TrueIdx) + return cbi->getTrueBB(); + return cbi->getFalseBB(); } bool isCondBranchUser() const { - return isa(User.getPointer()); + return isa(user.getPointer()); } unsigned getCondBranchSuccessorID() const { assert(isCondBranchUser()); - return User.getInt(); + return user.getInt(); } SILBasicBlock::iterator getIterator() const { - return User.getPointer()->getIterator(); + return user.getPointer()->getIterator(); } void *getAsOpaqueValue() const { - return llvm::PointerLikeTypeTraits::getAsVoidPointer(User); + return llvm::PointerLikeTypeTraits::getAsVoidPointer(user); } static BranchPropagatedUser getFromOpaqueValue(void *p) { - InnerTy TmpUser = + InnerTy tmpUser = llvm::PointerLikeTypeTraits::getFromVoidPointer(p); - if (auto *CBI = dyn_cast(TmpUser.getPointer())) { - return BranchPropagatedUser(CBI, TmpUser.getInt()); + if (auto *cbi = dyn_cast(tmpUser.getPointer())) { + return BranchPropagatedUser(cbi, tmpUser.getInt()); } - return BranchPropagatedUser(TmpUser.getPointer()); + return BranchPropagatedUser(tmpUser.getPointer()); } enum { NumLowBitsAvailable = llvm::PointerLikeTypeTraits::NumLowBitsAvailable }; + +private: + BranchPropagatedUser(SILInstruction *inst) : user(inst) { + assert(!isa(inst)); + } + + BranchPropagatedUser(CondBranchInst *cbi) : user(cbi) {} + + BranchPropagatedUser(CondBranchInst *cbi, unsigned successorIndex) + : user(cbi, successorIndex) { + assert(successorIndex == CondBranchInst::TrueIdx || + successorIndex == CondBranchInst::FalseIdx); + } }; } // namespace swift diff --git a/include/swift/SIL/InstructionUtils.h b/include/swift/SIL/InstructionUtils.h index affe24e8ac957..100b79c663175 100644 --- a/include/swift/SIL/InstructionUtils.h +++ b/include/swift/SIL/InstructionUtils.h @@ -142,6 +142,49 @@ bool onlyUsedByAssignByWrapper(PartialApplyInst *PAI); void findClosuresForFunctionValue(SILValue V, TinyPtrVector &results); +/// Given a polymorphic builtin \p bi that may be generic and thus have in/out +/// params, stash all of the information needed for either specializing while +/// inlining or propagating the type in constant propagation. +/// +/// NOTE: If we perform this transformation, our builtin will no longer have any +/// substitutions since we only substitute to concrete static overloads. +struct PolymorphicBuiltinSpecializedOverloadInfo { + const BuiltinInfo *builtinInfo; + Identifier staticOverloadIdentifier; + SmallVector argTypes; + SILType resultType; + bool hasOutParam; + +private: + bool isInitialized; + +public: + PolymorphicBuiltinSpecializedOverloadInfo() + : builtinInfo(nullptr), staticOverloadIdentifier(), argTypes(), + resultType(), hasOutParam(false), isInitialized(false) {} + + /// Returns true if we were able to map the polymorphic builtin to a static + /// overload. False otherwise. + /// + /// NOTE: This does not mean that the static overload actually exists. + bool init(BuiltinInst *bi); + + bool doesOverloadExist() const { + CanBuiltinType builtinType = argTypes.front().getAs(); + return canBuiltinBeOverloadedForType(builtinInfo->ID, builtinType); + } + +private: + bool init(SILFunction *fn, BuiltinValueKind builtinKind, + ArrayRef oldOperandTypes, SILType oldResultType); +}; + +/// Given a polymorphic builtin \p bi, analyze its types and create a builtin +/// for the static overload that the builtin corresponds to. If \p bi is not a +/// polymorphic builtin or does not have any available overload for these types, +/// return SILValue(). +SILValue getStaticOverloadForSpecializedPolymorphicBuiltin(BuiltinInst *bi); + } // end namespace swift #endif diff --git a/include/swift/SIL/OwnershipUtils.h b/include/swift/SIL/OwnershipUtils.h index 4d8a8ec66cd19..cb778bf52bd58 100644 --- a/include/swift/SIL/OwnershipUtils.h +++ b/include/swift/SIL/OwnershipUtils.h @@ -14,6 +14,7 @@ #define SWIFT_SIL_OWNERSHIPUTILS_H #include "swift/Basic/LLVM.h" +#include "swift/SIL/BranchPropagatedUser.h" #include "swift/SIL/SILArgument.h" #include "swift/SIL/SILInstruction.h" #include "swift/SIL/SILValue.h" @@ -126,27 +127,62 @@ class LinearLifetimeError { } }; -/// Returns true if: +/// A class used to validate linear lifetime with respect to an SSA-like +/// definition. /// -/// 1. No consuming uses are reachable from any other consuming use, from any -/// non-consuming uses, or from the producer instruction. -/// 2. The consuming use set jointly post dominates producers and all non -/// consuming uses. +/// This class is able to both validate that a linear lifetime has been properly +/// constructed (for verification and safety purposes) as well as return to the +/// caller upon failure, what the failure was. In certain cases (for instance if +/// there exists a path without a non-consuming use), the class will report back +/// the specific insertion points needed to insert these compensating releases. /// -/// \p value The value whose lifetime we are checking. -/// \p consumingUses the array of users that destroy or consume a value. -/// \p nonConsumingUses regular uses -/// \p deadEndBlocks a cache for the dead end block computation -/// \p errorBehavior If we detect an error, should we return false or hard -/// error. -/// \p leakingBlocks If non-null a list of blocks where the value was detected -/// to leak. Can be used to insert missing destroys. -LinearLifetimeError valueHasLinearLifetime( - SILValue value, ArrayRef consumingUses, - ArrayRef nonConsumingUses, - SmallPtrSetImpl &visitedBlocks, - DeadEndBlocks &deadEndBlocks, ownership::ErrorBehaviorKind errorBehavior, - SmallVectorImpl *leakingBlocks = nullptr); +/// DISCUSSION: A linear lifetime consists of a starting block or instruction +/// and a list of non-consuming uses and a set of consuming uses. The consuming +/// uses must not be reachable from each other and jointly post-dominate all +/// consuming uses as well as the defining block/instruction. +class LinearLifetimeChecker { + SmallPtrSetImpl &visitedBlocks; + DeadEndBlocks &deadEndBlocks; + +public: + LinearLifetimeChecker(SmallPtrSetImpl &visitedBlocks, + DeadEndBlocks &deadEndBlocks) + : visitedBlocks(visitedBlocks), deadEndBlocks(deadEndBlocks) {} + + /// Returns true if: + /// + /// 1. No consuming uses are reachable from any other consuming use, from any + /// non-consuming uses, or from the producer instruction. + /// 2. The consuming use set jointly post dominates producers and all non + /// consuming uses. + /// + /// Returns false otherwise. + /// + /// \p value The value whose lifetime we are checking. + /// \p consumingUses the array of users that destroy or consume a value. + /// \p nonConsumingUses regular uses + /// \p errorBehavior If we detect an error, should we return false or hard + /// error. + /// \p leakingBlocks If non-null a list of blocks where the value was detected + /// to leak. Can be used to insert missing destroys. + LinearLifetimeError + checkValue(SILValue value, ArrayRef consumingUses, + ArrayRef nonConsumingUses, + ownership::ErrorBehaviorKind errorBehavior, + SmallVectorImpl *leakingBlocks = nullptr); + + /// Returns true that \p value forms a linear lifetime with consuming uses \p + /// consumingUses, non consuming uses \p nonConsumingUses. Returns false + /// otherwise. + bool validateLifetime(SILValue value, + ArrayRef consumingUses, + ArrayRef nonConsumingUses) { + return !checkValue(value, consumingUses, nonConsumingUses, + ownership::ErrorBehaviorKind::ReturnFalse, + nullptr /*leakingBlocks*/) + .getFoundError(); + } +}; /// Returns true if v is an address or trivial. bool isValueAddressOrTrivial(SILValue v); @@ -164,10 +200,151 @@ bool isOwnershipForwardingInst(SILInstruction *i); bool isGuaranteedForwardingInst(SILInstruction *i); +struct BorrowScopeIntroducerKind { + using UnderlyingKindTy = std::underlying_type::type; + + /// Enum we use for exhaustive pattern matching over borrow scope introducers. + enum Kind : UnderlyingKindTy { + LoadBorrow = UnderlyingKindTy(ValueKind::LoadBorrowInst), + BeginBorrow = UnderlyingKindTy(ValueKind::BeginBorrowInst), + SILFunctionArgument = UnderlyingKindTy(ValueKind::SILFunctionArgument), + }; + + static Optional get(ValueKind kind) { + switch (kind) { + default: + return None; + case ValueKind::LoadBorrowInst: + return BorrowScopeIntroducerKind(LoadBorrow); + case ValueKind::BeginBorrowInst: + return BorrowScopeIntroducerKind(BeginBorrow); + case ValueKind::SILFunctionArgument: + return BorrowScopeIntroducerKind(SILFunctionArgument); + } + } + + Kind value; + + BorrowScopeIntroducerKind(Kind newValue) : value(newValue) {} + BorrowScopeIntroducerKind(const BorrowScopeIntroducerKind &other) + : value(other.value) {} + operator Kind() const { return value; } + + /// Is this a borrow scope that begins and ends within the same function and + /// thus is guaranteed to have an "end_scope" instruction. + /// + /// In contrast, borrow scopes that are non-local (e.x. from + /// SILFunctionArguments) rely a construct like a SILFunction as the begin/end + /// of the scope. + bool isLocalScope() const { + switch (value) { + case BorrowScopeIntroducerKind::BeginBorrow: + case BorrowScopeIntroducerKind::LoadBorrow: + return true; + case BorrowScopeIntroducerKind::SILFunctionArgument: + return false; + } + llvm_unreachable("Covered switch isnt covered?!"); + } + + void print(llvm::raw_ostream &os) const; + LLVM_ATTRIBUTE_DEPRECATED(void dump() const, "only for use in the debugger"); +}; + +llvm::raw_ostream &operator<<(llvm::raw_ostream &os, + BorrowScopeIntroducerKind kind); + +/// A higher level construct for working with values that represent the +/// introduction of a new borrow scope. +/// +/// DISCUSSION: A "borrow introducer" is a SILValue that represents the +/// beginning of a borrow scope that the ownership verifier validates. The idea +/// is this API allows one to work in a generic way with all of the various +/// introducers. +/// +/// Some examples of borrow introducers: guaranteed SILFunctionArgument, +/// LoadBorrow, BeginBorrow, guaranteed BeginApply results. +/// +/// NOTE: It is assumed that if a borrow introducer is a value of a +/// SILInstruction with multiple results, that the all of the SILInstruction's +/// guaranteed results are borrow introducers. In practice this means that +/// borrow introducers can not have guaranteed results that are not creating a +/// new borrow scope. No such instructions exist today. +struct BorrowScopeIntroducingValue { + BorrowScopeIntroducerKind kind; + SILValue value; + + BorrowScopeIntroducingValue(LoadBorrowInst *lbi) + : kind(BorrowScopeIntroducerKind::LoadBorrow), value(lbi) {} + BorrowScopeIntroducingValue(BeginBorrowInst *bbi) + : kind(BorrowScopeIntroducerKind::BeginBorrow), value(bbi) {} + BorrowScopeIntroducingValue(SILFunctionArgument *arg) + : kind(BorrowScopeIntroducerKind::SILFunctionArgument), value(arg) { + assert(arg->getOwnershipKind() == ValueOwnershipKind::Guaranteed); + } + + BorrowScopeIntroducingValue(SILValue v) + : kind(*BorrowScopeIntroducerKind::get(v->getKind())), value(v) { + assert(v.getOwnershipKind() == ValueOwnershipKind::Guaranteed); + } + + /// If value is a borrow introducer return it after doing some checks. + static Optional get(SILValue value) { + auto kind = BorrowScopeIntroducerKind::get(value->getKind()); + if (!kind || value.getOwnershipKind() != ValueOwnershipKind::Guaranteed) + return None; + return BorrowScopeIntroducingValue(*kind, value); + } + + /// If this value is introducing a local scope, gather all local end scope + /// instructions and append them to \p scopeEndingInsts. Asserts if this is + /// called with a scope that is not local. + /// + /// NOTE: To determine if a scope is a local scope, call + /// BorrowScopeIntoducingValue::isLocalScope(). + void getLocalScopeEndingInstructions( + SmallVectorImpl &scopeEndingInsts) const; + + /// If this value is introducing a local scope, gather all local end scope + /// instructions and pass them individually to visitor. Asserts if this is + /// called with a scope that is not local. + /// + /// The intention is that this method can be used instead of + /// BorrowScopeIntroducingValue::getLocalScopeEndingUses() to avoid + /// introducing an intermediate array when one needs to transform the + /// instructions before storing them. + /// + /// NOTE: To determine if a scope is a local scope, call + /// BorrowScopeIntoducingValue::isLocalScope(). + void visitLocalScopeEndingUses(function_ref visitor) const; + + bool isLocalScope() const { return kind.isLocalScope(); } + + /// Returns true if the passed in set of instructions is completely within the + /// lifetime of this borrow introducer. + /// + /// NOTE: Scratch space is used internally to this method to store the end + /// borrow scopes if needed. + bool areInstructionsWithinScope( + ArrayRef instructions, + SmallVectorImpl &scratchSpace, + SmallPtrSetImpl &visitedBlocks, + DeadEndBlocks &deadEndBlocks) const; + +private: + /// Internal constructor for failable static constructor. Please do not expand + /// its usage since it assumes the code passed in is well formed. + BorrowScopeIntroducingValue(BorrowScopeIntroducerKind kind, SILValue value) + : kind(kind), value(value) {} +}; + /// Look up through the def-use chain of \p inputValue, recording any "borrow" -/// introducers that we find into \p out. -bool getUnderlyingBorrowIntroducers(SILValue inputValue, - SmallVectorImpl &out); +/// introducing values that we find into \p out. If at any point, we find a +/// point in the chain we do not understand, we bail and return false. If we are +/// able to understand all of the def-use graph, we know that we have found all +/// of the borrow introducing values, we return true. +bool getUnderlyingBorrowIntroducingValues( + SILValue inputValue, SmallVectorImpl &out); } // namespace swift diff --git a/include/swift/SIL/PatternMatch.h b/include/swift/SIL/PatternMatch.h index ba05b4ad80629..ef75ce6fa1237 100644 --- a/include/swift/SIL/PatternMatch.h +++ b/include/swift/SIL/PatternMatch.h @@ -649,7 +649,7 @@ using BuiltinApplyTy = typename Apply_match::Ty; #define BUILTIN_CAST_OR_BITCAST_OPERATION(Id, Name, Attrs) \ BUILTIN_UNARY_OP_MATCH_WITH_ARG_MATCHER(Id, Id) -#define BUILTIN_BINARY_OPERATION(Id, Name, Attrs, Overload) \ +#define BUILTIN_BINARY_OPERATION_ALL(Id, Name, Attrs, Overload) \ BUILTIN_BINARY_OP_MATCH_WITH_ARG_MATCHER(Id, Id) #define BUILTIN_BINARY_PREDICATE(Id, Name, Attrs, Overload) \ diff --git a/include/swift/SIL/SILConstants.h b/include/swift/SIL/SILConstants.h index 71a0a0e1ba8e8..14e27e0e78323 100644 --- a/include/swift/SIL/SILConstants.h +++ b/include/swift/SIL/SILConstants.h @@ -37,69 +37,6 @@ struct UnknownSymbolicValue; extern llvm::cl::opt ConstExprLimit; -/// When we fail to constant fold a value, this captures a reason why, -/// allowing the caller to produce a specific diagnostic. The "Unknown" -/// SymbolicValue representation also includes a pointer to the SILNode in -/// question that was problematic. -enum class UnknownReason { - // TODO: Eliminate the default code, by making classifications for each - // failure mode. - Default, - - /// The constant expression was too big. This is reported on a random - /// instruction within the constexpr that triggered the issue. - TooManyInstructions, - - /// A control flow loop was found. - Loop, - - /// Integer overflow detected. - Overflow, - - /// Unspecified trap detected. - Trap, - - /// An operation was applied over operands whose symbolic values were - /// constants but were not valid for the operation. - InvalidOperandValue, - - /// Encountered an instruction not supported by the interpreter. - UnsupportedInstruction, - - /// Encountered a function call where the body of the called function is - /// not available. - CalleeImplementationUnknown, - - /// Attempted to load from/store into a SIL value that was not tracked by - /// the interpreter. - UntrackedSILValue, - - /// Attempted to find a concrete protocol conformance for a witness method - /// and failed. - UnknownWitnessMethodConformance, - - /// Attempted to determine the SIL function of a witness method (based on a - /// concrete protocol conformance) and failed. - UnresolvableWitnessMethod, - - /// The value of a top-level variable cannot be determined to be a constant. - /// This is only relevant in the backward evaluation mode, which is used by - /// #assert. - NotTopLevelConstant, - - /// A top-level value has multiple writers. This is only relevant in the - /// non-flow-sensitive evaluation mode, which is used by #assert. - MutipleTopLevelWriters, - - /// Indicates the return value of an instruction that was not evaluated during - /// interpretation. - ReturnedByUnevaluatedInstruction, - - /// Indicates that the value was possibly modified by an instruction - /// that was not evaluated during the interpretation. - MutatedByUnevaluatedInstruction, -}; - /// An abstract class that exposes functions for allocating symbolic values. /// The implementors of this class have to determine where to allocate them and /// and manage the lifetime of the allocated symbolic values. @@ -139,6 +76,132 @@ class SymbolicValueBumpAllocator : public SymbolicValueAllocator { } }; +/// When we fail to constant fold a value, this captures a reason why, +/// allowing the caller to produce a specific diagnostic. The "Unknown" +/// SymbolicValue representation also includes a pointer to the SILNode in +/// question that was problematic. +class UnknownReason { +public: + enum UnknownKind { + // TODO: Eliminate the default kind, by making classifications for each + // failure mode. + Default, + + /// The constant expression was too big. This is reported on a random + /// instruction within the constexpr that triggered the issue. + TooManyInstructions, + + /// A control flow loop was found. + Loop, + + /// Integer overflow detected. + Overflow, + + /// Trap detected. Traps will a message as a payload. + Trap, + + /// An operation was applied over operands whose symbolic values were + /// constants but were not valid for the operation. + InvalidOperandValue, + + /// Encountered an instruction not supported by the interpreter. + UnsupportedInstruction, + + /// Encountered a function call where the body of the called function is + /// not available. + CalleeImplementationUnknown, + + /// Attempted to load from/store into a SIL value that was not tracked by + /// the interpreter. + UntrackedSILValue, + + /// Attempted to find a concrete protocol conformance for a witness method + /// and failed. + UnknownWitnessMethodConformance, + + /// Attempted to determine the SIL function of a witness method and failed. + NoWitnesTableEntry, + + /// The value of a top-level variable cannot be determined to be a constant. + /// This is only relevant in the backward evaluation mode, which is used by + /// #assert. + NotTopLevelConstant, + + /// A top-level value has multiple writers. This is only relevant in the + /// non-flow-sensitive evaluation mode, which is used by #assert. + MutipleTopLevelWriters, + + /// Indicates the return value of an instruction that was not evaluated + /// during interpretation. + ReturnedByUnevaluatedInstruction, + + /// Indicates that the value was possibly modified by an instruction + /// that was not evaluated during the interpretation. + MutatedByUnevaluatedInstruction, + }; + +private: + UnknownKind kind; + + // Auxiliary information for different unknown kinds. + union { + SILFunction *function; + const char *trapMessage; + } payload; + +public: + UnknownKind getKind() { return kind; } + + static bool isUnknownKindWithPayload(UnknownKind kind) { + switch (kind) { + case UnknownKind::CalleeImplementationUnknown: + case UnknownKind::Trap: + return true; + default: + return false; + } + } + + static UnknownReason create(UnknownKind kind) { + assert(!isUnknownKindWithPayload(kind)); + UnknownReason reason; + reason.kind = kind; + return reason; + } + + static UnknownReason createCalleeImplementationUnknown(SILFunction *callee) { + assert(callee); + UnknownReason reason; + reason.kind = UnknownKind::CalleeImplementationUnknown; + reason.payload.function = callee; + return reason; + } + + SILFunction *getCalleeWithoutImplmentation() { + assert(kind == UnknownKind::CalleeImplementationUnknown); + return payload.function; + } + + static UnknownReason createTrap(StringRef message, + SymbolicValueAllocator &allocator) { + // Copy and null terminate the string. + size_t size = message.size(); + char *messagePtr = allocator.allocate(size + 1); + std::uninitialized_copy(message.begin(), message.end(), messagePtr); + messagePtr[size] = '\0'; + + UnknownReason reason; + reason.kind = UnknownKind::Trap; + reason.payload.trapMessage = messagePtr; + return reason; + } + + const char *getTrapMessage() { + assert(kind == UnknownKind::Trap); + return payload.trapMessage; + } +}; + /// This is the symbolic value tracked for each SILValue in a scope. We /// support multiple representational forms for the constant node in order to /// avoid pointless memory bloat + copying. This is intended to be a @@ -241,9 +304,6 @@ class SymbolicValue { RepresentationKind representationKind : 8; union { - /// This is the reason code for RK_Unknown values. - UnknownReason unknownReason : 32; - /// This is the number of bits in an RK_Integer or RK_IntegerInline /// representation, which makes the number of entries in the list derivable. unsigned integerBitwidth; diff --git a/include/swift/SIL/SILInstruction.h b/include/swift/SIL/SILInstruction.h index ec5fc873d0f82..5ed4979c693b2 100644 --- a/include/swift/SIL/SILInstruction.h +++ b/include/swift/SIL/SILInstruction.h @@ -525,6 +525,16 @@ class SILInstruction getAllOperands()[Num1].swap(getAllOperands()[Num2]); } +private: + /// Predicate used to filter OperandTypeRange. + struct OperandToType; + +public: + using OperandTypeRange = + OptionalTransformRange, OperandToType>; + // NOTE: We always skip type dependent operands. + OperandTypeRange getOperandTypes() const; + /// Return the list of results produced by this instruction. bool hasResults() const { return !getResults().empty(); } SILInstructionResultArray getResults() const { return getResultsImpl(); } @@ -702,6 +712,22 @@ SILInstruction::getOperandValues(bool skipTypeDependentOperands) const OperandToValue(*this, skipTypeDependentOperands)); } +struct SILInstruction::OperandToType { + const SILInstruction &i; + + OperandToType(const SILInstruction &i) : i(i) {} + + Optional operator()(const Operand &use) const { + if (i.isTypeDependentOperand(use)) + return None; + return use.get()->getType(); + } +}; + +inline auto SILInstruction::getOperandTypes() const -> OperandTypeRange { + return OperandTypeRange(getAllOperands(), OperandToType(*this)); +} + inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const SILInstruction &I) { I.print(OS); @@ -1837,7 +1863,8 @@ class ApplyInstBase : public Base { /// The operand number of the first argument. static unsigned getArgumentOperandNumber() { return NumStaticOperands; } - SILValue getCallee() const { return getAllOperands()[Callee].get(); } + const Operand *getCalleeOperand() const { return &getAllOperands()[Callee]; } + SILValue getCallee() const { return getCalleeOperand()->get(); } /// Gets the origin of the callee by looking through function type conversions /// until we find a function_ref, partial_apply, or unrecognized value. @@ -3009,7 +3036,7 @@ class BuiltinInst final /// Looks up the BuiltinKind of this builtin. Returns None if this is /// not a builtin. - llvm::Optional getBuiltinKind() const { + Optional getBuiltinKind() const { auto I = getBuiltinInfo(); if (I.ID == BuiltinValueKind::None) return None; @@ -7188,7 +7215,10 @@ class CondBranchInst final ProfileCounter FalseBBCount, SILFunction &F); public: - SILValue getCondition() const { return getAllOperands()[ConditionIdx].get(); } + const Operand *getConditionOperand() const { + return &getAllOperands()[ConditionIdx]; + } + SILValue getCondition() const { return getConditionOperand()->get(); } void setCondition(SILValue newCondition) { getAllOperands()[ConditionIdx].set(newCondition); } @@ -7234,6 +7264,11 @@ class CondBranchInst final return getAllOperands().slice(NumFixedOpers + getNumTrueArgs()); } + /// Returns true if \p op is mapped to the condition operand of the cond_br. + bool isConditionOperand(Operand *op) const { + return getConditionOperand() == op; + } + bool isConditionOperandIndex(unsigned OpIndex) const { assert(OpIndex < getNumOperands() && "OpIndex must be an index for an actual operand"); diff --git a/include/swift/SIL/TypeLowering.h b/include/swift/SIL/TypeLowering.h index 0e9e35da34add..6361b8f3bba95 100644 --- a/include/swift/SIL/TypeLowering.h +++ b/include/swift/SIL/TypeLowering.h @@ -689,7 +689,7 @@ class TypeConverter { llvm::DenseMap ConstantOverrideTypes; - llvm::DenseMap LoweredCaptures; + llvm::DenseMap LoweredCaptures; /// Cache of loadable SILType to number of (estimated) fields /// @@ -844,10 +844,13 @@ class TypeConverter { /// Returns the formal type, lowered AST type, and SILFunctionType /// for a constant reference. const SILConstantInfo &getConstantInfo(SILDeclRef constant); - + + /// Get the generic environment for a constant. + GenericSignature *getConstantGenericSignature(SILDeclRef constant); + /// Get the generic environment for a constant. GenericEnvironment *getConstantGenericEnvironment(SILDeclRef constant); - + /// Returns the SIL type of a constant reference. SILType getConstantType(SILDeclRef constant) { return getConstantInfo(constant).getSILType(); @@ -893,11 +896,6 @@ class TypeConverter { SILType getEmptyTupleType() { return SILType::getPrimitiveObjectType(TupleType::getEmpty(Context)); } - - /// Get a function type curried with its capture context. - CanAnyFunctionType getFunctionInterfaceTypeWithCaptures( - CanAnyFunctionType funcType, - AnyFunctionRef closure); /// Describes what we're trying to compute a bridged type for. /// @@ -944,17 +942,6 @@ class TypeConverter { SILType getSubstitutedStorageType(AbstractStorageDecl *value, Type lvalueType); - /// Retrieve the set of archetypes closed over by the given function. - GenericEnvironment *getEffectiveGenericEnvironment(AnyFunctionRef fn, - CaptureInfo captureInfo); - - /// Retrieve the set of generic parameters closed over by the given function. - CanGenericSignature getEffectiveGenericSignature(AnyFunctionRef fn, - CaptureInfo captureInfo); - - /// Retrieve the set of generic parameters closed over by the context. - CanGenericSignature getEffectiveGenericSignature(DeclContext *dc); - /// Push a generic function context. See GenericContextScope for an RAII /// interface to this function. /// @@ -980,10 +967,10 @@ class TypeConverter { CanType get##BridgedType##Type(); #include "swift/SIL/BridgedTypes.def" - /// Get the capture list from a closure, with transitive function captures - /// flattened. - CaptureInfo getLoweredLocalCaptures(AnyFunctionRef fn); - bool hasLoweredLocalCaptures(AnyFunctionRef fn); + /// Get the capture list for a function or default argument, with transitive + /// function captures flattened. + CaptureInfo getLoweredLocalCaptures(SILDeclRef fn); + bool hasLoweredLocalCaptures(SILDeclRef fn); enum class ABIDifference : uint8_t { // No ABI differences, function can be trivially bitcast to result type. diff --git a/include/swift/SILOptimizer/PassManager/Passes.def b/include/swift/SILOptimizer/PassManager/Passes.def index 22baa245ec15f..2126032328982 100644 --- a/include/swift/SILOptimizer/PassManager/Passes.def +++ b/include/swift/SILOptimizer/PassManager/Passes.def @@ -112,6 +112,8 @@ PASS(ConditionForwarding, "condition-forwarding", "Conditional Branch Forwarding to Fold SIL switch_enum") PASS(ConstantEvaluatorTester, "test-constant-evaluator", "Test constant evaluator") +PASS(ConstantEvaluableSubsetChecker, "test-constant-evaluable-subset", + "Test Swift code snippets expected to be constant evaluable") PASS(CopyForwarding, "copy-forwarding", "Copy Forwarding to Remove Redundant Copies") PASS(CopyPropagation, "copy-propagation", diff --git a/include/swift/SILOptimizer/Utils/ConstExpr.h b/include/swift/SILOptimizer/Utils/ConstExpr.h index 7cd8b452d4e2e..cb6cac6b97a6e 100644 --- a/include/swift/SILOptimizer/Utils/ConstExpr.h +++ b/include/swift/SILOptimizer/Utils/ConstExpr.h @@ -38,26 +38,39 @@ class SILNode; class SymbolicValue; class SymbolicValueAllocator; class ConstExprFunctionState; -enum class UnknownReason; +class UnknownReason; /// This class is the main entrypoint for evaluating constant expressions. It /// also handles caching of previously computed constexpr results. class ConstExprEvaluator { SymbolicValueAllocator &allocator; + // Assert configuration that must be used by the evaluator. This determines + // the result of the builtin "assert_configuration". + unsigned assertConfig; + /// The current call stack, used for providing accurate diagnostics. llvm::SmallVector callStack; + /// When set to true, keep track of all functions called during an evaluation. + bool trackCallees; + /// Functions called during the evaluation. This is an auxiliary information + /// provided to the clients. + llvm::SmallPtrSet calledFunctions; + void operator=(const ConstExprEvaluator &) = delete; public: - explicit ConstExprEvaluator(SymbolicValueAllocator &alloc); + explicit ConstExprEvaluator(SymbolicValueAllocator &alloc, + unsigned assertConf, bool trackCallees = false); ~ConstExprEvaluator(); explicit ConstExprEvaluator(const ConstExprEvaluator &other); SymbolicValueAllocator &getAllocator() { return allocator; } + unsigned getAssertConfig() { return assertConfig; } + void pushCallStack(SourceLoc loc) { callStack.push_back(loc); } void popCallStack() { @@ -75,12 +88,23 @@ class ConstExprEvaluator { /// This is done in code that is not necessarily itself a constexpr /// function. The results are added to the results list which is a parallel /// structure to the input values. - /// - /// TODO: Return information about which callees were found to be - /// constexprs, which would allow the caller to delete dead calls to them - /// that occur after after folding them. void computeConstantValues(ArrayRef values, SmallVectorImpl &results); + + void recordCalledFunctionIfEnabled(SILFunction *callee) { + if (trackCallees) { + calledFunctions.insert(callee); + } + } + + /// If the evaluator was initialized with \c trackCallees enabled, return the + /// SIL functions encountered during the evaluations performed with this + /// evaluator. The returned functions include those that were called but + /// failed to complete successfully. + const SmallPtrSetImpl &getFuncsCalledDuringEvaluation() const { + assert(trackCallees && "evaluator not configured to track callees"); + return calledFunctions; + } }; /// A constant-expression evaluator that can be used to step through a control @@ -106,7 +130,8 @@ class ConstExprStepEvaluator { /// Constructs a step evaluator given an allocator and a non-null pointer to a /// SILFunction. explicit ConstExprStepEvaluator(SymbolicValueAllocator &alloc, - SILFunction *fun); + SILFunction *fun, unsigned assertConf, + bool trackCallees = false); ~ConstExprStepEvaluator(); /// Evaluate an instruction in the current interpreter state. @@ -162,8 +187,6 @@ class ConstExprStepEvaluator { Optional lookupConstValue(SILValue value); - bool isKnownFunction(SILFunction *fun); - /// Returns true if and only if `errorVal` denotes an error that requires /// aborting interpretation and returning the error. Skipping an instruction /// that produces such errors is not a valid behavior. @@ -175,7 +198,18 @@ class ConstExprStepEvaluator { /// Note that 'skipByMakingEffectsNonConstant' operation is not considered /// as an evaluation. unsigned instructionsEvaluatedByLastEvaluation() { return stepsEvaluated; } + + /// If the evaluator was initialized with \c trackCallees enabled, return the + /// SIL functions encountered during the evaluations performed with this + /// evaluator. The returned functions include those that were called but + /// failed to complete successfully. Targets of skipped apply instructions + /// will not be included in the returned set. + const SmallPtrSetImpl &getFuncsCalledDuringEvaluation() { + return evaluator.getFuncsCalledDuringEvaluation(); + } }; +bool isKnownConstantEvaluableFunction(SILFunction *fun); + } // end namespace swift #endif diff --git a/include/swift/SILOptimizer/Utils/Local.h b/include/swift/SILOptimizer/Utils/Local.h index 9333c06c1b48f..055fc4efd5144 100644 --- a/include/swift/SILOptimizer/Utils/Local.h +++ b/include/swift/SILOptimizer/Utils/Local.h @@ -372,6 +372,46 @@ class BasicBlockCloner : public SILCloner { } }; +/// Sink address projections to their out-of-block uses. This is +/// required after cloning a block and before calling +/// updateSSAAfterCloning to avoid address-type phis. +/// +/// This clones address projections at their use points, but does not +/// mutate the block containing the projections. +class SinkAddressProjections { + // Projections ordered from last to first in the chain. + SmallVector projections; + SmallSetVector inBlockDefs; + +public: + /// Check for an address projection chain ending at \p inst. Return true if + /// the given instruction is successfully analyzed. + /// + /// If \p inst does not produce an address, then return + /// true. getInBlockDefs() will contain \p inst if any of its + /// (non-address) values are used outside its block. + /// + /// If \p inst does produce an address, return true only of the + /// chain of address projections within this block is clonable at + /// their use sites. getInBlockDefs will return all non-address + /// operands in the chain that are also defined in this block. These + /// may require phis after cloning the projections. + bool analyzeAddressProjections(SILInstruction *inst); + + /// After analyzing projections, returns the list of (non-address) values + /// defined in the same block as the projections which will have uses outside + /// the block after cloning. + ArrayRef getInBlockDefs() const { + return inBlockDefs.getArrayRef(); + } + /// Clone the chain of projections at their use sites. + /// + /// Return true if anything was done. + /// + /// getInBlockProjectionOperandValues() can be called before or after cloning. + bool cloneProjections(); +}; + /// Helper function to perform SSA updates in case of jump threading. void updateSSAAfterCloning(BasicBlockCloner &Cloner, SILBasicBlock *SrcBB, SILBasicBlock *DestBB); diff --git a/include/swift/Serialization/SerializedModuleLoader.h b/include/swift/Serialization/SerializedModuleLoader.h index 908a3383ef46f..bbd904d541026 100644 --- a/include/swift/Serialization/SerializedModuleLoader.h +++ b/include/swift/Serialization/SerializedModuleLoader.h @@ -13,6 +13,7 @@ #ifndef SWIFT_SERIALIZATION_MODULELOADER_H #define SWIFT_SERIALIZATION_MODULELOADER_H +#include "swift/AST/FileUnit.h" #include "swift/AST/Module.h" #include "swift/AST/ModuleLoader.h" #include "llvm/Support/MemoryBuffer.h" diff --git a/include/swift/SwiftRemoteMirror/SwiftRemoteMirrorTypes.h b/include/swift/SwiftRemoteMirror/SwiftRemoteMirrorTypes.h index 8085525cba31c..c64ce70e5449a 100644 --- a/include/swift/SwiftRemoteMirror/SwiftRemoteMirrorTypes.h +++ b/include/swift/SwiftRemoteMirror/SwiftRemoteMirrorTypes.h @@ -53,32 +53,32 @@ typedef struct swift_reflection_section { typedef struct swift_reflection_info { struct { swift_reflection_section_t section; - swift_reflection_ptr_t offset; + swift_reflection_ptr_t offset; ///< DEPRECATED. Must be zero } field; struct { swift_reflection_section_t section; - swift_reflection_ptr_t offset; + swift_reflection_ptr_t offset; ///< DEPRECATED. Must be zero } associated_types; struct { swift_reflection_section_t section; - swift_reflection_ptr_t offset; + swift_reflection_ptr_t offset; ///< DEPRECATED. Must be zero } builtin_types; struct { swift_reflection_section_t section; - swift_reflection_ptr_t offset; + swift_reflection_ptr_t offset; ///< DEPRECATED. Must be zero } capture; struct { swift_reflection_section_t section; - swift_reflection_ptr_t offset; + swift_reflection_ptr_t offset; ///< DEPRECATED. Must be zero } type_references; struct { swift_reflection_section_t section; - swift_reflection_ptr_t offset; + swift_reflection_ptr_t offset; ///< DEPRECATED. Must be zero } reflection_strings; // Start address in local and remote address spaces. diff --git a/include/swift/Syntax/Syntax.h b/include/swift/Syntax/Syntax.h index eef64dfaf526e..c4b2d8f227dc3 100644 --- a/include/swift/Syntax/Syntax.h +++ b/include/swift/Syntax/Syntax.h @@ -172,11 +172,11 @@ class Syntax { /// Returns the first non-missing token in this syntax. Returns None if there /// is no non-missing token. - Optional getFirstToken(); + Optional getFirstToken() const; /// Returns the last non-missing token in this syntax. Returns None if there /// is no non-missing token. - Optional getLastToken(); + Optional getLastToken() const; /// Print the syntax node with full fidelity to the given output stream. void print(llvm::raw_ostream &OS, SyntaxPrintOptions Opts = SyntaxPrintOptions()) const; diff --git a/include/swift/Syntax/SyntaxBuilders.h.gyb b/include/swift/Syntax/SyntaxBuilders.h.gyb index 7fe71ed159a3d..60f90057efa57 100644 --- a/include/swift/Syntax/SyntaxBuilders.h.gyb +++ b/include/swift/Syntax/SyntaxBuilders.h.gyb @@ -29,7 +29,7 @@ namespace syntax { class SyntaxArena; -% for node in SYNTAX_NODES: +% for node in SYNTAX_NODES + PARSEONLY_NODES: % if node.is_buildable(): % child_count = len(node.children) class ${node.name}Builder { diff --git a/include/swift/Syntax/SyntaxFactory.h.gyb b/include/swift/Syntax/SyntaxFactory.h.gyb index 387279d73f891..ef4566cbff237 100644 --- a/include/swift/Syntax/SyntaxFactory.h.gyb +++ b/include/swift/Syntax/SyntaxFactory.h.gyb @@ -71,7 +71,7 @@ struct SyntaxFactory { static Syntax makeBlankCollectionSyntax(SyntaxKind Kind); -% for node in SYNTAX_NODES: +% for node in SYNTAX_NODES + PARSEONLY_NODES: % if node.children: % child_params = [] % for child in node.children: diff --git a/include/swift/Syntax/SyntaxKind.h.gyb b/include/swift/Syntax/SyntaxKind.h.gyb index 21f344a572352..7f2bfbc5158d1 100644 --- a/include/swift/Syntax/SyntaxKind.h.gyb +++ b/include/swift/Syntax/SyntaxKind.h.gyb @@ -2,7 +2,7 @@ from gyb_syntax_support import * from gyb_syntax_support.kinds import SYNTAX_BASE_KINDS grouped_nodes = { kind: [] for kind in SYNTAX_BASE_KINDS } - for node in SYNTAX_NODES: + for node in SYNTAX_NODES + PARSEONLY_NODES: grouped_nodes[node.base_kind].append(node) # -*- mode: C++ -*- # Ignore the following admonition; it applies to the resulting .h file only @@ -89,12 +89,14 @@ struct WrapperTypeTraits { return 0; case syntax::SyntaxKind::Unknown: return 1; -% for name, nodes in grouped_nodes.items(): -% for node in nodes: +% for node in SYNTAX_NODES: case syntax::SyntaxKind::${node.syntax_kind}: return ${SYNTAX_NODE_SERIALIZATION_CODES[node.syntax_kind]}; -% end % end +% for node in PARSEONLY_NODES: + case syntax::SyntaxKind::${node.syntax_kind}: +% end + llvm_unreachable("unserializable syntax kind"); } llvm_unreachable("unhandled kind"); } @@ -122,6 +124,10 @@ struct ScalarReferenceTraits { case syntax::SyntaxKind::${node.syntax_kind}: return "\"${node.syntax_kind}\""; % end +% for node in PARSEONLY_NODES: + case syntax::SyntaxKind::${node.syntax_kind}: +% end + llvm_unreachable("unserializable syntax kind"); } llvm_unreachable("unhandled kind"); } diff --git a/include/swift/Syntax/SyntaxNodes.h.gyb b/include/swift/Syntax/SyntaxNodes.h.gyb index 65219ce8489d1..2f990973864c6 100644 --- a/include/swift/Syntax/SyntaxNodes.h.gyb +++ b/include/swift/Syntax/SyntaxNodes.h.gyb @@ -32,13 +32,13 @@ namespace syntax { % # Emit the non-collection classes first, then emit the collection classes % # that reference these classes. -% for node in SYNTAX_NODES: +% for node in SYNTAX_NODES + PARSEONLY_NODES: % if not node.is_syntax_collection(): class ${node.name}; % end % end -% for node in SYNTAX_NODES: +% for node in SYNTAX_NODES + PARSEONLY_NODES: % if node.is_syntax_collection(): using ${node.name} = SyntaxCollection get${child.name}(); + llvm::Optional<${child.type_name}> get${child.name}() const; % else: - ${child.type_name} get${child.name}(); + ${child.type_name} get${child.name}() const; % end % child_node = NODE_MAP.get(child.syntax_kind) diff --git a/include/swift/Syntax/SyntaxVisitor.h.gyb b/include/swift/Syntax/SyntaxVisitor.h.gyb index 5c172a430c693..14b936357a783 100644 --- a/include/swift/Syntax/SyntaxVisitor.h.gyb +++ b/include/swift/Syntax/SyntaxVisitor.h.gyb @@ -32,7 +32,7 @@ namespace syntax { struct SyntaxVisitor { virtual ~SyntaxVisitor() {} -% for node in SYNTAX_NODES: +% for node in SYNTAX_NODES + PARSEONLY_NODES: % if is_visitable(node): virtual void visit(${node.name} node); % end diff --git a/include/swift/TBDGen/TBDGen.h b/include/swift/TBDGen/TBDGen.h index 073e570c40f08..7419e60d3c469 100644 --- a/include/swift/TBDGen/TBDGen.h +++ b/include/swift/TBDGen/TBDGen.h @@ -33,6 +33,9 @@ struct TBDGenOptions { /// Whether this compilation has multiple IRGen instances. bool HasMultipleIGMs; + /// Whether this compilation is producing a TBD for InstallAPI. + bool IsInstallAPI; + /// The install_name to use in the TBD file. std::string InstallName; diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 1ce6f5e541081..fdc4ec4691530 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -22,6 +22,7 @@ #include "swift/AST/DiagnosticEngine.h" #include "swift/AST/DiagnosticsSema.h" #include "swift/AST/ExistentialLayout.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/ForeignErrorConvention.h" #include "swift/AST/GenericEnvironment.h" #include "swift/AST/GenericSignature.h" @@ -36,6 +37,7 @@ #include "swift/AST/PropertyWrappers.h" #include "swift/AST/ProtocolConformance.h" #include "swift/AST/RawComment.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/SubstitutionMap.h" #include "swift/AST/SILLayout.h" #include "swift/AST/TypeCheckRequests.h" @@ -98,9 +100,10 @@ using AssociativityCacheType = Associativity>; #define FOR_KNOWN_FOUNDATION_TYPES(MACRO) \ - MACRO(NSError) \ - MACRO(NSNumber) \ - MACRO(NSValue) + MACRO(NSCopying, ProtocolDecl) \ + MACRO(NSError, ClassDecl) \ + MACRO(NSNumber, ClassDecl) \ + MACRO(NSValue, ClassDecl) struct OverrideSignatureKey { GenericSignature *baseMethodSig; @@ -232,9 +235,9 @@ struct ASTContext::Implementation { /// The declaration of ObjectiveC.ObjCBool. StructDecl *ObjCBoolDecl = nullptr; -#define CACHE_FOUNDATION_DECL(NAME) \ +#define CACHE_FOUNDATION_DECL(NAME, DECLTYPE) \ /** The declaration of Foundation.NAME. */ \ - ClassDecl *NAME##Decl = nullptr; + DECLTYPE *NAME##Decl = nullptr; FOR_KNOWN_FOUNDATION_TYPES(CACHE_FOUNDATION_DECL) #undef CACHE_FOUNDATION_DECL @@ -1021,18 +1024,18 @@ StructDecl *ASTContext::getObjCBoolDecl() const { return getImpl().ObjCBoolDecl; } -#define GET_FOUNDATION_DECL(NAME) \ -ClassDecl *ASTContext::get##NAME##Decl() const { \ +#define GET_FOUNDATION_DECL(NAME, DECLTYPE) \ +DECLTYPE *ASTContext::get##NAME##Decl() const { \ if (!getImpl().NAME##Decl) { \ if (ModuleDecl *M = getLoadedModule(Id_Foundation)) { \ /* Note: lookupQualified() will search both the Foundation module \ * and the Clang Foundation module it imports. */ \ SmallVector decls; \ M->lookupQualified(M, getIdentifier(#NAME), NL_OnlyTypes, decls); \ - if (decls.size() == 1 && isa(decls[0])) { \ - auto classDecl = cast(decls[0]); \ - if (classDecl->getGenericParams() == nullptr) { \ - getImpl().NAME##Decl = classDecl; \ + if (decls.size() == 1 && isa(decls[0])) { \ + auto decl = cast(decls[0]); \ + if (isa(decl) || decl->getGenericParams() == nullptr) { \ + getImpl().NAME##Decl = decl; \ } \ } \ } \ @@ -1102,8 +1105,8 @@ static FuncDecl *findLibraryIntrinsic(const ASTContext &ctx, ctx.lookupInSwiftModule(name, results); if (results.size() == 1) { if (auto FD = dyn_cast(results.front())) { - if (auto *resolver = ctx.getLazyResolver()) - resolver->resolveDeclSignature(FD); + // FIXME(InterfaceTypeRequest): Remove this. + (void)FD->getInterfaceType(); return FD; } } @@ -1167,9 +1170,6 @@ lookupOperatorFunc(const ASTContext &ctx, StringRef oper, Type contextType, if (!contextTy->isEqual(contextType)) continue; } - if (auto resolver = ctx.getLazyResolver()) - resolver->resolveDeclSignature(fnDecl); - auto *funcTy = getIntrinsicCandidateType(fnDecl, /*allowTypeMembers=*/true); if (!funcTy) continue; @@ -4160,8 +4160,6 @@ static NominalTypeDecl *findUnderlyingTypeInModule(ASTContext &ctx, // Look through typealiases. if (auto typealias = dyn_cast(result)) { - if (auto resolver = ctx.getLazyResolver()) - resolver->resolveDeclSignature(typealias); return typealias->getDeclaredInterfaceType()->getAnyNominal(); } } diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index ce34964644958..a44add52bbf87 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -22,6 +22,7 @@ #include "swift/AST/Initializer.h" #include "swift/AST/ParameterList.h" #include "swift/AST/ProtocolConformance.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/TypeVisitor.h" #include "swift/Basic/Defer.h" #include "swift/Basic/QuotedString.h" @@ -616,9 +617,9 @@ namespace { void visitTypeAliasDecl(TypeAliasDecl *TAD) { printCommon(TAD, "typealias"); PrintWithColorRAII(OS, TypeColor) << " type='"; - if (TAD->getUnderlyingTypeLoc().getType()) { + if (auto underlying = TAD->getUnderlyingType()) { PrintWithColorRAII(OS, TypeColor) - << TAD->getUnderlyingTypeLoc().getType().getString(); + << underlying.getString(); } else { PrintWithColorRAII(OS, TypeColor) << "<<>>"; } @@ -987,9 +988,17 @@ namespace { if (P->isAutoClosure()) OS << " autoclosure"; - if (P->getDefaultArgumentKind() != DefaultArgumentKind::None) + if (P->getDefaultArgumentKind() != DefaultArgumentKind::None) { printField("default_arg", getDefaultArgumentKindString(P->getDefaultArgumentKind())); + } + + if (P->getDefaultValue() && + !P->getDefaultArgumentCaptureInfo().isTrivial()) { + OS << " "; + P->getDefaultArgumentCaptureInfo().print( + PrintWithColorRAII(OS, CapturesColor).getOS()); + } if (auto init = P->getDefaultValue()) { OS << " expression=\n"; @@ -3418,6 +3427,12 @@ namespace { void visitTypeAliasType(TypeAliasType *T, StringRef label) { printCommon(label, "type_alias_type"); printField("decl", T->getDecl()->printRef()); + PrintWithColorRAII(OS, TypeColor) << " underlying='"; + if (auto underlying = T->getSinglyDesugaredType()) { + PrintWithColorRAII(OS, TypeColor) << underlying->getString(); + } else { + PrintWithColorRAII(OS, TypeColor) << "<<>>"; + } if (T->getParent()) printRec("parent", T->getParent()); diff --git a/lib/AST/ASTMangler.cpp b/lib/AST/ASTMangler.cpp index 02224436ce7b3..28de54122449f 100644 --- a/lib/AST/ASTMangler.cpp +++ b/lib/AST/ASTMangler.cpp @@ -18,6 +18,7 @@ #include "swift/AST/ASTContext.h" #include "swift/AST/ASTVisitor.h" #include "swift/AST/ExistentialLayout.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/GenericSignature.h" #include "swift/AST/Initializer.h" #include "swift/AST/LazyResolver.h" @@ -2414,13 +2415,7 @@ CanType ASTMangler::getDeclTypeForMangling( parentGenericSig = nullptr; auto &C = decl->getASTContext(); - if (!decl->hasInterfaceType() && !decl->getDeclContext()->isLocalContext()) { - if (auto *resolver = C.getLazyResolver()) { - resolver->resolveDeclSignature(const_cast(decl)); - } - } - - if (!decl->hasInterfaceType() || decl->getInterfaceType()->is()) { + if (!decl->getInterfaceType() || decl->getInterfaceType()->is()) { if (isa(decl)) return CanFunctionType::get({AnyFunctionType::Param(C.TheErrorType)}, C.TheErrorType); diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index c7981b0886900..63a7381da0748 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -22,6 +22,7 @@ #include "swift/AST/Comment.h" #include "swift/AST/Decl.h" #include "swift/AST/Expr.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/GenericEnvironment.h" #include "swift/AST/Module.h" #include "swift/AST/NameLookup.h" @@ -2276,7 +2277,7 @@ void PrintAST::visitTypeAliasDecl(TypeAliasDecl *decl) { printGenericDeclGenericParams(decl); }); bool ShouldPrint = true; - Type Ty = decl->getUnderlyingTypeLoc().getType(); + Type Ty = decl->getUnderlyingType(); // If the underlying type is private, don't print it. if (Options.SkipPrivateStdlibDecls && Ty && Ty.isPrivateStdlibType()) @@ -2294,7 +2295,7 @@ void PrintAST::visitTypeAliasDecl(TypeAliasDecl *decl) { // preserving sugar. llvm::SaveAndRestore setGenericEnv(Options.GenericEnv, decl->getGenericEnvironment()); - printTypeLoc(decl->getUnderlyingTypeLoc()); + printTypeLoc(TypeLoc(decl->getUnderlyingTypeRepr(), Ty)); printGenericDeclGenericRequirements(decl); } } diff --git a/lib/AST/ASTScope.cpp b/lib/AST/ASTScope.cpp index c996ed2707221..adce677b4a120 100644 --- a/lib/AST/ASTScope.cpp +++ b/lib/AST/ASTScope.cpp @@ -25,6 +25,7 @@ #include "swift/AST/NameLookup.h" #include "swift/AST/ParameterList.h" #include "swift/AST/Pattern.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/Stmt.h" #include "swift/AST/TypeRepr.h" #include "swift/Basic/NullablePtr.h" @@ -178,7 +179,7 @@ NullablePtr BraceStmtScope::getDeclContext() const { NullablePtr DefaultArgumentInitializerScope::getDeclContext() const { auto *dc = decl->getDefaultArgumentInitContext(); - assert(dc && "If scope exists, this must exist"); + ASTScopeAssert(dc, "If scope exists, this must exist"); return dc; } @@ -230,6 +231,9 @@ DEFINE_GET_CLASS_NAME(ClosureParametersScope) DEFINE_GET_CLASS_NAME(ClosureBodyScope) DEFINE_GET_CLASS_NAME(TopLevelCodeScope) DEFINE_GET_CLASS_NAME(SpecializeAttributeScope) +// SWIFT_ENABLE_TENSORFLOW +DEFINE_GET_CLASS_NAME(DifferentiableAttributeScope) +// SWIFT_ENABLE_TENSORFLOW END DEFINE_GET_CLASS_NAME(SubscriptDeclScope) DEFINE_GET_CLASS_NAME(VarDeclScope) DEFINE_GET_CLASS_NAME(EnumElementScope) @@ -267,6 +271,9 @@ ExtensionScope::getCorrespondingNominalTypeDecl() const { void ASTScopeImpl::preOrderDo(function_ref fn) { fn(this); + preOrderChildrenDo(fn); +} +void ASTScopeImpl::preOrderChildrenDo(function_ref fn) { for (auto *child : getChildren()) child->preOrderDo(fn); } @@ -285,3 +292,22 @@ const StmtConditionElement & ConditionalClauseScope::getStmtConditionElement() const { return getCond()[index]; } + +unsigned ASTScopeImpl::countDescendants() const { + unsigned count = 0; + const_cast(this)->preOrderDo( + [&](ASTScopeImpl *) { ++count; }); + return count - 1; +} + +// Can fail if a subscope is lazy and not reexpanded +void ASTScopeImpl::assertThatTreeDoesNotShrink(function_ref fn) { +#ifndef NDEBUG + unsigned beforeCount = countDescendants(); +#endif + fn(); +#ifndef NDEBUG + unsigned afterCount = countDescendants(); + ASTScopeAssert(beforeCount <= afterCount, "shrank?!"); +#endif +} diff --git a/lib/AST/ASTScopeCreation.cpp b/lib/AST/ASTScopeCreation.cpp index 7a3d4113b4103..041d7a8e62973 100644 --- a/lib/AST/ASTScopeCreation.cpp +++ b/lib/AST/ASTScopeCreation.cpp @@ -25,6 +25,7 @@ #include "swift/AST/Module.h" #include "swift/AST/ParameterList.h" #include "swift/AST/Pattern.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/Stmt.h" #include "swift/AST/TypeRepr.h" #include "swift/Basic/STLExtras.h" @@ -59,6 +60,11 @@ static SourceRange getRangeableSourceRange(const Rangeable *const p) { static SourceRange getRangeableSourceRange(const SpecializeAttr *a) { return a->getRange(); } +// SWIFT_ENABLE_TENSORFLOW +static SourceRange getRangeableSourceRange(const DifferentiableAttr *a) { + return a->getRange(); +} +// SWIFT_ENABLE_TENSORFLOW END static SourceRange getRangeableSourceRange(const ASTNode n) { return n.getSourceRange(); } @@ -93,6 +99,19 @@ static void dumpRangeable(SpecializeAttr *r, llvm::raw_ostream &f) { llvm::errs() << "SpecializeAttr\n"; } +// SWIFT_ENABLE_TENSORFLOW +static void dumpRangeable(const DifferentiableAttr *a, + llvm::raw_ostream &f) LLVM_ATTRIBUTE_USED; +static void dumpRangeable(const DifferentiableAttr *a, llvm::raw_ostream &f) { + llvm::errs() << "DifferentiableAttr\n"; +} +static void dumpRangeable(DifferentiableAttr *a, + llvm::raw_ostream &f) LLVM_ATTRIBUTE_USED; +static void dumpRangeable(DifferentiableAttr *a, llvm::raw_ostream &f) { + llvm::errs() << "DifferentiableAttr\n"; +} +// SWIFT_ENABLE_TENSORFLOW END + /// For Debugging template bool doesRangeableRangeMatch(const T *x, const SourceManager &SM, @@ -185,27 +204,9 @@ class ScopeCreator final { /// For allocating scopes. ASTContext &ctx; -public: - /// Because type checking can mutate the AST, eagerly build the tree, then - /// freeze it - enum class Temperature { - Warm, // Can be lazy - Freezing, // Should expand everything eagerly - Frozen // No more changes, except when Decls are added to the source file - }; - -private: - /// Because type checking can mutate the AST, eagerly build the tree, then - /// freeze it - Temperature temperature = Temperature::Warm; - public: ASTSourceFileScope *const sourceFileScope; ASTContext &getASTContext() const { return ctx; } - bool getIsFrozen() const { return temperature == Temperature::Frozen; } - bool getIsFreezing() const { return temperature == Temperature::Freezing; } - void beFreezing() { temperature = Temperature::Freezing; } - void beFrozen() { temperature = Temperature::Frozen; } /// The AST can have duplicate nodes, and we don't want to create scopes for /// those. @@ -222,15 +223,25 @@ class ScopeCreator final { /// Given an array of ASTNodes or Decl pointers, add them /// Return the resultant insertionPoint - ASTScopeImpl *addSiblingsToScopeTree(ASTScopeImpl *const insertionPoint, - ArrayRef nodesOrDeclsToAdd) { + ASTScopeImpl * + addSiblingsToScopeTree(ASTScopeImpl *const insertionPoint, + ASTScopeImpl *const organicInsertionPoint, + ArrayRef nodesOrDeclsToAdd) { auto *ip = insertionPoint; for (auto nd : expandIfConfigClausesThenCullAndSortElementsOrMembers( nodesOrDeclsToAdd)) { - if (shouldThisNodeBeScopedWhenFoundInSourceFileBraceStmtOrType(nd)) - ip = addToScopeTreeAndReturnInsertionPoint(nd, ip).getPtrOr(ip); - else + if (!shouldThisNodeBeScopedWhenFoundInSourceFileBraceStmtOrType(nd)) { + // FIXME: Could the range get lost if the node is ever reexpanded? ip->widenSourceRangeForIgnoredASTNode(nd); + } else { + const unsigned preCount = ip->getChildren().size(); + auto *const newIP = + addToScopeTreeAndReturnInsertionPoint(nd, ip).getPtrOr(ip); + if (ip != organicInsertionPoint) + ip->increaseASTAncestorScopeCount(ip->getChildren().size() - + preCount); + ip = newIP; + } } return ip; } @@ -300,9 +311,9 @@ class ScopeCreator final { // IDE/complete_property_delegate_attribute.swift fails because we try to // expand a member whose source range is backwards. (void)SM; - assert((d->getStartLoc().isInvalid() || - !SM.isBeforeInBuffer(d->getEndLoc(), d->getStartLoc())) && - "end-before-start will break tree search via location"); + ASTScopeAssert(d->getStartLoc().isInvalid() || + !SM.isBeforeInBuffer(d->getEndLoc(), d->getStartLoc()), + "end-before-start will break tree search via location"); return true; } @@ -313,8 +324,8 @@ class ScopeCreator final { template ASTScopeImpl *constructExpandAndInsertUncheckable(ASTScopeImpl *parent, Args... args) { - assert(!Scope(args...).getReferrent() && - "Not checking for duplicate ASTNode but class supports it"); + ASTScopeAssert(!Scope(args...).getReferrent(), + "Not checking for duplicate ASTNode but class supports it"); return constructExpandAndInsert(parent, args...); } @@ -322,8 +333,9 @@ class ScopeCreator final { NullablePtr ifUniqueConstructExpandAndInsert(ASTScopeImpl *parent, Args... args) { Scope dryRun(args...); - assert(dryRun.getReferrent() && - "Checking for duplicate ASTNode but class does not support it"); + ASTScopeAssert( + dryRun.getReferrent(), + "Checking for duplicate ASTNode but class does not support it"); if (scopedNodes.insert(&dryRun)) return constructExpandAndInsert(parent, args...); return nullptr; @@ -334,7 +346,7 @@ class ScopeCreator final { Args... args) { if (auto s = ifUniqueConstructExpandAndInsert(parent, args...)) return s.get(); - llvm_unreachable("Scope should have been unique"); + ASTScope_unreachable("Scope should have been unique"); } private: @@ -347,8 +359,8 @@ class ScopeCreator final { return ip; } ASTScopeImpl *insertionPoint = child->expandAndBeCurrent(*this); - assert(child->verifyThatThisNodeComeAfterItsPriorSibling() && - "Ensure search will work"); + ASTScopeAssert(child->verifyThatThisNodeComeAfterItsPriorSibling(), + "Ensure search will work"); return insertionPoint; } @@ -387,6 +399,7 @@ class ScopeCreator final { // A safe way to discover this, without creating a circular request. // Cannot call getAttachedPropertyWrappers. + // rdar://55263708 static bool hasAttachedPropertyWrapper(VarDecl *vd) { return AttachedPropertyWrapperScope::getSourceRangeOfVarDecl(vd).isValid(); } @@ -440,6 +453,24 @@ class ScopeCreator final { fn(specializeAttr); } + // SWIFT_ENABLE_TENSORFLOW + void forEachDifferentiableAttrInSourceOrder( + Decl *decl, function_ref fn) { + std::vector sortedDifferentiableAttrs; + for (auto *attr : decl->getAttrs()) + if (auto *diffAttr = dyn_cast(attr)) + // NOTE(TF-835): Skipping implicit `@differentiable` attributes is + // necessary to avoid verification failure: + // `ASTScopeImpl::verifyThatChildrenAreContainedWithin`. + // Perhaps this check is no longer necessary after TF-835: robust + // `@differentiating` attribute lowering. + if (!diffAttr->isImplicit()) + sortedDifferentiableAttrs.push_back(diffAttr); + for (auto *diffAttr : sortBySourceRange(sortedDifferentiableAttrs)) + fn(diffAttr); + } + // SWIFT_ENABLE_TENSORFLOW END + std::vector expandIfConfigClausesThenCullAndSortElementsOrMembers( ArrayRef input) const { auto cleanedupNodes = sortBySourceRange(cull(expandIfConfigClauses(input))); @@ -488,9 +519,8 @@ class ScopeCreator final { expansion.push_back(cond); if (clause.isActive) { // rdar://53922172 - assert(isInAnActiveNode && "Clause should not be marked " - "active unless it's context is " - "active"); + ASTScopeAssert(isInAnActiveNode, "Clause should not be marked active " + "unless it's context is active"); // get inactive nodes that nest in active clauses for (auto n : clause.Elements) { if (auto *const d = n.dyn_cast()) @@ -513,8 +543,9 @@ class ScopeCreator final { // When working on rdar://53971116 may have to cull more. std::vector culled; llvm::copy_if(input, std::back_inserter(culled), [&](ASTNode n) { - assert(!n.isDecl(DeclKind::Accessor) && - "Should not find accessors in iterable types or brace statements"); + ASTScopeAssert( + !n.isDecl(DeclKind::Accessor), + "Should not find accessors in iterable types or brace statements"); return isLocalizable(n) && !n.isDecl(DeclKind::Var) && !n.isDecl(DeclKind::EnumCase); }); @@ -577,13 +608,13 @@ class ScopeCreator final { dumpPBD(pbd, "prev"); if (auto *pbd = dyn_cast(d)) { dumpPBD(pbd, "curr"); - llvm_unreachable("found colliding pattern binding decls"); + ASTScope_unreachable("found colliding pattern binding decls"); } llvm::errs() << "Two same kind decls at same loc: \n"; lastD->dump(llvm::errs()); llvm::errs() << "and\n"; d->dump(llvm::errs()); - llvm_unreachable("Two same kind decls; unexpected kinds"); + ASTScope_unreachable("Two same kind decls; unexpected kinds"); } } @@ -617,7 +648,8 @@ class ScopeCreator final { dumpRangeable(n2, llvm::errs()); } #endif - assert(startOrder * endOrder != -1 && "Start order contradicts end order"); + ASTScopeAssert(startOrder * endOrder != -1, + "Start order contradicts end order"); return startOrder + endOrder < 1; } @@ -636,18 +668,18 @@ class ScopeCreator final { // they get created directly by the pattern code. // Doing otherwise distorts the source range // of their parents. - assert(!n.isDecl(DeclKind::Accessor) && "Should not see accessors here"); + ASTScopeAssert(!n.isDecl(DeclKind::Accessor), + "Should not see accessors here"); // Can occur in illegal code if (auto *const s = n.dyn_cast()) { if (auto *const bs = dyn_cast(s)) - assert(bs->getNumElements() == 0 && "Might mess up insertion point"); + ASTScopeAssert(bs->getNumElements() == 0, + "Might mess up insertion point"); } return !n.isDecl(DeclKind::Var); } - bool shouldBeLazy() const { - return !getIsFreezing() && ctx.LangOpts.LazyASTScopes; - } + bool shouldBeLazy() const { return ctx.LangOpts.LazyASTScopes; } public: /// For debugging. Return true if scope tree contains all the decl contexts in @@ -657,11 +689,9 @@ class ScopeCreator final { auto allDeclContexts = findLocalizableDeclContextsInAST(); llvm::DenseMap bogusDCs; bool rebuilt = false; - if (!getIsFrozen()) { - sourceFileScope->preOrderDo([&](ASTScopeImpl *scope) { - rebuilt |= scope->reexpandIfObsolete(*this); - }); - } + sourceFileScope->preOrderDo([&](ASTScopeImpl *scope) { + rebuilt |= scope->reexpandIfObsolete(*this); + }); sourceFileScope->postOrderDo([&](ASTScopeImpl *scope) { if (auto *dc = scope->getDeclContext().getPtrOrNull()) { auto iter = allDeclContexts.find(dc); @@ -730,7 +760,7 @@ class ScopeCreator final { void *operator new(size_t bytes, const ASTContext &ctx, unsigned alignment = alignof(ScopeCreator)); void *operator new(size_t Bytes, void *Mem) { - assert(Mem); + ASTScopeAssert(Mem, "Allocation failed"); return Mem; } }; @@ -741,36 +771,46 @@ class ScopeCreator final { ASTScope::ASTScope(SourceFile *SF) : impl(createScopeTree(SF)) {} -void ASTScope::buildScopeTreeEagerly() { - impl->buildScopeTreeEagerly(); +void ASTScope::buildFullyExpandedTree() { impl->buildFullyExpandedTree(); } + +void ASTScope:: + buildEnoughOfTreeForTopLevelExpressionsButDontRequestGenericsOrExtendedNominals() { + impl->buildEnoughOfTreeForTopLevelExpressionsButDontRequestGenericsOrExtendedNominals(); } ASTSourceFileScope *ASTScope::createScopeTree(SourceFile *SF) { ScopeCreator *scopeCreator = new (SF->getASTContext()) ScopeCreator(SF); - scopeCreator->sourceFileScope->addNewDeclsToScopeTree(); return scopeCreator->sourceFileScope; } -void ASTSourceFileScope::buildScopeTreeEagerly() { - scopeCreator->beFreezing(); - // Eagerly expand any decls already in the tree. - preOrderDo([&](ASTScopeImpl *s) { s->reexpandIfObsolete(*scopeCreator); }); +void ASTSourceFileScope::buildFullyExpandedTree() { + addNewDeclsToScopeTree(); + preOrderChildrenDo( + [&](ASTScopeImpl *s) { s->reexpandIfObsolete(*scopeCreator); }); +} + +void ASTSourceFileScope:: + buildEnoughOfTreeForTopLevelExpressionsButDontRequestGenericsOrExtendedNominals() { addNewDeclsToScopeTree(); - scopeCreator->beFrozen(); } void ASTSourceFileScope::addNewDeclsToScopeTree() { - assert(SF && scopeCreator); + ASTScopeAssert(SF && scopeCreator, + "Must already have a SourceFile and a ScopeCreator."); ArrayRef decls = SF->Decls; // Assume that decls are only added at the end, in source order ArrayRef newDecls = decls.slice(numberOfDeclsAlreadySeen); std::vector newNodes(newDecls.begin(), newDecls.end()); insertionPoint = - scopeCreator->addSiblingsToScopeTree(insertionPoint, newNodes); + scopeCreator->addSiblingsToScopeTree(insertionPoint, this, newNodes); + + // TODO: use regular expansion machinery for ASTSourceFileScope + // rdar://55562483 numberOfDeclsAlreadySeen = SF->Decls.size(); + setWasExpanded(); // Too slow to perform all the time: - // assert(scopeCreator->containsAllDeclContextsFromAST() && + // ASTScopeAssert(scopeCreator->containsAllDeclContextsFromAST(), // "ASTScope tree missed some DeclContexts or made some up"); } @@ -896,7 +936,7 @@ class NodeAdder #pragma mark special-case creation ASTScopeImpl *visitSourceFile(SourceFile *, ASTScopeImpl *, ScopeCreator &) { - llvm_unreachable("SourceFiles are orphans."); + ASTScope_unreachable("SourceFiles are orphans."); } NullablePtr visitYieldStmt(YieldStmt *ys, ASTScopeImpl *p, @@ -974,8 +1014,9 @@ class NodeAdder NullablePtr visitIfConfigDecl(IfConfigDecl *icd, ASTScopeImpl *p, ScopeCreator &scopeCreator) { - llvm_unreachable("Should be handled inside of " - "expandIfConfigClausesThenCullAndSortElementsOrMembers"); + ASTScope_unreachable( + "Should be handled inside of " + "expandIfConfigClausesThenCullAndSortElementsOrMembers"); } NullablePtr visitReturnStmt(ReturnStmt *rs, ASTScopeImpl *p, @@ -1040,6 +1081,15 @@ void ScopeCreator::addChildrenForAllLocalizableAccessorsInSourceOrder( return enclosingAbstractStorageDecl == ad->getStorage(); }); + // SWIFT_ENABLE_TENSORFLOW + // Create scopes for `@differentiable` attributes. + forEachDifferentiableAttrInSourceOrder( + asd, [&](DifferentiableAttr *diffAttr) { + ifUniqueConstructExpandAndInsert( + parent, diffAttr, asd); + }); + // SWIFT_ENABLE_TENSORFLOW END + // Sort in order to include synthesized ones, which are out of order. // Part of rdar://53921774 rm extra copy for (auto *accessor : sortBySourceRange(accessorsToScope)) @@ -1057,12 +1107,9 @@ void ASTScopeImpl::addChild(ASTScopeImpl *child, ASTContext &ctx) { haveAddedCleanup = true; } storedChildren.push_back(child); - assert(!child->getParent() && "child should not already have parent"); + ASTScopeAssert(!child->getParent(), "child should not already have parent"); child->parent = this; clearCachedSourceRangesOfMeAndAncestors(); - // It's possible that some callees do lookups back into the tree. - // So make sure childrenCountWhenLastExpanded is up to date. - setChildrenCountWhenLastExpanded(); } void ASTScopeImpl::removeChildren() { @@ -1084,11 +1131,17 @@ void ASTScopeImpl::disownDescendants(ScopeCreator &scopeCreator) { ASTScopeImpl *ASTScopeImpl::expandAndBeCurrent(ScopeCreator &scopeCreator) { auto *insertionPoint = expandSpecifically(scopeCreator); if (scopeCreator.shouldBeLazy()) { - assert(!insertionPointForDeferredExpansion() || - insertionPointForDeferredExpansion().get() == insertionPoint); - } + ASTScopeAssert(!insertionPointForDeferredExpansion() || + insertionPointForDeferredExpansion().get() == + insertionPoint, + "In order for lookups into lazily-expanded scopes to be " + "accurate before expansion, the insertion point before " + "expansion must be the same as after expansion."); + } + setWasExpanded(); beCurrent(); - assert(checkSourceRangeAfterExpansion(scopeCreator.getASTContext())); + ASTScopeAssert(checkSourceRangeAfterExpansion(scopeCreator.getASTContext()), + "Bad range."); return insertionPoint; } @@ -1144,6 +1197,9 @@ NO_EXPANSION(GenericParamScope) NO_EXPANSION(ASTSourceFileScope) NO_EXPANSION(ClosureParametersScope) NO_EXPANSION(SpecializeAttributeScope) +// SWIFT_ENABLE_TENSORFLOW +NO_EXPANSION(DifferentiableAttributeScope) +// SWIFT_ENABLE_TENSORFLOW END NO_EXPANSION(ConditionalClausePatternUseScope) NO_EXPANSION(LookupParentDiversionScope) @@ -1178,9 +1234,9 @@ PatternEntryDeclScope::expandAScopeThatCreatesANewInsertionPoint( // we cannot make a scope for it, since no source range. if (patternEntry.getOriginalInit() && isLocalizable(patternEntry.getOriginalInit())) { - assert( + ASTScopeAssert( !getSourceManager().isBeforeInBuffer( - patternEntry.getOriginalInit()->getStartLoc(), decl->getStartLoc()) && + patternEntry.getOriginalInit()->getStartLoc(), decl->getStartLoc()), "Original inits are always after the '='"); scopeCreator .constructExpandAndInsertUncheckable( @@ -1190,8 +1246,8 @@ PatternEntryDeclScope::expandAScopeThatCreatesANewInsertionPoint( forEachVarDeclWithLocalizableAccessors(scopeCreator, [&](VarDecl *var) { scopeCreator.ifUniqueConstructExpandAndInsert(this, var); }); - assert(!handleUseBeforeDef && - "next line is wrong otherwise; would need a use scope"); + ASTScopeAssert(!handleUseBeforeDef, + "next line is wrong otherwise; would need a use scope"); return {getParent().get(), "When not handling use-before-def, succeeding " "code just goes in the same scope as this one"}; @@ -1229,7 +1285,7 @@ ConditionalClauseScope::expandAScopeThatCreatesANewInsertionPoint( return {ccPatternUseScope, "Succeeding code must be in scope of conditional variables"}; } - llvm_unreachable("Unhandled StmtConditionKind in switch"); + ASTScope_unreachable("Unhandled StmtConditionKind in switch"); } AnnotatedInsertionPoint @@ -1262,7 +1318,7 @@ BraceStmtScope::expandAScopeThatCreatesANewInsertionPoint( ScopeCreator &scopeCreator) { // TODO: remove the sort after performing rdar://53254395 auto *insertionPoint = - scopeCreator.addSiblingsToScopeTree(this, stmt->getElements()); + scopeCreator.addSiblingsToScopeTree(this, this, stmt->getElements()); if (auto *s = scopeCreator.getASTContext().Stats) ++s->getFrontendCounters().NumBraceStmtASTScopeExpansions; return { @@ -1288,7 +1344,7 @@ TopLevelCodeScope::expandAScopeThatCreatesANewInsertionPoint(ScopeCreator & void ASTSourceFileScope::expandAScopeThatDoesNotCreateANewInsertionPoint( ScopeCreator &scopeCreator) { - llvm_unreachable("expanded by addNewDeclsToScopeTree()"); + ASTScope_unreachable("expanded by addNewDeclsToScopeTree()"); } // Create child scopes for every declaration in a body. @@ -1301,6 +1357,17 @@ void AbstractFunctionDeclScope::expandAScopeThatDoesNotCreateANewInsertionPoint( scopeCreator.ifUniqueConstructExpandAndInsert( this, specializeAttr, decl); }); + + // SWIFT_ENABLE_TENSORFLOW + // Create scopes for `@differentiable` attributes. + scopeCreator.forEachDifferentiableAttrInSourceOrder( + decl, [&](DifferentiableAttr *diffAttr) { + scopeCreator + .ifUniqueConstructExpandAndInsert( + this, diffAttr, decl); + }); + // SWIFT_ENABLE_TENSORFLOW END + // Create scopes for generic and ordinary parameters. // For a subscript declaration, the generic and ordinary parameters are in an // ancestor scope, so don't make them here. @@ -1483,7 +1550,8 @@ void DefaultArgumentInitializerScope:: expandAScopeThatDoesNotCreateANewInsertionPoint( ScopeCreator &scopeCreator) { auto *initExpr = decl->getDefaultValue(); - assert(initExpr); + ASTScopeAssert(initExpr, + "Default argument initializer must have an initializer."); scopeCreator.addToScopeTree(initExpr, this); } @@ -1598,8 +1666,8 @@ AbstractPatternEntryScope::AbstractPatternEntryScope( PatternBindingDecl *declBeingScoped, unsigned entryIndex, DeclVisibilityKind vis) : decl(declBeingScoped), patternEntryIndex(entryIndex), vis(vis) { - assert(entryIndex < declBeingScoped->getPatternList().size() && - "out of bounds"); + ASTScopeAssert(entryIndex < declBeingScoped->getPatternList().size(), + "out of bounds"); } void AbstractPatternEntryScope::forEachVarDeclWithLocalizableAccessors( @@ -1627,6 +1695,12 @@ NullablePtr SpecializeAttributeScope::getEnclosingAbstractStorageDecl() const { return getParent().get()->getEnclosingAbstractStorageDecl(); } +// SWIFT_ENABLE_TENSORFLOW +NullablePtr +DifferentiableAttributeScope::getEnclosingAbstractStorageDecl() const { + return getParent().get()->getEnclosingAbstractStorageDecl(); +} +// SWIFT_ENABLE_TENSORFLOW END NullablePtr AbstractFunctionDeclScope::getEnclosingAbstractStorageDecl() const { return getParent().get()->getEnclosingAbstractStorageDecl(); @@ -1648,7 +1722,8 @@ bool ASTScopeImpl::isATypeDeclScope() const { void ScopeCreator::forEachClosureIn( Expr *expr, function_ref, ClosureExpr *)> foundClosure) { - assert(expr); + ASTScopeAssert(expr, + "If looking for closures, must have an expression to search."); /// AST walker that finds top-level closures in an expression. class ClosureFinder : public ASTWalker { @@ -1719,7 +1794,7 @@ void GenericTypeOrExtensionScope::expandBody(ScopeCreator &) {} void IterableTypeScope::expandBody(ScopeCreator &scopeCreator) { auto nodes = asNodeVector(getIterableDeclContext().get()->getMembers()); - scopeCreator.addSiblingsToScopeTree(this, nodes); + scopeCreator.addSiblingsToScopeTree(this, this, nodes); if (auto *s = scopeCreator.getASTContext().Stats) ++s->getFrontendCounters().NumIterableTypeBodyASTScopeExpansions; } @@ -1727,19 +1802,22 @@ void IterableTypeScope::expandBody(ScopeCreator &scopeCreator) { #pragma mark - reexpandIfObsolete bool ASTScopeImpl::reexpandIfObsolete(ScopeCreator &scopeCreator) { - if (scopeCreator.getIsFrozen() || - (isCurrent() && - !scopeCreator.getASTContext().LangOpts.StressASTScopeLookup)) + if (isCurrent() && + !scopeCreator.getASTContext().LangOpts.StressASTScopeLookup) { + ASTScopeAssert(getWasExpanded(), "Cannot be current if unexpanded."); return false; + } reexpand(scopeCreator); return true; } void ASTScopeImpl::reexpand(ScopeCreator &scopeCreator) { - auto scopesToReuse = rescueScopesToReuse(); + auto astAncestorScopes = rescueASTAncestorScopesForReuseFromMeOrDescendants(); disownDescendants(scopeCreator); + // If the expansion recurses back into the tree for lookup, the ASTAncestor + // scopes will have already been rescued and won't be found! expandAndBeCurrent(scopeCreator); - addReusedScopes(scopesToReuse); + replaceASTAncestorScopes(astAncestorScopes); } #pragma mark getScopeCreator @@ -1771,6 +1849,9 @@ GET_REFERRENT(AbstractStmtScope, getStmt()) GET_REFERRENT(CaptureListScope, getExpr()) GET_REFERRENT(WholeClosureScope, getExpr()) GET_REFERRENT(SpecializeAttributeScope, specializeAttr) +// SWIFT_ENABLE_TENSORFLOW +GET_REFERRENT(DifferentiableAttributeScope, differentiableAttr) +// SWIFT_ENABLE_TENSORFLOW END GET_REFERRENT(GenericTypeOrExtensionScope, portion->getReferrentOfScope(this)); const Decl * @@ -1799,8 +1880,15 @@ NullablePtr IterableTypeScope::insertionPointForDeferredExpansion() { return portion->insertionPointForDeferredExpansion(this); } + +NullablePtr +GenericTypeOrExtensionWholePortion::insertionPointForDeferredExpansion( + IterableTypeScope *s) const { + return s->getParent().get(); +} NullablePtr -Portion::insertionPointForDeferredExpansion(IterableTypeScope *) const { +GenericTypeOrExtensionWherePortion::insertionPointForDeferredExpansion( + IterableTypeScope *) const { return nullptr; } NullablePtr @@ -1809,23 +1897,46 @@ IterableTypeBodyPortion::insertionPointForDeferredExpansion( return s->getParent().get(); } +bool ASTScopeImpl::isCurrent() const { + return getWasExpanded() && isCurrentIfWasExpanded(); +} void ASTScopeImpl::beCurrent() {} -bool ASTScopeImpl::isCurrent() const { return true; } +bool ASTScopeImpl::isCurrentIfWasExpanded() const { return true; } void IterableTypeScope::beCurrent() { portion->beCurrent(this); } -bool IterableTypeScope::isCurrent() const { return portion->isCurrent(this); } - -void Portion::beCurrent(IterableTypeScope *) const {} -bool Portion::isCurrent(const IterableTypeScope *) const { return true; } +bool IterableTypeScope::isCurrentIfWasExpanded() const { + return portion->isCurrentIfWasExpanded(this); +} +void GenericTypeOrExtensionWholePortion::beCurrent(IterableTypeScope *s) const { + s->makeWholeCurrent(); +} +bool GenericTypeOrExtensionWholePortion::isCurrentIfWasExpanded( + const IterableTypeScope *s) const { + return s->isWholeCurrent(); +} +void GenericTypeOrExtensionWherePortion::beCurrent(IterableTypeScope *) const {} +bool GenericTypeOrExtensionWherePortion::isCurrentIfWasExpanded( + const IterableTypeScope *) const { + return true; +} void IterableTypeBodyPortion::beCurrent(IterableTypeScope *s) const { s->makeBodyCurrent(); } -bool IterableTypeBodyPortion::isCurrent(const IterableTypeScope *s) const { +bool IterableTypeBodyPortion::isCurrentIfWasExpanded( + const IterableTypeScope *s) const { return s->isBodyCurrent(); } +void IterableTypeScope::makeWholeCurrent() { + ASTScopeAssert(getWasExpanded(), "Should have been expanded"); +} +bool IterableTypeScope::isWholeCurrent() const { + // Whole starts out unexpanded, and is lazily built but will have at least a + // body scope child + return getWasExpanded(); +} void IterableTypeScope::makeBodyCurrent() { memberCount = getIterableDeclContext().get()->getMemberCount(); } @@ -1836,13 +1947,12 @@ bool IterableTypeScope::isBodyCurrent() const { void AbstractFunctionBodyScope::beCurrent() { bodyWhenLastExpanded = decl->getBody(false); } -bool AbstractFunctionBodyScope::isCurrent() const { +bool AbstractFunctionBodyScope::isCurrentIfWasExpanded() const { return bodyWhenLastExpanded == decl->getBody(false); - ; } void TopLevelCodeScope::beCurrent() { bodyWhenLastExpanded = decl->getBody(); } -bool TopLevelCodeScope::isCurrent() const { +bool TopLevelCodeScope::isCurrentIfWasExpanded() const { return bodyWhenLastExpanded == decl->getBody(); } @@ -1861,11 +1971,12 @@ void PatternEntryDeclScope::beCurrent() { return; varCountWhenLastExpanded = countVars(getPatternEntry()); } -bool PatternEntryDeclScope::isCurrent() const { +bool PatternEntryDeclScope::isCurrentIfWasExpanded() const { if (initWhenLastExpanded != getPatternEntry().getOriginalInit()) return false; if (assumeVarsDoNotGetAdded && varCountWhenLastExpanded) { - assert(varCountWhenLastExpanded == countVars(getPatternEntry())); + ASTScopeAssert(varCountWhenLastExpanded == countVars(getPatternEntry()), + "Vars were not supposed to be added to a pattern entry."); return true; } return countVars(getPatternEntry()) == varCountWhenLastExpanded; @@ -1874,62 +1985,69 @@ bool PatternEntryDeclScope::isCurrent() const { void WholeClosureScope::beCurrent() { bodyWhenLastExpanded = closureExpr->getBody(); } -bool WholeClosureScope::isCurrent() const { +bool WholeClosureScope::isCurrentIfWasExpanded() const { return bodyWhenLastExpanded == closureExpr->getBody(); } -#pragma mark getParentOfRescuedScopes -NullablePtr ASTScopeImpl::getParentOfRescuedScopes() { +#pragma mark getParentOfASTAncestorScopesToBeRescued +NullablePtr +ASTScopeImpl::getParentOfASTAncestorScopesToBeRescued() { return this; } NullablePtr -AbstractFunctionBodyScope::getParentOfRescuedScopes() { +AbstractFunctionBodyScope::getParentOfASTAncestorScopesToBeRescued() { // Reexpansion always creates a new body as the first child + // That body contains the scopes to be rescued. return getChildren().empty() ? nullptr : getChildren().front(); } -NullablePtr TopLevelCodeScope::getParentOfRescuedScopes() { +NullablePtr +TopLevelCodeScope::getParentOfASTAncestorScopesToBeRescued() { // Reexpansion always creates a new body as the first child + // That body contains the scopes to be rescued. return getChildren().empty() ? nullptr : getChildren().front(); } #pragma mark rescuing & reusing -std::vector ASTScopeImpl::rescueScopesToReuse() { - if (auto *p = getParentOfRescuedScopes().getPtrOrNull()) { - return p->rescueYoungestChildren(p->getChildren().size() - - p->childrenCountWhenLastExpanded); +std::vector +ASTScopeImpl::rescueASTAncestorScopesForReuseFromMeOrDescendants() { + if (auto *p = getParentOfASTAncestorScopesToBeRescued().getPtrOrNull()) { + return p->rescueASTAncestorScopesForReuseFromMe(); } + ASTScopeAssert( + getASTAncestorScopeCount() == 0, + "If receives ASTAncestor scopes, must know where to find parent"); return {}; } -void ASTScopeImpl::addReusedScopes(ArrayRef scopesToAdd) { - auto *p = getParentOfRescuedScopes().getPtrOrNull(); +void ASTScopeImpl::replaceASTAncestorScopes( + ArrayRef scopesToAdd) { + auto *p = getParentOfASTAncestorScopesToBeRescued().getPtrOrNull(); if (!p) { - assert(scopesToAdd.empty() && "Non-empty body disappeared?!"); + ASTScopeAssert(scopesToAdd.empty(), "Non-empty body disappeared?!"); return; } auto &ctx = getASTContext(); for (auto *s : scopesToAdd) { p->addChild(s, ctx); - assert(s->verifyThatThisNodeComeAfterItsPriorSibling() && - "Ensure search will work"); + ASTScopeAssert(s->verifyThatThisNodeComeAfterItsPriorSibling(), + "Ensure search will work"); } + p->increaseASTAncestorScopeCount(scopesToAdd.size()); } std::vector -ASTScopeImpl::rescueYoungestChildren(const unsigned int count) { - std::vector youngestChildren; - for (unsigned i = getChildren().size() - count; i < getChildren().size(); ++i) - youngestChildren.push_back(getChildren()[i]); +ASTScopeImpl::rescueASTAncestorScopesForReuseFromMe() { + std::vector astAncestorScopes; + for (unsigned i = getChildren().size() - getASTAncestorScopeCount(); + i < getChildren().size(); ++i) + astAncestorScopes.push_back(getChildren()[i]); // So they don't get disowned and children cleared. - for (unsigned i = 0; i < count; ++i) { + for (unsigned i = 0; i < getASTAncestorScopeCount(); ++i) { storedChildren.back()->emancipate(); storedChildren.pop_back(); } - return youngestChildren; -} - -void ASTScopeImpl::setChildrenCountWhenLastExpanded() { - childrenCountWhenLastExpanded = getChildren().size(); + resetASTAncestorScopeCount(); + return astAncestorScopes; } bool AbstractFunctionDeclScope::shouldCreateAccessorScope( diff --git a/lib/AST/ASTScopeLookup.cpp b/lib/AST/ASTScopeLookup.cpp index 7db3b840963b7..115542bbcef6a 100644 --- a/lib/AST/ASTScopeLookup.cpp +++ b/lib/AST/ASTScopeLookup.cpp @@ -25,6 +25,7 @@ #include "swift/AST/NameLookup.h" #include "swift/AST/ParameterList.h" #include "swift/AST/Pattern.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/Stmt.h" #include "swift/AST/TypeRepr.h" #include "swift/Basic/STLExtras.h" @@ -63,6 +64,8 @@ const ASTScopeImpl *ASTScopeImpl::findStartingScopeForLookup( return fileScope; // operators always at file scope const auto innermost = fileScope->findInnermostEnclosingScope(loc, nullptr); + ASTScopeAssert(innermost->getWasExpanded(), + "If looking in a scope, it must have been expanded."); // The legacy lookup code gets passed both a SourceLoc and a starting context. // However, our ultimate intent is for clients to not have to pass in a @@ -94,10 +97,12 @@ const ASTScopeImpl *ASTScopeImpl::findStartingScopeForLookup( // fileScope->dump(); llvm::errs() << "\n\n"; - assert(fileScope->crossCheckWithAST()); + // Might distort things + // if (fileScope->crossCheckWithAST()) + // llvm::errs() << "Tree creation missed some DeclContexts.\n"; } - assert(startingScope && "ASTScopeImpl: could not find startingScope"); + ASTScopeAssert(startingScope, "ASTScopeImpl: could not find startingScope"); return startingScope; } @@ -122,7 +127,8 @@ const ASTScopeImpl *ASTScopeImpl::findInnermostEnclosingScopeImpl( bool ASTScopeImpl::checkSourceRangeOfThisASTNode() const { const auto r = getSourceRangeOfThisASTNode(); (void)r; - assert(!getSourceManager().isBeforeInBuffer(r.End, r.Start)); + ASTScopeAssert(!getSourceManager().isBeforeInBuffer(r.End, r.Start), + "Range is backwards."); return true; } @@ -134,12 +140,12 @@ ASTScopeImpl::findChildContaining(SourceLoc loc, SourceManager &sourceMgr; bool operator()(const ASTScopeImpl *scope, SourceLoc loc) { - assert(scope->checkSourceRangeOfThisASTNode()); + ASTScopeAssert(scope->checkSourceRangeOfThisASTNode(), "Bad range."); return sourceMgr.isBeforeInBuffer(scope->getSourceRangeOfScope().End, loc); } bool operator()(SourceLoc loc, const ASTScopeImpl *scope) { - assert(scope->checkSourceRangeOfThisASTNode()); + ASTScopeAssert(scope->checkSourceRangeOfThisASTNode(), "Bad range."); return sourceMgr.isBeforeInBuffer(loc, scope->getSourceRangeOfScope().End); } @@ -168,7 +174,7 @@ bool ASTScopeImpl::doesContextMatchStartingContext( if (auto p = getParent()) return p.get()->doesContextMatchStartingContext(context); // Topmost scope always has a context, the SourceFile. - llvm_unreachable("topmost scope always has a context, the SourceFile"); + ASTScope_unreachable("topmost scope always has a context, the SourceFile"); } // For a SubscriptDecl with generic parameters, the call tries to do lookups @@ -188,6 +194,21 @@ bool GenericParamScope::doesContextMatchStartingContext( return false; } +// SWIFT_ENABLE_TENSORFLOW +bool DifferentiableAttributeScope::doesContextMatchStartingContext( + const DeclContext *context) const { + // Need special logic to handle case where `attributedDeclaration` is an + // `AbstractStorageDecl` (`SubscriptDecl` or `VarDecl`). The initial starting + // context in `ASTScopeImpl::findStartingScopeForLookup` will be an accessor + // of the `attributedDeclaration`. + if (auto *asd = dyn_cast(attributedDeclaration)) + for (auto accessor : asd->getAllAccessors()) + if (up_cast(accessor) == context) + return true; + return false; +} +// SWIFT_ENABLE_TENSORFLOW END + #pragma mark lookup methods that run once per scope void ASTScopeImpl::lookup(SmallVectorImpl &history, @@ -382,7 +403,7 @@ bool AbstractFunctionBodyScope::lookupLocalsOrMembers( bool MethodBodyScope::lookupLocalsOrMembers( ArrayRef history, DeclConsumer consumer) const { - assert(isAMethod(decl)); + ASTScopeAssert(isAMethod(decl), "Asking for members of a non-method."); if (AbstractFunctionBodyScope::lookupLocalsOrMembers(history, consumer)) return true; return consumer.consume({decl->getImplicitSelfDecl()}, @@ -391,7 +412,9 @@ bool MethodBodyScope::lookupLocalsOrMembers( bool PureFunctionBodyScope::lookupLocalsOrMembers( ArrayRef history, DeclConsumer consumer) const { - assert(!isAMethod(decl)); + ASTScopeAssert( + !isAMethod(decl), + "Should have called lookupLocalsOrMembers instead of this function."); if (AbstractFunctionBodyScope::lookupLocalsOrMembers(history, consumer)) return true; @@ -416,6 +439,27 @@ bool SpecializeAttributeScope::lookupLocalsOrMembers( return false; } +// SWIFT_ENABLE_TENSORFLOW +bool DifferentiableAttributeScope::lookupLocalsOrMembers( + ArrayRef, DeclConsumer consumer) const { + auto visitAbstractFunctionDecl = [&](AbstractFunctionDecl *afd) { + if (auto *params = afd->getGenericParams()) + for (auto *param : params->getParams()) + if (consumer.consume({param}, DeclVisibilityKind::GenericParameter)) + return true; + return false; + }; + if (auto *afd = dyn_cast(attributedDeclaration)) { + return visitAbstractFunctionDecl(afd); + } else if (auto *asd = dyn_cast(attributedDeclaration)) { + for (auto *accessor : asd->getAllAccessors()) + if (visitAbstractFunctionDecl(accessor)) + return true; + } + return false; +} +// SWIFT_ENABLE_TENSORFLOW END + bool BraceStmtScope::lookupLocalsOrMembers(ArrayRef, DeclConsumer consumer) const { // All types and functions are visible anywhere within a brace statement @@ -490,7 +534,7 @@ bool ASTScopeImpl::lookupLocalBindingsInPattern(Pattern *p, NullablePtr GenericTypeOrExtensionWhereOrBodyPortion::computeSelfDC( ArrayRef history) { - assert(history.size() != 0 && "includes current scope"); + ASTScopeAssert(history.size() != 0, "includes current scope"); size_t i = history.size() - 1; // skip last entry (this scope) while (i != 0) { Optional> maybeSelfDC = @@ -631,7 +675,7 @@ Optional GenericParamScope::resolveIsCascadingUseForThisScope( Optional isCascadingUse) const { if (auto *dc = getDeclContext().getPtrOrNull()) return ifUnknownIsCascadingUseAccordingTo(isCascadingUse, dc); - llvm_unreachable("generic what?"); + ASTScope_unreachable("generic what?"); } Optional AbstractFunctionDeclScope::resolveIsCascadingUseForThisScope( diff --git a/lib/AST/ASTScopePrinting.cpp b/lib/AST/ASTScopePrinting.cpp index e6adb04afdc2e..670b7de5fd1db 100644 --- a/lib/AST/ASTScopePrinting.cpp +++ b/lib/AST/ASTScopePrinting.cpp @@ -24,6 +24,7 @@ #include "swift/AST/Module.h" #include "swift/AST/ParameterList.h" #include "swift/AST/Pattern.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/Stmt.h" #include "swift/AST/TypeRepr.h" #include "swift/Basic/STLExtras.h" diff --git a/lib/AST/ASTScopeSourceRange.cpp b/lib/AST/ASTScopeSourceRange.cpp index 47d5fb869dd6d..3742a4be884ce 100644 --- a/lib/AST/ASTScopeSourceRange.cpp +++ b/lib/AST/ASTScopeSourceRange.cpp @@ -24,6 +24,7 @@ #include "swift/AST/Module.h" #include "swift/AST/ParameterList.h" #include "swift/AST/Pattern.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/Stmt.h" #include "swift/AST/TypeRepr.h" #include "swift/Basic/STLExtras.h" @@ -37,6 +38,7 @@ using namespace ast_scope; static SourceLoc getStartOfFirstParam(ClosureExpr *closure); static SourceLoc getLocEncompassingPotentialLookups(const SourceManager &, SourceLoc endLoc); +static SourceLoc getLocAfterExtendedNominal(const ExtensionDecl *); SourceRange ASTScopeImpl::widenSourceRangeForIgnoredASTNodes( const SourceRange range) const { @@ -52,7 +54,7 @@ SourceRange ASTScopeImpl::widenSourceRangeForChildren(const SourceRange range, const bool omitAssertions) const { if (getChildren().empty()) { - assert(omitAssertions || range.Start.isValid()); + ASTScopeAssert(omitAssertions || range.Start.isValid(), "Bad range."); return range; } const auto childStart = @@ -60,7 +62,7 @@ ASTScopeImpl::widenSourceRangeForChildren(const SourceRange range, const auto childEnd = getChildren().back()->getSourceRangeOfScope(omitAssertions).End; auto childRange = SourceRange(childStart, childEnd); - assert(omitAssertions || childRange.isValid()); + ASTScopeAssert(omitAssertions || childRange.isValid(), "Bad range."); if (range.isInvalid()) return childRange; @@ -70,12 +72,14 @@ ASTScopeImpl::widenSourceRangeForChildren(const SourceRange range, } bool ASTScopeImpl::checkSourceRangeAfterExpansion(const ASTContext &ctx) const { - assert((getSourceRangeOfThisASTNode().isValid() || !getChildren().empty()) && - "need to be able to find source range"); - assert(verifyThatChildrenAreContainedWithin(getSourceRangeOfScope()) && - "Search will fail"); - assert(checkLazySourceRange(ctx) && - "Lazy scopes must have compatible ranges before and after expansion"); + ASTScopeAssert(getSourceRangeOfThisASTNode().isValid() || + !getChildren().empty(), + "need to be able to find source range"); + ASTScopeAssert(verifyThatChildrenAreContainedWithin(getSourceRangeOfScope()), + "Search will fail"); + ASTScopeAssert( + checkLazySourceRange(ctx), + "Lazy scopes must have compatible ranges before and after expansion"); return true; } @@ -143,7 +147,7 @@ bool ASTScopeImpl::verifyThatThisNodeComeAfterItsPriorSibling() const { // .getRangeForBuffer( // getSourceFile()->getBufferID().getValue()) // .str(); - llvm_unreachable("unexpected out-of-order nodes"); + ASTScope_unreachable("unexpected out-of-order nodes"); return false; } @@ -160,7 +164,7 @@ NullablePtr ASTScopeImpl::getPriorSibling() const { break; } } - assert(myIndex != -1 && "I have been disowned!"); + ASTScopeAssert(myIndex != -1, "I have been disowned!"); if (myIndex == 0) return nullptr; return siblingsAndMe[myIndex - 1]; @@ -189,6 +193,13 @@ SourceRange SpecializeAttributeScope::getSourceRangeOfThisASTNode( return specializeAttr->getRange(); } +// SWIFT_ENABLE_TENSORFLOW +SourceRange DifferentiableAttributeScope::getSourceRangeOfThisASTNode( + const bool omitAssertions) const { + return differentiableAttr->getRange(); +} +// SWIFT_ENABLE_TENSORFLOW END + SourceRange AbstractFunctionBodyScope::getSourceRangeOfThisASTNode( const bool omitAssertions) const { return decl->getBodySourceRange(); @@ -262,10 +273,15 @@ SourceRange GenericParamScope::getSourceRangeOfThisASTNode( // is visible from the start of the body. if (auto *protoDecl = dyn_cast(nOrE)) return SourceRange(protoDecl->getBraces().Start, protoDecl->getEndLoc()); - auto startLoc = paramList->getSourceRange().Start; - if (startLoc.isInvalid()) - startLoc = holder->getStartLoc(); - return SourceRange(startLoc, holder->getEndLoc()); + const auto startLoc = paramList->getSourceRange().Start; + const auto validStartLoc = + startLoc.isValid() ? startLoc : holder->getStartLoc(); + // Since ExtensionScope (whole portion) range doesn't start till after the + // extended nominal, the range here must be pushed back, too. + if (auto const *const ext = dyn_cast(holder)) { + return SourceRange(getLocAfterExtendedNominal(ext), ext->getEndLoc()); + } + return SourceRange(validStartLoc, holder->getEndLoc()); } SourceRange ASTSourceFileScope::getSourceRangeOfThisASTNode( @@ -293,12 +309,28 @@ SourceRange GenericTypeOrExtensionWholePortion::getChildlessSourceRangeOf( auto *d = scope->getDecl(); auto r = d->getSourceRangeIncludingAttrs(); if (r.Start.isValid()) { - assert(r.End.isValid()); - return r; + ASTScopeAssert(r.End.isValid(), "Start valid imples end valid."); + return scope->moveStartPastExtendedNominal(r); } return d->getSourceRange(); } +SourceRange +ExtensionScope::moveStartPastExtendedNominal(const SourceRange sr) const { + const auto start = getLocAfterExtendedNominal(decl); + // Illegal code can have an endLoc that is before the end of the + // ExtendedNominal, so push the end back, too, in that case. + const auto end = + getSourceManager().isBeforeInBuffer(sr.End, start) ? start : sr.End; + return SourceRange(start, end); +} + +SourceRange +GenericTypeScope::moveStartPastExtendedNominal(const SourceRange sr) const { + // There is no extended nominal + return sr; +} + SourceRange GenericTypeOrExtensionWherePortion::getChildlessSourceRangeOf( const GenericTypeOrExtensionScope *scope, const bool omitAssertions) const { return scope->getGenericContext()->getTrailingWhereClause()->getSourceRange(); @@ -313,7 +345,7 @@ SourceRange IterableTypeBodyPortion::getChildlessSourceRangeOf( return e->getBraces(); if (omitAssertions) return SourceRange(); - llvm_unreachable("No body!"); + ASTScope_unreachable("No body!"); } SourceRange AbstractFunctionDeclScope::getSourceRangeOfThisASTNode( @@ -322,7 +354,7 @@ SourceRange AbstractFunctionDeclScope::getSourceRangeOfThisASTNode( // them at the start location of the accessor. auto r = decl->getSourceRangeIncludingAttrs(); if (r.Start.isValid()) { - assert(r.End.isValid()); + ASTScopeAssert(r.End.isValid(), "Start valid imples end valid."); return r; } return decl->getBodySourceRange(); @@ -334,9 +366,9 @@ SourceRange ParameterListScope::getSourceRangeOfThisASTNode( getSourceRangeOfEnclosedParamsOfASTNode(omitAssertions); auto r = SourceRange(rangeForGoodInput.Start, fixupEndForBadInput(rangeForGoodInput)); - assert(getSourceManager().rangeContains( - getParent().get()->getSourceRangeOfThisASTNode(true), r) && - "Parameters not within function?!"); + ASTScopeAssert(getSourceManager().rangeContains( + getParent().get()->getSourceRangeOfThisASTNode(true), r), + "Parameters not within function?!"); return r; } @@ -423,8 +455,8 @@ CaptureListScope::getSourceRangeOfThisASTNode(const bool omitAssertions) const { SourceRange ClosureParametersScope::getSourceRangeOfThisASTNode( const bool omitAssertions) const { if (!omitAssertions) - assert(closureExpr->getInLoc().isValid() && - "We don't create these if no in loc"); + ASTScopeAssert(closureExpr->getInLoc().isValid(), + "We don't create these if no in loc"); return SourceRange(getStartOfFirstParam(closureExpr), closureExpr->getInLoc()); } @@ -458,7 +490,9 @@ ASTScopeImpl::getSourceRangeOfScope(const bool omitAssertions) const { bool ASTScopeImpl::isSourceRangeCached(const bool omitAssertions) const { const bool isCached = cachedSourceRange.hasValue(); - assert(omitAssertions || isCached || ensureNoAncestorsSourceRangeIsCached()); + ASTScopeAssert(omitAssertions || isCached || + ensureNoAncestorsSourceRangeIsCached(), + "Cached ancestor's range likely is obsolete."); return isCached; } @@ -467,7 +501,7 @@ bool ASTScopeImpl::ensureNoAncestorsSourceRangeIsCached() const { auto r = !p->isSourceRangeCached(true) && p->ensureNoAncestorsSourceRangeIsCached(); if (!r) - llvm_unreachable("found a violation"); + ASTScope_unreachable("found a violation"); return true; } return true; @@ -553,8 +587,12 @@ static bool isInterpolatedStringLiteral(const Token& tok) { Segments.front().Kind != Lexer::StringSegment::Literal; } -// If right brace is missing, the source range of the body will end -// at the last token, which may be a one of the special cases below. +/// If right brace is missing, the source range of the body will end +/// at the last token, which may be a one of the special cases below. +/// This work is only needed for *unexpanded* scopes because unioning the range +/// with the children will do the same thing for an expanded scope. +/// It is also needed for ignored \c ASTNodes, which may be, e.g. \c +/// InterpolatedStringLiterals static SourceLoc getLocEncompassingPotentialLookups(const SourceManager &SM, const SourceLoc endLoc) { const auto tok = Lexer::getTokenAtLocation(SM, endLoc); @@ -587,11 +625,33 @@ SourceRange AbstractFunctionBodyScope::sourceRangeForDeferredExpansion() const { return SourceRange(bsr.Start, endEvenIfNoCloseBraceAndEndsWithInterpolatedStringLiteral); } -SourceRange -Portion::sourceRangeForDeferredExpansion(const IterableTypeScope *) const { + +SourceRange GenericTypeOrExtensionWholePortion::sourceRangeForDeferredExpansion( + const IterableTypeScope *s) const { + const auto rangeOfThisNodeWithoutChildren = + getChildlessSourceRangeOf(s, false); + const auto rangeExtendedForFinalToken = SourceRange( + rangeOfThisNodeWithoutChildren.Start, + getLocEncompassingPotentialLookups(s->getSourceManager(), + rangeOfThisNodeWithoutChildren.End)); + const auto rangePastExtendedNominal = + s->moveStartPastExtendedNominal(rangeExtendedForFinalToken); + return rangePastExtendedNominal; +} + +SourceRange GenericTypeOrExtensionWherePortion::sourceRangeForDeferredExpansion( + const IterableTypeScope *) const { return SourceRange(); } +SourceRange IterableTypeBodyPortion::sourceRangeForDeferredExpansion( + const IterableTypeScope *s) const { + const auto bracesRange = getChildlessSourceRangeOf(s, false); + return SourceRange(bracesRange.Start, + getLocEncompassingPotentialLookups(s->getSourceManager(), + bracesRange.End)); +} + SourceRange ASTScopeImpl::getEffectiveSourceRange(const ASTNode n) const { if (const auto *d = n.dyn_cast()) return d->getSourceRange(); @@ -695,12 +755,11 @@ AbstractFunctionDeclScope::getParmsSourceLocOfAFD(AbstractFunctionDecl *decl) { // clang-format on } -#pragma mark deferred scope source ranges - -SourceRange IterableTypeBodyPortion::sourceRangeForDeferredExpansion( - const IterableTypeScope *s) const { - const auto bracesRange = getChildlessSourceRangeOf(s, false); - const auto &SM = s->getSourceManager(); - return SourceRange(bracesRange.Start, - getLocEncompassingPotentialLookups(SM, bracesRange.End)); +SourceLoc getLocAfterExtendedNominal(const ExtensionDecl *const ext) { + const auto *const etr = ext->getExtendedTypeRepr(); + if (!etr) + return ext->getStartLoc(); + const auto &SM = ext->getASTContext().SourceMgr; + return Lexer::getCharSourceRangeFromSourceRange(SM, etr->getSourceRange()) + .getEnd(); } diff --git a/lib/AST/ASTVerifier.cpp b/lib/AST/ASTVerifier.cpp index 54d0d957fa50a..414d4ee2fbad3 100644 --- a/lib/AST/ASTVerifier.cpp +++ b/lib/AST/ASTVerifier.cpp @@ -29,6 +29,7 @@ #include "swift/AST/Pattern.h" #include "swift/AST/PrettyStackTrace.h" #include "swift/AST/ProtocolConformance.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/Stmt.h" #include "swift/Basic/SourceManager.h" #include "swift/Subsystems.h" @@ -167,15 +168,16 @@ std::pair dispatchVisitPreExprHelper( } namespace { - /// Retrieve the "overridden" declaration of this declaration, but only if - // it's already been computed. - template - T *getOverriddenDeclIfAvailable(T *decl) { - if (!decl->overriddenDeclsComputed()) return nullptr; +// Retrieve the "overridden" declaration of this declaration, but only if +// it's already been computed. +template T *getOverriddenDeclIfAvailable(T *decl) { + if (!decl->overriddenDeclsComputed()) + return nullptr; - return cast_or_null(decl->getOverriddenDecl()); - } + return cast_or_null(decl->getOverriddenDecl()); } +} // namespace + class Verifier : public ASTWalker { PointerUnion M; ASTContext &Ctx; @@ -190,8 +192,9 @@ class Verifier : public ASTWalker { using ScopeLike = llvm::PointerUnion; SmallVector Scopes; - /// The stack of context generic signatures. - SmallVector GenericSig; + /// The stack of generic contexts. + using GenericLike = llvm::PointerUnion; + SmallVector Generics; /// The stack of optional evaluations active at this point. SmallVector OptionalEvaluations; @@ -614,7 +617,7 @@ class Verifier : public ASTWalker { } // Otherwise, the archetype needs to be from this scope. - if (GenericSig.empty() || !GenericSig.back()) { + if (Generics.empty() || !Generics.back()) { Out << "AST verification error: archetype outside of generic " "context: " << root->getString() << "\n"; return true; @@ -625,13 +628,20 @@ class Verifier : public ASTWalker { auto *archetypeEnv = rootPrimary->getGenericEnvironment(); auto *archetypeSig = archetypeEnv->getGenericSignature(); - if (GenericSig.back() != archetypeSig) { + auto genericCtx = Generics.back(); + GenericSignature *genericSig; + if (auto *genericDC = genericCtx.dyn_cast()) + genericSig = genericDC->getGenericSignatureOfContext(); + else + genericSig = genericCtx.get(); + + if (genericSig != archetypeSig) { Out << "Archetype " << root->getString() << " not allowed " << "in this context\n"; Out << "Archetype generic signature: " << archetypeSig->getAsString() << "\n"; Out << "Context generic signature: " - << GenericSig.back()->getAsString() << "\n"; + << genericSig->getAsString() << "\n"; return true; } @@ -686,16 +696,16 @@ class Verifier : public ASTWalker { void pushScope(DeclContext *scope) { Scopes.push_back(scope); - GenericSig.push_back(scope->getGenericSignatureOfContext()); + Generics.push_back(scope); } void pushScope(BraceStmt *scope) { Scopes.push_back(scope); } void popScope(DeclContext *scope) { assert(Scopes.back().get() == scope); - assert(GenericSig.back() == scope->getGenericSignatureOfContext()); + assert(Generics.back().get() == scope); Scopes.pop_back(); - GenericSig.pop_back(); + Generics.pop_back(); } void popScope(BraceStmt *scope) { assert(Scopes.back().get() == scope); @@ -2669,14 +2679,15 @@ class Verifier : public ASTWalker { const auto &witness = normal->getWitness(req); if (auto *genericEnv = witness.getSyntheticEnvironment()) - GenericSig.push_back(genericEnv->getGenericSignature()); + Generics.push_back(genericEnv->getGenericSignature()); verifyChecked(witness.getRequirementToSyntheticSubs()); verifyChecked(witness.getSubstitutions()); if (auto *genericEnv = witness.getSyntheticEnvironment()) { - assert(GenericSig.back() == genericEnv->getGenericSignature()); - GenericSig.pop_back(); + assert(Generics.back().get() + == genericEnv->getGenericSignature()); + Generics.pop_back(); } continue; @@ -2957,7 +2968,7 @@ class Verifier : public ASTWalker { void verifyChecked(AbstractFunctionDecl *AFD) { PrettyStackTraceDecl debugStack("verifying AbstractFunctionDecl", AFD); - if (!AFD->hasValidSignature()) { + if (!AFD->hasInterfaceType()) { if (isa(AFD) && AFD->isImplicit()) return; diff --git a/lib/AST/ASTWalker.cpp b/lib/AST/ASTWalker.cpp index 940191ca732a3..b159130bfa2d7 100644 --- a/lib/AST/ASTWalker.cpp +++ b/lib/AST/ASTWalker.cpp @@ -232,7 +232,10 @@ class Traversal : public ASTVisitorgetUnderlyingTypeLoc()); + if (auto typerepr = TAD->getUnderlyingTypeRepr()) + if (doIt(typerepr)) + return true; + return false; } bool visitOpaqueTypeDecl(OpaqueTypeDecl *OTD) { diff --git a/lib/AST/AccessRequests.cpp b/lib/AST/AccessRequests.cpp index 0a20c266bf755..f3fc0de11f186 100644 --- a/lib/AST/AccessRequests.cpp +++ b/lib/AST/AccessRequests.cpp @@ -17,6 +17,7 @@ #include "swift/AST/DiagnosticsCommon.h" #include "swift/AST/Module.h" #include "swift/AST/NameLookupRequests.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/Types.h" #include "llvm/Support/MathExtras.h" diff --git a/lib/AST/Builtins.cpp b/lib/AST/Builtins.cpp index e48f65069a02e..e137818554cd0 100644 --- a/lib/AST/Builtins.cpp +++ b/lib/AST/Builtins.cpp @@ -16,6 +16,7 @@ #include "swift/AST/Builtins.h" #include "swift/AST/ASTContext.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/GenericEnvironment.h" #include "swift/AST/GenericSignatureBuilder.h" #include "swift/AST/Module.h" @@ -1283,6 +1284,15 @@ static ValueDecl *getOnceOperation(ASTContext &Context, } } +static ValueDecl *getPolymorphicBinaryOperation(ASTContext &ctx, + Identifier id) { + BuiltinGenericSignatureBuilder builder(ctx); + builder.addParameter(makeGenericParam()); + builder.addParameter(makeGenericParam()); + builder.setResult(makeGenericParam()); + return builder.build(id); +} + /// An array of the overloaded builtin kinds. static const OverloadedBuiltinKind OverloadedBuiltinKinds[] = { OverloadedBuiltinKind::None, @@ -1293,8 +1303,10 @@ static const OverloadedBuiltinKind OverloadedBuiltinKinds[] = { OverloadedBuiltinKind::Special, #define BUILTIN_CAST_OR_BITCAST_OPERATION(id, attrs, name) \ OverloadedBuiltinKind::Special, -#define BUILTIN_BINARY_OPERATION(id, name, attrs, overload) \ - OverloadedBuiltinKind::overload, +#define BUILTIN_BINARY_OPERATION_OVERLOADED_STATIC(id, name, attrs, overload) \ + OverloadedBuiltinKind::overload, +#define BUILTIN_BINARY_OPERATION_POLYMORPHIC(id, name, attrs) \ + OverloadedBuiltinKind::Special, #define BUILTIN_BINARY_OPERATION_WITH_OVERFLOW(id, name, _, attrs, overload) \ OverloadedBuiltinKind::overload, #define BUILTIN_BINARY_PREDICATE(id, name, attrs, overload) \ @@ -1347,6 +1359,13 @@ inline bool isBuiltinTypeOverloaded(Type T, OverloadedBuiltinKind OK) { llvm_unreachable("bad overloaded builtin kind"); } +bool swift::canBuiltinBeOverloadedForType(BuiltinValueKind ID, Type Ty) { + if (ID == BuiltinValueKind::None) + return false; + + return isBuiltinTypeOverloaded(Ty, OverloadedBuiltinKinds[unsigned(ID)]); +} + /// Table of string intrinsic names indexed by enum value. static const char *const IntrinsicNameTable[] = { "not_intrinsic", @@ -1889,10 +1908,21 @@ ValueDecl *swift::getBuiltinValueDecl(ASTContext &Context, Identifier Id) { return getEndUnpairedAccessOperation(Context, Id); #define BUILTIN(id, name, Attrs) -#define BUILTIN_BINARY_OPERATION(id, name, attrs, overload) case BuiltinValueKind::id: +#define BUILTIN_BINARY_OPERATION(id, name, attrs) +#define BUILTIN_BINARY_OPERATION_OVERLOADED_STATIC(id, name, attrs, overload) \ + case BuiltinValueKind::id: #include "swift/AST/Builtins.def" if (Types.size() != 1) return nullptr; - return getBinaryOperation(Id, Types[0]); + return getBinaryOperation(Id, Types[0]); + +#define BUILTIN(id, name, attrs) +#define BUILTIN_BINARY_OPERATION(id, name, attrs) +#define BUILTIN_BINARY_OPERATION_POLYMORPHIC(id, name, attrs) \ + case BuiltinValueKind::id: +#include "swift/AST/Builtins.def" + if (!Types.empty()) + return nullptr; + return getPolymorphicBinaryOperation(Context, Id); #define BUILTIN(id, name, Attrs) #define BUILTIN_BINARY_OPERATION_WITH_OVERFLOW(id, name, _, attrs, overload) case BuiltinValueKind::id: @@ -2150,6 +2180,21 @@ StringRef swift::getBuiltinName(BuiltinValueKind ID) { llvm_unreachable("bad BuiltinValueKind"); } +bool swift::isPolymorphicBuiltin(BuiltinValueKind id) { + switch (id) { + case BuiltinValueKind::None: + llvm_unreachable("no builtin kind"); +#define BUILTIN(Id, Name, Attrs) \ + case BuiltinValueKind::Id: \ + return false; +#define BUILTIN_BINARY_OPERATION_POLYMORPHIC(Id, Name, Attrs) \ + case BuiltinValueKind::Id: \ + return true; +#include "swift/AST/Builtins.def" + } + llvm_unreachable("bad BuiltinValueKind"); +} + BuiltinTypeKind BuiltinType::getBuiltinTypeKind() const { // If we do not have a vector or an integer our job is easy. return BuiltinTypeKind(std::underlying_type::type(getKind())); diff --git a/lib/AST/CaptureInfo.cpp b/lib/AST/CaptureInfo.cpp index de209b3558a4b..ea641857d8693 100644 --- a/lib/AST/CaptureInfo.cpp +++ b/lib/AST/CaptureInfo.cpp @@ -11,11 +11,50 @@ //===----------------------------------------------------------------------===// #include "swift/AST/CaptureInfo.h" +#include "swift/AST/ASTContext.h" #include "swift/AST/Decl.h" #include "llvm/Support/raw_ostream.h" using namespace swift; +CaptureInfo::CaptureInfo(ASTContext &ctx, ArrayRef captures, + DynamicSelfType *dynamicSelf, + OpaqueValueExpr *opaqueValue, + bool genericParamCaptures) { + static_assert(IsTriviallyDestructible::value, + "Capture info is alloc'd on the ASTContext and not destroyed"); + static_assert(IsTriviallyDestructible::value, + "Capture info is alloc'd on the ASTContext and not destroyed"); + + OptionSet flags; + if (genericParamCaptures) + flags |= Flags::HasGenericParamCaptures; + + if (captures.empty() && !dynamicSelf && !opaqueValue) { + *this = CaptureInfo::empty(); + StorageAndFlags.setInt(flags); + return; + } + + size_t storageToAlloc = + CaptureInfoStorage::totalSizeToAlloc(captures.size()); + void *storageBuf = ctx.Allocate(storageToAlloc, alignof(CaptureInfoStorage)); + auto *storage = new (storageBuf) CaptureInfoStorage(captures.size(), + dynamicSelf, + opaqueValue); + StorageAndFlags.setPointerAndInt(storage, flags); + std::uninitialized_copy(captures.begin(), captures.end(), + storage->getTrailingObjects()); +} + +CaptureInfo CaptureInfo::empty() { + static const CaptureInfoStorage empty{0, /*dynamicSelf*/nullptr, + /*opaqueValue*/nullptr}; + CaptureInfo result; + result.StorageAndFlags.setPointer(&empty); + return result; +} + bool CaptureInfo::hasLocalCaptures() const { for (auto capture : getCaptures()) if (capture.getDecl()->getDeclContext()->isLocalContext()) @@ -28,7 +67,7 @@ void CaptureInfo:: getLocalCaptures(SmallVectorImpl &Result) const { if (!hasLocalCaptures()) return; - Result.reserve(Count); + Result.reserve(getCaptures().size()); // Filter out global variables. for (auto capture : getCaptures()) { diff --git a/lib/AST/ConformanceLookupTable.cpp b/lib/AST/ConformanceLookupTable.cpp index 064cf632a393e..dbe519d83907a 100644 --- a/lib/AST/ConformanceLookupTable.cpp +++ b/lib/AST/ConformanceLookupTable.cpp @@ -21,6 +21,7 @@ #include "swift/AST/LazyResolver.h" #include "swift/AST/Module.h" #include "swift/AST/NameLookup.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/ProtocolConformance.h" #include "swift/AST/ProtocolConformanceRef.h" #include "llvm/Support/SaveAndRestore.h" @@ -794,16 +795,6 @@ ConformanceLookupTable::getConformance(NominalTypeDecl *nominal, if (!conformingDC) return nullptr; - // Everything about this conformance is nailed down, so we can now ensure that - // the extension is fully resolved. - if (auto resolver = nominal->getASTContext().getLazyResolver()) { - if (auto ED = dyn_cast(conformingDC)) { - resolver->resolveExtension(ED); - } else { - resolver->resolveDeclSignature(cast(conformingDC)); - } - } - auto *conformingNominal = conformingDC->getSelfNominalTypeDecl(); // Form the conformance. diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index d42a236b58eff..defff427b9757 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -38,6 +38,7 @@ #include "swift/AST/PropertyWrappers.h" #include "swift/AST/ProtocolConformance.h" #include "swift/AST/ResilienceExpansion.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/Stmt.h" #include "swift/AST/TypeCheckRequests.h" #include "swift/AST/TypeLoc.h" @@ -463,6 +464,16 @@ SourceRange Decl::getSourceRangeIncludingAttrs() const { } for (auto Attr : getAttrs()) { + // SWIFT_ENABLE_TENSORFLOW + // Skip implicitly `@differentiable` attribute generated during + // `@differentiating` attribute type-checking. + // TODO(TF-835): Instead of generating implicit `@differentiable` + // attributes, lower `@differentiating` attributes to `[differentiable]` + // attributes on the referenced declaration. + if (auto *diffAttr = dyn_cast(Attr)) + if (diffAttr->isImplicit()) + continue; + // SWIFT_ENABLE_TENSORFLOW END if (Attr->getRange().isValid()) Range.widen(Attr->getRangeWithAt()); } @@ -855,22 +866,19 @@ GenericParamList *GenericContext::getGenericParams() const { const_cast(this)}, nullptr); } -GenericSignature *GenericContext::getGenericSignature() const { - if (GenericSig) - return GenericSig; - - // The signature of a Protocol is trivial (Self: TheProtocol) so let's compute - // it. - if (auto PD = dyn_cast(this)) { - auto self = PD->getSelfInterfaceType()->castTo(); - auto req = - Requirement(RequirementKind::Conformance, self, PD->getDeclaredType()); - const_cast(this)->GenericSig - = GenericSignature::get({self}, {req}); - return GenericSig; - } +bool GenericContext::hasComputedGenericSignature() const { + return GenericSigAndBit.getInt(); +} + +bool GenericContext::isComputingGenericSignature() const { + return getASTContext().evaluator.hasActiveRequest( + GenericSignatureRequest{const_cast(this)}); +} - return nullptr; +GenericSignature *GenericContext::getGenericSignature() const { + return evaluateOrDefault( + getASTContext().evaluator, + GenericSignatureRequest{const_cast(this)}, nullptr); } GenericEnvironment *GenericContext::getGenericEnvironment() const { @@ -881,8 +889,9 @@ GenericEnvironment *GenericContext::getGenericEnvironment() const { } void GenericContext::setGenericSignature(GenericSignature *genericSig) { - assert(GenericSig == nullptr && "Generic signature cannot be changed"); - this->GenericSig = genericSig; + assert(!GenericSigAndBit.getPointer() && "Generic signature cannot be changed"); + getASTContext().evaluator.cacheOutput(GenericSignatureRequest{this}, + std::move(genericSig)); } SourceRange GenericContext::getGenericTrailingWhereClauseSourceRange() const { @@ -2698,7 +2707,13 @@ bool ValueDecl::hasInterfaceType() const { } Type ValueDecl::getInterfaceType() const { - assert(hasInterfaceType() && "No interface type was set"); + if (!hasInterfaceType()) { + // Our clients that don't register the lazy resolver are relying on the + // fact that they can't pull an interface type out to avoid doing work. + // This is a necessary evil until we can wean them off. + if (auto resolver = getASTContext().getLazyResolver()) + resolver->resolveDeclSignature(const_cast(this)); + } return TypeAndAccess.getPointer(); } @@ -2721,14 +2736,6 @@ void ValueDecl::setInterfaceType(Type type) { TypeAndAccess.setPointer(type); } -bool ValueDecl::hasValidSignature() const { - if (!hasInterfaceType()) - return false; - // FIXME -- The build blows up if the correct code is used: - // return getValidationState() > ValidationState::CheckingWithValidSignature; - return getValidationState() != ValidationState::Checking; -} - Optional ValueDecl::getObjCRuntimeName( bool skipIsObjCResolution) const { if (auto func = dyn_cast(this)) @@ -3250,7 +3257,7 @@ Type TypeDecl::getDeclaredInterfaceType() const { selfTy, const_cast(ATD)); } - Type interfaceType = hasInterfaceType() ? getInterfaceType() : nullptr; + Type interfaceType = getInterfaceType(); if (interfaceType.isNull() || interfaceType->is()) return interfaceType; @@ -3607,34 +3614,42 @@ SourceRange TypeAliasDecl::getSourceRange() const { return { TypeAliasLoc, getNameLoc() }; } -void TypeAliasDecl::setUnderlyingType(Type underlying) { - setValidationToChecked(); +void TypeAliasDecl::computeType() { + assert(!hasInterfaceType()); + + // Set the interface type of this declaration. + ASTContext &ctx = getASTContext(); + + auto *genericSig = getGenericSignature(); + SubstitutionMap subs; + if (genericSig) + subs = genericSig->getIdentitySubstitutionMap(); + + Type parent; + auto parentDC = getDeclContext(); + if (parentDC->isTypeContext()) + parent = parentDC->getDeclaredInterfaceType(); + auto sugaredType = TypeAliasType::get(this, parent, subs, getUnderlyingType()); + setInterfaceType(MetatypeType::get(sugaredType, ctx)); +} +Type TypeAliasDecl::getUnderlyingType() const { + return evaluateOrDefault(getASTContext().evaluator, + UnderlyingTypeRequest{const_cast(this)}, + Type()); +} + +void TypeAliasDecl::setUnderlyingType(Type underlying) { // lldb creates global typealiases containing archetypes // sometimes... if (underlying->hasArchetype() && isGenericContext()) underlying = underlying->mapTypeOutOfContext(); - UnderlyingTy.setType(underlying); - - // FIXME -- if we already have an interface type, we're changing the - // underlying type. See the comment in the ProtocolDecl case of - // validateDecl(). - if (!hasInterfaceType()) { - // Set the interface type of this declaration. - ASTContext &ctx = getASTContext(); - - auto *genericSig = getGenericSignature(); - SubstitutionMap subs; - if (genericSig) - subs = genericSig->getIdentitySubstitutionMap(); - - Type parent; - auto parentDC = getDeclContext(); - if (parentDC->isTypeContext()) - parent = parentDC->getDeclaredInterfaceType(); - auto sugaredType = TypeAliasType::get(this, parent, subs, underlying); - setInterfaceType(MetatypeType::get(sugaredType, ctx)); - } + getASTContext().evaluator.cacheOutput( + StructuralTypeRequest{const_cast(this)}, + std::move(underlying)); + getASTContext().evaluator.cacheOutput( + UnderlyingTypeRequest{const_cast(this)}, + std::move(underlying)); } UnboundGenericType *TypeAliasDecl::getUnboundGenericType() const { @@ -3651,12 +3666,10 @@ UnboundGenericType *TypeAliasDecl::getUnboundGenericType() const { } Type TypeAliasDecl::getStructuralType() const { - assert(!getGenericParams()); - auto &context = getASTContext(); - return evaluateOrDefault(context.evaluator, - StructuralTypeRequest { const_cast(this) }, - Type()); + return evaluateOrDefault( + context.evaluator, + StructuralTypeRequest{const_cast(this)}, Type()); } Type AbstractTypeParamDecl::getSuperclass() const { @@ -5716,12 +5729,18 @@ void VarDecl::emitLetToVarNoteIfSimple(DeclContext *UseDC) const { if (FD && !FD->isMutating() && !FD->isImplicit() && FD->isInstanceMember()&& !FD->getDeclContext()->getDeclaredInterfaceType() ->hasReferenceSemantics()) { - // Do not suggest the fix it in implicit getters + // Do not suggest the fix-it in implicit getters if (auto AD = dyn_cast(FD)) { if (AD->isGetter() && !AD->getAccessorKeywordLoc().isValid()) return; + + auto accessorDC = AD->getDeclContext(); + // Do not suggest the fix-it if `Self` is a class type. + if (accessorDC->isTypeContext() && !accessorDC->hasValueSemantics()) { + return; + } } - + auto &d = getASTContext().Diags; d.diagnose(FD->getFuncLoc(), diag::change_to_mutating, isa(FD)) @@ -5943,6 +5962,11 @@ void ParamDecl::setDefaultArgumentInitContext(Initializer *initContext) { DefaultValueAndFlags.getPointer()->InitContext = initContext; } +void ParamDecl::setDefaultArgumentCaptureInfo(const CaptureInfo &captures) { + assert(DefaultValueAndFlags.getPointer()); + DefaultValueAndFlags.getPointer()->Captures = captures; +} + /// Return nullptr if there is no property wrapper Expr *swift::findOriginalPropertyWrapperInitialValue(VarDecl *var, Expr *init) { @@ -6236,6 +6260,10 @@ void SubscriptDecl::computeType() { // Record the interface type. setInterfaceType(funcTy); + + // Make sure that there are no unresolved dependent types in the + // generic signature. + assert(!funcTy->findUnresolvedDependentMemberType()); } ObjCSubscriptKind SubscriptDecl::getObjCSubscriptKind() const { @@ -6614,17 +6642,6 @@ static bool requiresNewVTableEntry(const AbstractFunctionDecl *decl) { if (decl->isEffectiveLinkageMoreVisibleThan(base)) return true; - // FIXME: Remove this once getInterfaceType() has been request-ified. - if (!decl->hasInterfaceType()) { - ctx.getLazyResolver()->resolveDeclSignature( - const_cast(decl)); - } - - if (!base->hasInterfaceType()) { - ctx.getLazyResolver()->resolveDeclSignature( - const_cast(base)); - } - // If the method overrides something, we only need a new entry if the // override has a more general AST type. However an abstraction // change is OK; we don't want to add a whole new vtable entry just @@ -6830,6 +6847,10 @@ void AbstractFunctionDecl::computeType(AnyFunctionType::ExtInfo info) { // Compute the type of the 'self' parameter if we're created one already. if (hasSelf) computeSelfDeclType(); + + // Make sure that there are no unresolved dependent types in the + // generic signature. + assert(!funcTy->findUnresolvedDependentMemberType()); } bool AbstractFunctionDecl::hasInlinableBodyText() const { diff --git a/lib/AST/DeclContext.cpp b/lib/AST/DeclContext.cpp index 9803975c2617d..33f0547426792 100644 --- a/lib/AST/DeclContext.cpp +++ b/lib/AST/DeclContext.cpp @@ -15,11 +15,13 @@ #include "swift/AST/ASTContext.h" #include "swift/AST/ASTWalker.h" #include "swift/AST/Expr.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/GenericEnvironment.h" #include "swift/AST/Initializer.h" #include "swift/AST/LazyResolver.h" #include "swift/AST/Module.h" #include "swift/AST/ParseRequests.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/Types.h" #include "swift/AST/TypeCheckRequests.h" #include "swift/Basic/SourceManager.h" @@ -1018,6 +1020,14 @@ DeclContextKind DeclContext::getContextKind() const { llvm_unreachable("Unhandled DeclContext ASTHierarchy"); } +bool DeclContext::hasValueSemantics() const { + if (auto contextTy = getSelfTypeInContext()) { + return !contextTy->hasReferenceSemantics(); + } + + return false; +} + SourceLoc swift::extractNearestSourceLoc(const DeclContext *dc) { switch (dc->getContextKind()) { case DeclContextKind::AbstractFunctionDecl: diff --git a/lib/AST/DiagnosticEngine.cpp b/lib/AST/DiagnosticEngine.cpp index d6dc1696a17f2..26209736a7780 100644 --- a/lib/AST/DiagnosticEngine.cpp +++ b/lib/AST/DiagnosticEngine.cpp @@ -23,6 +23,7 @@ #include "swift/AST/Module.h" #include "swift/AST/Pattern.h" #include "swift/AST/PrintOptions.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/TypeRepr.h" #include "swift/Basic/SourceManager.h" #include "swift/Config.h" @@ -379,7 +380,7 @@ static bool isInterestingTypealias(Type type) { // Compatibility aliases are only interesting insofar as their underlying // types are interesting. if (aliasDecl->isCompatibilityAlias()) { - auto underlyingTy = aliasDecl->getUnderlyingTypeLoc().getType(); + auto underlyingTy = aliasDecl->getUnderlyingType(); return isInterestingTypealias(underlyingTy); } diff --git a/lib/AST/ExperimentalDependenciesSourceFileDepGraphConstructor.cpp b/lib/AST/ExperimentalDependenciesSourceFileDepGraphConstructor.cpp index 3987a603312aa..4b9be295c3263 100644 --- a/lib/AST/ExperimentalDependenciesSourceFileDepGraphConstructor.cpp +++ b/lib/AST/ExperimentalDependenciesSourceFileDepGraphConstructor.cpp @@ -24,6 +24,7 @@ #include "swift/AST/Module.h" #include "swift/AST/ModuleLoader.h" #include "swift/AST/NameLookup.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/Types.h" #include "swift/Basic/FileSystem.h" #include "swift/Basic/LLVM.h" diff --git a/lib/AST/GenericSignatureBuilder.cpp b/lib/AST/GenericSignatureBuilder.cpp index bd56eb548b58a..1c0a3ddaef27c 100644 --- a/lib/AST/GenericSignatureBuilder.cpp +++ b/lib/AST/GenericSignatureBuilder.cpp @@ -22,6 +22,7 @@ #include "swift/AST/DiagnosticsSema.h" #include "swift/AST/DiagnosticEngine.h" #include "swift/AST/ExistentialLayout.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/GenericEnvironment.h" #include "swift/AST/LazyResolver.h" #include "swift/AST/Module.h" @@ -3785,10 +3786,14 @@ PotentialArchetype *GenericSignatureBuilder::realizePotentialArchetype( static Type getStructuralType(TypeDecl *typeDecl) { if (auto typealias = dyn_cast(typeDecl)) { - if (auto resolved = typealias->getUnderlyingTypeLoc().getType()) - return resolved; - - return typealias->getStructuralType(); + // When we're computing requirement signatures, the structural type + // suffices. Otherwise we'll potentially try to validate incomplete + // requirements. + auto *proto = dyn_cast_or_null( + typealias->getDeclContext()->getAsDecl()); + if (proto && proto->isComputingRequirementSignature()) + return typealias->getStructuralType(); + return typealias->getUnderlyingType(); } return typeDecl->getDeclaredInterfaceType(); @@ -4196,11 +4201,10 @@ ConstraintResult GenericSignatureBuilder::expandConformanceRequirement( out << start; out << type->getFullName() << " == "; if (auto typealias = dyn_cast(type)) { - if (auto underlyingTypeRepr = - typealias->getUnderlyingTypeLoc().getTypeRepr()) + if (auto underlyingTypeRepr = typealias->getUnderlyingTypeRepr()) underlyingTypeRepr->print(out); else - typealias->getUnderlyingTypeLoc().getType().print(out); + typealias->getUnderlyingType().print(out); } else { type->print(out); } @@ -5313,6 +5317,12 @@ class GenericSignatureBuilder::InferRequirementsWalker : public TypeWalker { auto decl = ty->getAnyNominal(); if (!decl) return Action::Continue; + // FIXME: The GSB and the request evaluator both detect a cycle here if we + // force a recursive generic signature. We should look into moving cycle + // detection into the generic signature request(s) - see rdar://55263708 + if (!decl->hasComputedGenericSignature()) + return Action::Continue; + auto genericSig = decl->getGenericSignature(); if (!genericSig) return Action::Continue; diff --git a/lib/AST/ImportCache.cpp b/lib/AST/ImportCache.cpp index 4e4b6676a9056..2d8ff08890c96 100644 --- a/lib/AST/ImportCache.cpp +++ b/lib/AST/ImportCache.cpp @@ -18,6 +18,7 @@ #include "llvm/ADT/DenseSet.h" #include "swift/AST/ASTContext.h" #include "swift/AST/ClangModuleLoader.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/ImportCache.h" #include "swift/AST/Module.h" diff --git a/lib/AST/Module.cpp b/lib/AST/Module.cpp index 47a5c3ea23f8a..ccd49db49205a 100644 --- a/lib/AST/Module.cpp +++ b/lib/AST/Module.cpp @@ -23,6 +23,7 @@ #include "swift/AST/Builtins.h" #include "swift/AST/DiagnosticsSema.h" #include "swift/AST/ExistentialLayout.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/GenericEnvironment.h" #include "swift/AST/ImportCache.h" #include "swift/AST/LazyResolver.h" @@ -33,6 +34,7 @@ #include "swift/AST/PrettyStackTrace.h" #include "swift/AST/PrintOptions.h" #include "swift/AST/ProtocolConformance.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/TypeCheckRequests.h" #include "swift/Basic/Compiler.h" #include "swift/Basic/SourceManager.h" @@ -101,6 +103,8 @@ void BuiltinUnit::LookupCache::lookupValue( const_cast(&M)); TAD->setUnderlyingType(Ty); TAD->setAccess(AccessLevel::Public); + TAD->setValidationToChecked(); + TAD->computeType(); Entry = TAD; } } @@ -1819,14 +1823,15 @@ SourceFile::lookupOpaqueResultType(StringRef MangledName, auto found = ValidatedOpaqueReturnTypes.find(MangledName); if (found != ValidatedOpaqueReturnTypes.end()) return found->second; - + // If there are unvalidated decls with opaque types, go through and validate // them now. if (resolver && !UnvalidatedDeclsWithOpaqueReturnTypes.empty()) { while (!UnvalidatedDeclsWithOpaqueReturnTypes.empty()) { ValueDecl *decl = *UnvalidatedDeclsWithOpaqueReturnTypes.begin(); UnvalidatedDeclsWithOpaqueReturnTypes.erase(decl); - resolver->resolveDeclSignature(decl); + // FIXME(InterfaceTypeRequest): Remove this. + (void)decl->getInterfaceType(); } found = ValidatedOpaqueReturnTypes.find(MangledName); diff --git a/lib/AST/NameLookup.cpp b/lib/AST/NameLookup.cpp index 4e04d2f64f3d3..f3b0ae29a675c 100644 --- a/lib/AST/NameLookup.cpp +++ b/lib/AST/NameLookup.cpp @@ -28,6 +28,7 @@ #include "swift/AST/NameLookupRequests.h" #include "swift/AST/ParameterList.h" #include "swift/AST/ReferencedNameTracker.h" +#include "swift/AST/SourceFile.h" #include "swift/Basic/SourceManager.h" #include "swift/Basic/Statistic.h" #include "swift/Basic/STLExtras.h" @@ -433,8 +434,6 @@ static void recordShadowedDecls(ArrayRef decls, if (decls.size() < 2) return; - auto typeResolver = decls[0]->getASTContext().getLazyResolver(); - // Categorize all of the declarations based on their overload signatures. llvm::SmallDenseMap> collisions; llvm::SmallVector collisionTypes; @@ -462,19 +461,16 @@ static void recordShadowedDecls(ArrayRef decls, CanType signature; if (!isa(decl)) { - // We need an interface type here. - if (typeResolver) - typeResolver->resolveDeclSignature(decl); - // If the decl is currently being validated, this is likely a recursive // reference and we'll want to skip ahead so as to avoid having its type // attempt to desugar itself. - if (!decl->hasValidSignature()) + auto ifaceType = decl->getInterfaceType(); + if (!ifaceType) continue; // FIXME: the canonical type makes a poor signature, because we don't // canonicalize away default arguments. - signature = decl->getInterfaceType()->getCanonicalType(); + signature = ifaceType->getCanonicalType(); // FIXME: The type of a variable or subscript doesn't include // enough context to distinguish entities from different @@ -1813,7 +1809,7 @@ resolveTypeDeclsToNominal(Evaluator &evaluator, // Recognize Swift.AnyObject directly. if (typealias->getName().is("AnyObject")) { // TypeRepr version: Builtin.AnyObject - if (auto typeRepr = typealias->getUnderlyingTypeLoc().getTypeRepr()) { + if (auto typeRepr = typealias->getUnderlyingTypeRepr()) { if (auto compound = dyn_cast(typeRepr)) { auto components = compound->getComponents(); if (components.size() == 2 && @@ -1825,9 +1821,10 @@ resolveTypeDeclsToNominal(Evaluator &evaluator, } // Type version: an empty class-bound existential. - if (auto type = typealias->getUnderlyingTypeLoc().getType()) { - if (type->isAnyObject()) - anyObject = true; + if (typealias->hasInterfaceType()) { + if (auto type = typealias->getUnderlyingType()) + if (type->isAnyObject()) + anyObject = true; } } @@ -2091,7 +2088,7 @@ DirectlyReferencedTypeDecls UnderlyingTypeDeclsReferencedRequest::evaluate( Evaluator &evaluator, TypeAliasDecl *typealias) const { // Prefer syntactic information when we have it. - if (auto typeRepr = typealias->getUnderlyingTypeLoc().getTypeRepr()) { + if (auto typeRepr = typealias->getUnderlyingTypeRepr()) { return directReferencesForTypeRepr(evaluator, typealias->getASTContext(), typeRepr, typealias); } @@ -2099,7 +2096,7 @@ DirectlyReferencedTypeDecls UnderlyingTypeDeclsReferencedRequest::evaluate( // Fall back to semantic types. // FIXME: In the long run, we shouldn't need this. Non-syntactic results // should be cached. - if (auto type = typealias->getUnderlyingTypeLoc().getType()) { + if (auto type = typealias->getUnderlyingType()) { return directReferencesForType(type); } diff --git a/lib/AST/ProtocolConformance.cpp b/lib/AST/ProtocolConformance.cpp index 3a210c62a4d15..da5a61d94ba86 100644 --- a/lib/AST/ProtocolConformance.cpp +++ b/lib/AST/ProtocolConformance.cpp @@ -18,6 +18,7 @@ #include "swift/AST/ASTContext.h" #include "swift/AST/Availability.h" #include "swift/AST/Decl.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/LazyResolver.h" #include "swift/AST/GenericEnvironment.h" #include "swift/AST/Module.h" @@ -127,10 +128,12 @@ ProtocolConformanceRef::subst(Type origType, // If the type is an existential, it must be self-conforming. if (substType->isExistentialType()) { - auto optConformance = - proto->getModuleContext()->lookupExistentialConformance(substType, proto); - assert(optConformance && "existential type didn't self-conform"); - return *optConformance; + if (auto optConformance = + proto->getModuleContext()->lookupExistentialConformance( + substType, proto)) + return *optConformance; + + return ProtocolConformanceRef::forInvalid(); } // Check the conformance map. @@ -139,7 +142,7 @@ ProtocolConformanceRef::subst(Type origType, return *result; } - llvm_unreachable("Invalid conformance substitution"); + return ProtocolConformanceRef::forInvalid(); } ProtocolConformanceRef ProtocolConformanceRef::mapConformanceOutOfContext() const { @@ -528,7 +531,7 @@ void NormalProtocolConformance::differenceAndStoreConditionalRequirements() assert(CRState == ConditionalRequirementsState::Computing); CRState = ConditionalRequirementsState::Uncomputed; }; - + auto &ctxt = getProtocol()->getASTContext(); auto DC = getDeclContext(); // A non-extension conformance won't have conditional requirements. @@ -547,29 +550,24 @@ void NormalProtocolConformance::differenceAndStoreConditionalRequirements() return; } - auto extensionSig = ext->getGenericSignature(); - if (!extensionSig) { - if (auto lazyResolver = ctxt.getLazyResolver()) { - lazyResolver->resolveExtension(ext); - extensionSig = ext->getGenericSignature(); - } + // If the extension is invalid, it won't ever get a signature, so we + // "succeed" with an empty result instead. + if (ext->isInvalid()) { + success({}); + return; } - // The type is generic, but the extension doesn't have a signature yet, so - // we might be in a recursive validation situation. - if (!extensionSig) { - // If the extension is invalid, it won't ever get a signature, so we - // "succeed" with an empty result instead. - if (ext->isInvalid()) { - success({}); - return; - } - - // Otherwise we'll try again later. + // Recursively validating the signature comes up frequently as expanding + // conformance requirements might re-enter this method. We can at least catch + // this and come back to these requirements later. + // + // FIXME: In the long run, break this cycle in a more principled way. + if (ext->isComputingGenericSignature()) { failure(); return; } + auto extensionSig = ext->getGenericSignature(); auto canExtensionSig = extensionSig->getCanonicalSignature(); auto canTypeSig = typeSig->getCanonicalSignature(); if (canTypeSig == canExtensionSig) { diff --git a/lib/AST/RawComment.cpp b/lib/AST/RawComment.cpp index 41815a47993f7..f60efcf4e97e2 100644 --- a/lib/AST/RawComment.cpp +++ b/lib/AST/RawComment.cpp @@ -19,6 +19,7 @@ #include "swift/AST/Comment.h" #include "swift/AST/ASTContext.h" #include "swift/AST/Decl.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/Module.h" #include "swift/AST/PrettyStackTrace.h" #include "swift/AST/Types.h" diff --git a/lib/AST/SubstitutionMap.cpp b/lib/AST/SubstitutionMap.cpp index 9d0ea0c2c2feb..acab31b997bdb 100644 --- a/lib/AST/SubstitutionMap.cpp +++ b/lib/AST/SubstitutionMap.cpp @@ -388,12 +388,15 @@ SubstitutionMap::lookupConformance(CanType type, ProtocolDecl *proto) const { if (conformance->isAbstract()) { // FIXME: Rip this out once we can get a concrete conformance from // an archetype. - auto *M = proto->getParentModule(); auto substType = type.subst(*this); + if (substType->hasError()) + return ProtocolConformanceRef(proto); + if ((!substType->is() || substType->castTo()->getSuperclass()) && !substType->isTypeParameter() && !substType->isExistentialType()) { + auto *M = proto->getParentModule(); return M->lookupConformance(substType, proto); } @@ -483,27 +486,9 @@ SubstitutionMap SubstitutionMap::getProtocolSubstitutions(ProtocolDecl *protocol, Type selfType, ProtocolConformanceRef conformance) { - auto protocolSelfType = protocol->getSelfInterfaceType(); - - return get( - protocol->getGenericSignature(), - [&](SubstitutableType *type) -> Type { - if (type->isEqual(protocolSelfType)) - return selfType; - - // This will need to change if we ever support protocols - // inside generic types. - return Type(); - }, - [&](CanType origType, Type replacementType, ProtocolDecl *protoType) - -> Optional { - if (origType->isEqual(protocolSelfType) && protoType == protocol) - return conformance; - - // This will need to change if we ever support protocols - // inside generic types. - return None; - }); + return get(protocol->getGenericSignature(), + llvm::makeArrayRef(selfType), + llvm::makeArrayRef(conformance)); } SubstitutionMap diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 4cfd23cd1e982..9f7ffddc298e0 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -1098,8 +1098,8 @@ CanType TypeBase::computeCanonicalType() { assert(resolver && "Need to resolve generic parameter depth"); if (auto decl = gpDecl->getDeclContext()->getInnermostDeclarationDeclContext()) - if (auto valueDecl = dyn_cast(decl)) - resolver->resolveDeclSignature(valueDecl); + if (auto valueDecl = decl->getAsGenericContext()) + (void)valueDecl->getGenericSignature(); } assert(gpDecl->getDepth() != GenericTypeParamDecl::InvalidDepth && diff --git a/lib/AST/TypeCheckRequests.cpp b/lib/AST/TypeCheckRequests.cpp index 3d4a00f5047e1..7c9bf58563028 100644 --- a/lib/AST/TypeCheckRequests.cpp +++ b/lib/AST/TypeCheckRequests.cpp @@ -368,6 +368,14 @@ SourceLoc RequirementRequest::getNearestLoc() const { return owner.getLoc(); } +void RequirementRequest::noteCycleStep(DiagnosticEngine &diags) const { + // For now, the GSB does a better job of describing the exact structure of + // the cycle. + // + // FIXME: We should consider merging the circularity handling the GSB does + // into this request. See rdar://55263708 +} + MutableArrayRef WhereClauseOwner::getRequirements() const { if (auto genericParams = source.dyn_cast()) { return genericParams->getRequirements(); @@ -817,3 +825,49 @@ void IsImplicitlyUnwrappedOptionalRequest::cacheResult(bool value) const { auto *decl = std::get<0>(getStorage()); decl->setImplicitlyUnwrappedOptional(value); } + +//----------------------------------------------------------------------------// +// GenericSignatureRequest computation. +//----------------------------------------------------------------------------// + +Optional GenericSignatureRequest::getCachedResult() const { + auto *GC = std::get<0>(getStorage()); + if (GC->GenericSigAndBit.getInt()) { + return GC->GenericSigAndBit.getPointer(); + } + return None; +} + +void GenericSignatureRequest::cacheResult(GenericSignature *value) const { + auto *GC = std::get<0>(getStorage()); + GC->GenericSigAndBit.setPointerAndInt(value, true); +} + +//----------------------------------------------------------------------------// +// GenericSignatureRequest computation. +//----------------------------------------------------------------------------// + +void InferredGenericSignatureRequest::noteCycleStep(DiagnosticEngine &d) const { + // For now, the GSB does a better job of describing the exact structure of + // the cycle. + // + // FIXME: We should consider merging the circularity handling the GSB does + // into this request. See rdar://55263708 +} + +//----------------------------------------------------------------------------// +// IsImplicitlyUnwrappedOptionalRequest computation. +//----------------------------------------------------------------------------// + +Optional +UnderlyingTypeRequest::getCachedResult() const { + auto *typeAlias = std::get<0>(getStorage()); + if (auto type = typeAlias->UnderlyingTy.getType()) + return type; + return None; +} + +void UnderlyingTypeRequest::cacheResult(Type value) const { + auto *typeAlias = std::get<0>(getStorage()); + typeAlias->UnderlyingTy.setType(value); +} diff --git a/lib/AST/TypeRefinementContext.cpp b/lib/AST/TypeRefinementContext.cpp index e794daf155e5d..604323bda8db7 100644 --- a/lib/AST/TypeRefinementContext.cpp +++ b/lib/AST/TypeRefinementContext.cpp @@ -19,6 +19,7 @@ #include "swift/AST/Module.h" #include "swift/AST/Stmt.h" #include "swift/AST/Expr.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/TypeRefinementContext.h" #include "swift/Basic/SourceManager.h" diff --git a/lib/AST/USRGeneration.cpp b/lib/AST/USRGeneration.cpp index 70d112c5f9009..23d722ffbefdc 100644 --- a/lib/AST/USRGeneration.cpp +++ b/lib/AST/USRGeneration.cpp @@ -241,11 +241,12 @@ swift::USRGenerationRequest::evaluate(Evaluator &evaluator, } } - if (!D->hasInterfaceType()) + auto declIFaceTy = D->getInterfaceType(); + if (!declIFaceTy) return std::string(); // Invalid code. - if (D->getInterfaceType().findIf([](Type t) -> bool { + if (declIFaceTy.findIf([](Type t) -> bool { return t->is(); })) return std::string(); diff --git a/lib/AST/UnqualifiedLookup.cpp b/lib/AST/UnqualifiedLookup.cpp index d8bd21798f606..4cfbcc4e2aaeb 100644 --- a/lib/AST/UnqualifiedLookup.cpp +++ b/lib/AST/UnqualifiedLookup.cpp @@ -28,6 +28,7 @@ #include "swift/AST/NameLookupRequests.h" #include "swift/AST/ParameterList.h" #include "swift/AST/ReferencedNameTracker.h" +#include "swift/AST/SourceFile.h" #include "swift/Basic/STLExtras.h" #include "swift/Basic/SourceManager.h" #include "swift/Basic/Statistic.h" @@ -226,15 +227,15 @@ namespace { whereToLook, isCascadingUse.getValueOr(resolution)}; } }; - - bool useASTScopesForExperimentalLookup() const; - + + bool useASTScopesForLookup() const; + /// For testing, assume this lookup is enabled: - bool useASTScopesForExperimentalLookupIfEnabled() const; - + bool useASTScopesForLookupIfEnabled() const; + void lookUpTopLevelNamesInModuleScopeContext(DeclContext *); - void experimentallyLookInASTScopes(); + void lookInASTScopes(); /// Can lookup stop searching for results, assuming hasn't looked for outer /// results yet? @@ -472,7 +473,8 @@ UnqualifiedLookupFactory::UnqualifiedLookupFactory( void UnqualifiedLookupFactory::performUnqualifiedLookup() { #ifndef NDEBUG ++lookupCounter; - stopForDebuggingIfStartingTargetLookup(false); + auto localCounter = lookupCounter; + (void)localCounter; // for debugging #endif FrontendStatsTracer StatsTracer(Ctx.Stats, "performUnqualifedLookup", DC->getParentSourceFile()); @@ -481,30 +483,40 @@ void UnqualifiedLookupFactory::performUnqualifiedLookup() { ContextAndUnresolvedIsCascadingUse contextAndIsCascadingUse{ DC, initialIsCascadingUse}; - const bool compareToASTScopes = Ctx.LangOpts.CompareToASTScopeLookup; - if (useASTScopesForExperimentalLookup() && !compareToASTScopes) { + const bool crosscheckUnqualifiedLookup = + Ctx.LangOpts.CrosscheckUnqualifiedLookup; + if (useASTScopesForLookup()) { static bool haveWarned = false; if (!haveWarned && Ctx.LangOpts.WarnIfASTScopeLookup) { haveWarned = true; llvm::errs() << "WARNING: TRYING Scope exclusively\n"; } - experimentallyLookInASTScopes(); - return; - } + lookInASTScopes(); + } else { +#ifndef NDEBUG + stopForDebuggingIfStartingTargetLookup(false); +#endif - if (Name.isOperator()) - lookupOperatorInDeclContexts(contextAndIsCascadingUse); - else - lookupNamesIntroducedBy(contextAndIsCascadingUse); + if (Name.isOperator()) + lookupOperatorInDeclContexts(contextAndIsCascadingUse); + else + lookupNamesIntroducedBy(contextAndIsCascadingUse); + } - if (compareToASTScopes && useASTScopesForExperimentalLookupIfEnabled()) { + if (crosscheckUnqualifiedLookup && useASTScopesForLookupIfEnabled()) { ResultsVector results; size_t indexOfFirstOuterResult = 0; - UnqualifiedLookupFactory scopeLookup(Name, DC, Loc, options, - results, indexOfFirstOuterResult); - scopeLookup.experimentallyLookInASTScopes(); - assert(verifyEqualTo(std::move(scopeLookup), "UnqualifedLookup", - "Scope lookup")); + UnqualifiedLookupFactory altLookup(Name, DC, Loc, options, results, + indexOfFirstOuterResult); + if (!useASTScopesForLookup()) + altLookup.lookInASTScopes(); + else if (Name.isOperator()) + altLookup.lookupOperatorInDeclContexts(contextAndIsCascadingUse); + else + altLookup.lookupNamesIntroducedBy(contextAndIsCascadingUse); + + assert( + verifyEqualTo(std::move(altLookup), "main lookup", "alternate lookup")); } } @@ -529,13 +541,11 @@ void UnqualifiedLookupFactory::lookUpTopLevelNamesInModuleScopeContext( recordCompletionOfAScope(); } -bool UnqualifiedLookupFactory::useASTScopesForExperimentalLookup() const { - return Ctx.LangOpts.EnableASTScopeLookup && - useASTScopesForExperimentalLookupIfEnabled(); +bool UnqualifiedLookupFactory::useASTScopesForLookup() const { + return Ctx.LangOpts.EnableASTScopeLookup && useASTScopesForLookupIfEnabled(); } -bool UnqualifiedLookupFactory::useASTScopesForExperimentalLookupIfEnabled() - const { +bool UnqualifiedLookupFactory::useASTScopesForLookupIfEnabled() const { if (!Loc.isValid()) return false; const auto *const SF = DC->getParentSourceFile(); @@ -1097,7 +1107,7 @@ UnqualifiedLookupFactory::ResultFinderForTypeContext::findSelfBounds( #pragma mark ASTScopeImpl support -void UnqualifiedLookupFactory::experimentallyLookInASTScopes() { +void UnqualifiedLookupFactory::lookInASTScopes() { ASTScopeDeclConsumerForUnqualifiedLookup consumer(*this); @@ -1141,7 +1151,7 @@ bool ASTScopeDeclConsumerForUnqualifiedLookup::consume( // In order to preserve the behavior of the existing context-based lookup, // which finds all results for non-local variables at the top level instead // of stopping at the first one, ignore results at the top level that are - // not local variables. The caller \c experimentallyLookInASTScopes will + // not local variables. The caller \c lookInASTScopes will // then do the appropriate work when the scope lookup fails. In // FindLocalVal::visitBraceStmt, it sees PatternBindingDecls, not VarDecls, // so a VarDecl at top level would not be found by the context-based lookup. diff --git a/lib/ClangImporter/ClangImporter.cpp b/lib/ClangImporter/ClangImporter.cpp index efbf2c7625ff2..d005364439c03 100644 --- a/lib/ClangImporter/ClangImporter.cpp +++ b/lib/ClangImporter/ClangImporter.cpp @@ -2685,7 +2685,7 @@ void ClangModuleUnit::getTopLevelDecls(SmallVectorImpl &results) const { auto alias = dyn_cast(importedDecl); if (!alias || !alias->isCompatibilityAlias()) continue; - auto aliasedTy = alias->getUnderlyingTypeLoc().getType(); + auto aliasedTy = alias->getUnderlyingType(); ext = nullptr; importedDecl = nullptr; diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp index e785d445eaac3..7d37e91efaac8 100644 --- a/lib/ClangImporter/ImportDecl.cpp +++ b/lib/ClangImporter/ImportDecl.cpp @@ -1493,6 +1493,7 @@ static void addSynthesizedTypealias(NominalTypeDecl *nominal, Identifier name, typealias->setAccess(AccessLevel::Public); typealias->setValidationToChecked(); typealias->setImplicit(); + typealias->computeType(); nominal->addMember(typealias); } @@ -2563,6 +2564,8 @@ namespace { /*genericparams*/nullptr, DC); typealias->setUnderlyingType( underlying->getDeclaredInterfaceType()); + typealias->setValidationToChecked(); + typealias->computeType(); Impl.SpecialTypedefNames[Decl->getCanonicalDecl()] = MappedTypeNameKind::DefineAndUse; @@ -2582,6 +2585,8 @@ namespace { /*genericparams*/nullptr, DC); typealias->setUnderlyingType( Impl.SwiftContext.getAnyObjectType()); + typealias->setValidationToChecked(); + typealias->computeType(); Impl.SpecialTypedefNames[Decl->getCanonicalDecl()] = MappedTypeNameKind::DefineAndUse; @@ -2629,13 +2634,13 @@ namespace { return newtype; if (!SwiftType) { - // Import typedefs of blocks as their fully-bridged equivalent Swift - // type. That matches how we want to use them in most cases. All other - // types should be imported in a non-bridged way. + // Note that the code below checks to see if the typedef allows + // bridging, i.e. if the imported typealias should name a bridged type + // or the original C type. clang::QualType ClangType = Decl->getUnderlyingType(); SwiftType = Impl.importTypeIgnoreIUO( ClangType, ImportTypeKind::Typedef, isInSystemModule(DC), - getTypedefBridgeability(Decl, ClangType), OTK_Optional); + getTypedefBridgeability(Decl), OTK_Optional); } if (!SwiftType) @@ -2649,7 +2654,9 @@ namespace { Loc, /*genericparams*/nullptr, DC); Result->setUnderlyingType(SwiftType); - + Result->setValidationToChecked(); + Result->computeType(); + // Make Objective-C's 'id' unavailable. if (Impl.SwiftContext.LangOpts.EnableObjCInterop && isObjCId(Decl)) { auto attr = AvailableAttr::createPlatformAgnostic( @@ -2943,6 +2950,8 @@ namespace { C.Id_ErrorType, loc, /*genericparams=*/nullptr, enumDecl); alias->setUnderlyingType(errorWrapper->getDeclaredInterfaceType()); + alias->setValidationToChecked(); + alias->computeType(); enumDecl->addMember(alias); // Add the 'Code' enum to the error wrapper. @@ -4033,7 +4042,9 @@ namespace { Loc, /*genericparams*/nullptr, DC); Result->setUnderlyingType(SwiftTypeDecl->getDeclaredInterfaceType()); - + Result->setValidationToChecked(); + Result->computeType(); + return Result; } @@ -5169,6 +5180,8 @@ namespace { } typealias->setUnderlyingType(typeDecl->getDeclaredInterfaceType()); + typealias->setValidationToChecked(); + typealias->computeType(); return typealias; } @@ -5404,7 +5417,9 @@ Decl *SwiftDeclConverter::importCompatibilityTypeAlias( } alias->setUnderlyingType(typeDecl->getDeclaredInterfaceType()); - + alias->setValidationToChecked(); + alias->computeType(); + // Record that this is the official version of this declaration. Impl.ImportedDecls[{decl->getCanonicalDecl(), getVersion()}] = alias; markAsVariant(alias, correctSwiftName); @@ -8240,7 +8255,7 @@ ClangImporter::Implementation::createConstant(Identifier name, DeclContext *dc, auto maxFloatTypeDecl = context.get_MaxBuiltinFloatTypeDecl(); floatExpr->setBuiltinType( - maxFloatTypeDecl->getUnderlyingTypeLoc().getType()); + maxFloatTypeDecl->getUnderlyingType()); auto *floatDecl = literalType->getAnyNominal(); floatExpr->setBuiltinInitializer( diff --git a/lib/ClangImporter/ImportType.cpp b/lib/ClangImporter/ImportType.cpp index e0ab429b35f9f..a3feabe58fc2e 100644 --- a/lib/ClangImporter/ImportType.cpp +++ b/lib/ClangImporter/ImportType.cpp @@ -160,15 +160,6 @@ namespace { explicit operator bool() const { return (bool) AbstractType; } }; - static OptionalTypeKind getOptionalKind(ImportTypeKind kind, - OptionalTypeKind OptKind) { - // Import pointee types as true Optional. - if (OptKind == OTK_ImplicitlyUnwrappedOptional && - kind == ImportTypeKind::Pointee) - return OTK_Optional; - return OptKind; - } - class SwiftTypeConverter : public clang::TypeVisitor { @@ -384,19 +375,13 @@ namespace { } // All other C pointers to concrete types map to - // UnsafeMutablePointer or OpaquePointer (FIXME:, except in - // parameter position under the pre- - // intrinsic-pointer-conversion regime.) + // UnsafeMutablePointer or OpaquePointer. // With pointer conversions enabled, map to the normal pointer types // without special hints. - Type pointeeType; - if (pointeeQualType->isVoidType()) - pointeeType = Impl.getNamedSwiftType(Impl.getStdlibModule(), "Void"); - else - pointeeType = Impl.importTypeIgnoreIUO( - pointeeQualType, ImportTypeKind::Pointee, AllowNSUIntegerAsInt, - Bridgeability::None); + Type pointeeType = Impl.importTypeIgnoreIUO( + pointeeQualType, ImportTypeKind::Value, AllowNSUIntegerAsInt, + Bridgeability::None); // If the pointed-to type is unrepresentable in Swift, or its C // alignment is greater than the maximum Swift alignment, import as @@ -446,9 +431,7 @@ namespace { ImportResult VisitBlockPointerType(const clang::BlockPointerType *type) { // Block pointer types are mapped to function types. - Type pointeeType = Impl.importTypeIgnoreIUO( - type->getPointeeType(), ImportTypeKind::Abstract, - AllowNSUIntegerAsInt, Bridging); + Type pointeeType = Visit(type->getPointeeType()).AbstractType; if (!pointeeType) return Type(); FunctionType *fTy = pointeeType->castTo(); @@ -478,15 +461,12 @@ namespace { } ImportResult VisitConstantArrayType(const clang::ConstantArrayType *type) { - // FIXME: In a function argument context, arrays should import as - // pointers. - // FIXME: Map to a real fixed-size Swift array type when we have those. // Importing as a tuple at least fills the right amount of space, and // we can cheese static-offset "indexing" using .$n operations. Type elementType = Impl.importTypeIgnoreIUO( - type->getElementType(), ImportTypeKind::Pointee, AllowNSUIntegerAsInt, + type->getElementType(), ImportTypeKind::Value, AllowNSUIntegerAsInt, Bridgeability::None); if (!elementType) return Type(); @@ -498,11 +478,7 @@ namespace { if (size > 4096) return Type(); - TupleTypeElt elt(elementType); - SmallVector elts; - for (size_t i = 0; i < size; ++i) - elts.push_back(elt); - + SmallVector elts{size, elementType}; return TupleType::get(elts, elementType->getASTContext()); } @@ -545,8 +521,7 @@ namespace { if (type->isVariadic()) return Type(); - // Import the result type. We currently provide no mechanism - // for this to be audited. + // Import the result type. auto resultTy = Impl.importTypeIgnoreIUO( type->getReturnType(), ImportTypeKind::Result, AllowNSUIntegerAsInt, Bridging, OTK_Optional); @@ -566,7 +541,7 @@ namespace { // FIXME: If we were walking TypeLocs, we could actually get parameter // names. The probably doesn't matter outside of a FuncDecl, which // we'll have to special-case, but it's an interesting bit of data loss. - // We also lose `noescape`. + // params.push_back(FunctionType::Param(swiftParamTy)); } @@ -637,8 +612,8 @@ namespace { ImportResult VisitObjCTypeParamType(const clang::ObjCTypeParamType *type) { // FIXME: This drops any added protocols on the floor, which is the whole - // point of ObjCTypeParamType. When not in Swift 3 compatibility mode, we - // should adjust the resulting type accordingly. + // point of ObjCTypeParamType. Fixing this might be source-breaking, + // though. rdar://problem/29763975 if (auto result = importObjCTypeParamDecl(type->getDecl())) return result.getValue(); // Fall back to importing the desugared type, which uses the parameter's @@ -663,7 +638,7 @@ namespace { // If that fails, fall back on importing the underlying type. if (!decl) return Visit(type->desugar()); - Type mappedType = getAdjustedTypeDeclReferenceType(decl); + Type mappedType = decl->getDeclaredInterfaceType(); if (getSwiftNewtypeAttr(type->getDecl(), Impl.CurrentVersion)) { if (isCFTypeDecl(type->getDecl())) { @@ -731,23 +706,13 @@ namespace { // Otherwise, recurse on the underlying type. We need to recompute // the hint, and if the typedef uses different bridgeability than the // context then we may also need to bypass the typedef. - auto underlyingType = type->desugar(); - - // Figure out the bridgeability we would normally use for this typedef. - auto typedefBridgeability = - getTypedefBridgeability(type->getDecl(), underlyingType); - - // Figure out the typedef we should actually use. - auto underlyingBridgeability = Bridging; - SwiftTypeConverter innerConverter(Impl, AllowNSUIntegerAsInt, - underlyingBridgeability); - auto underlyingResult = innerConverter.Visit(underlyingType); + auto underlyingResult = Visit(type->desugar()); // If we used different bridgeability than this typedef normally // would because we're in a non-bridgeable context, and therefore // the underlying type is different from the mapping of the typedef, // use the underlying type. - if (underlyingBridgeability != typedefBridgeability && + if (Bridging != getTypedefBridgeability(type->getDecl()) && !underlyingResult.AbstractType->isEqual(mappedType)) { return underlyingResult; } @@ -816,19 +781,6 @@ namespace { if (!decl) return nullptr; - return getAdjustedTypeDeclReferenceType(decl); - } - - /// Retrieve the adjusted type of a reference to the given type declaration. - Type getAdjustedTypeDeclReferenceType(TypeDecl *decl) { - // If the imported declaration is a bridged NSError, dig out - // the Code nested type. References to the enum type from C - // code need to map to the code type (which is ABI compatible with C), - // and the bridged error type is used elsewhere. - if (auto *structDecl = dyn_cast(decl)) - if (auto *codeEnum = Impl.lookupErrorCodeEnum(structDecl)) - return codeEnum->getDeclaredInterfaceType(); - return decl->getDeclaredInterfaceType(); } @@ -861,7 +813,7 @@ namespace { if (!decl) return nullptr; - return getAdjustedTypeDeclReferenceType(decl); + return decl->getDeclaredInterfaceType(); } } @@ -1131,7 +1083,6 @@ static bool canBridgeTypes(ImportTypeKind importKind) { case ImportTypeKind::Value: case ImportTypeKind::Variable: case ImportTypeKind::AuditedVariable: - case ImportTypeKind::Pointee: case ImportTypeKind::Enum: case ImportTypeKind::RecordField: return false; @@ -1159,7 +1110,6 @@ static bool isCFAudited(ImportTypeKind importKind) { case ImportTypeKind::ObjCCollectionElement: case ImportTypeKind::Variable: case ImportTypeKind::Result: - case ImportTypeKind::Pointee: case ImportTypeKind::Enum: case ImportTypeKind::RecordField: return false; @@ -1203,10 +1153,12 @@ static bool isNSString(Type type) { } static ImportedType adjustTypeForConcreteImport( - ClangImporter::Implementation &impl, clang::QualType clangType, - Type importedType, ImportTypeKind importKind, ImportHint hint, + ClangImporter::Implementation &impl, + ImportResult importResult, ImportTypeKind importKind, bool allowNSUIntegerAsInt, Bridgeability bridging, OptionalTypeKind optKind, bool resugarNSErrorPointer) { + Type importedType = importResult.AbstractType; + ImportHint hint = importResult.Hint; if (importKind == ImportTypeKind::Abstract) { return {importedType, false}; @@ -1431,7 +1383,6 @@ static ImportedType adjustTypeForConcreteImport( // optional type. bool isIUO = false; if (importKind != ImportTypeKind::Typedef && canImportAsOptional(hint)) { - optKind = getOptionalKind(importKind, optKind); isIUO = optKind == OTK_ImplicitlyUnwrappedOptional; if (optKind != OTK_None) importedType = OptionalType::get(importedType); @@ -1487,8 +1438,8 @@ ImportedType ClangImporter::Implementation::importType( // Now fix up the type based on how we're concretely using it. auto adjustedType = adjustTypeForConcreteImport( - *this, type, importResult.AbstractType, importKind, importResult.Hint, - allowNSUIntegerAsInt, bridging, optionality, resugarNSErrorPointer); + *this, importResult, importKind, allowNSUIntegerAsInt, bridging, + optionality, resugarNSErrorPointer); return adjustedType; } @@ -2077,15 +2028,11 @@ ImportedType ClangImporter::Implementation::importMethodType( bool paramIsIUO; if (kind == SpecialMethodKind::NSDictionarySubscriptGetter && paramTy->isObjCIdType()) { - auto optKind = - getOptionalKind(ImportTypeKind::Parameter, optionalityOfParam); + swiftParamTy = SwiftContext.getNSCopyingDecl()->getDeclaredType(); + if (optionalityOfParam != OTK_None) + swiftParamTy = OptionalType::get(swiftParamTy); - if (optKind == OTK_None) - swiftParamTy = getNSCopyingType(); - else - swiftParamTy = OptionalType::get(getNSCopyingType()); - - paramIsIUO = optKind == OTK_ImplicitlyUnwrappedOptional; + paramIsIUO = optionalityOfParam == OTK_ImplicitlyUnwrappedOptional; } else { ImportTypeKind importKind = ImportTypeKind::Parameter; if (param->hasAttr()) @@ -2346,9 +2293,6 @@ Type ClangImporter::Implementation::getNamedSwiftType(ModuleDecl *module, assert(!decl->hasClangNode() && "picked up the original type?"); - if (auto *lazyResolver = SwiftContext.getLazyResolver()) - lazyResolver->resolveDeclSignature(decl); - if (auto *nominalDecl = dyn_cast(decl)) return nominalDecl->getDeclaredType(); return decl->getDeclaredInterfaceType(); @@ -2496,10 +2440,6 @@ static Type getNamedProtocolType(ClangImporter::Implementation &impl, return Type(); } -Type ClangImporter::Implementation::getNSCopyingType() { - return getNamedProtocolType(*this, "NSCopying"); -} - Type ClangImporter::Implementation::getNSObjectProtocolType() { return getNamedProtocolType(*this, "NSObject"); } diff --git a/lib/ClangImporter/ImporterImpl.h b/lib/ClangImporter/ImporterImpl.h index bac23850f54b9..5e5fc64330657 100644 --- a/lib/ClangImporter/ImporterImpl.h +++ b/lib/ClangImporter/ImporterImpl.h @@ -152,13 +152,6 @@ enum class ImportTypeKind { /// This ensures that the parameter is not marked as Unmanaged. CFUnretainedOutParameter, - /// Import the type pointed to by a pointer or reference. - /// - /// This provides special treatment for pointer-to-ObjC-pointer - /// types, which get imported as pointers to *checked* optional, - /// *Pointer, instead of implicitly unwrapped optional as usual. - Pointee, - /// Import the type of an ObjC property. /// /// This enables the conversion of bridged types. Properties are always @@ -178,19 +171,18 @@ enum class ImportTypeKind { Enum }; -/// Controls whether a typedef for \p type should name the fully-bridged Swift -/// type or the original Clang type. +/// Controls whether \p decl, when imported, should name the fully-bridged +/// Swift type or the original Clang type. /// /// In either case we end up losing sugar at some uses sites, so this is more /// about what the right default is. -static inline Bridgeability getTypedefBridgeability( - const clang::TypedefNameDecl *decl, - clang::QualType type) { - return decl->hasAttr() - ? Bridgeability::Full - : type->isBlockPointerType() - ? Bridgeability::Full - : Bridgeability::None; +static inline Bridgeability +getTypedefBridgeability(const clang::TypedefNameDecl *decl) { + if (decl->hasAttr() || + decl->getUnderlyingType()->isBlockPointerType()) { + return Bridgeability::Full; + } + return Bridgeability::None; } /// Describes the kind of the C type that can be mapped to a stdlib @@ -943,9 +935,6 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation /// Retrieve the NSObject protocol type. Type getNSObjectProtocolType(); - /// Retrieve the NSCopying protocol type. - Type getNSCopyingType(); - /// Determines whether the given type matches an implicit type /// bound of "Hashable", which is used to validate NSDictionary/NSSet. bool matchesHashableBound(Type type); diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 8f9e04744d776..59c936c298753 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -337,7 +337,8 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args, Args.hasFlag(options::OPT_enable_astscope_lookup, options::OPT_disable_astscope_lookup, Opts.EnableASTScopeLookup) || Opts.DisableParserLookup; - Opts.CompareToASTScopeLookup |= Args.hasArg(OPT_compare_to_astscope_lookup); + Opts.CrosscheckUnqualifiedLookup |= + Args.hasArg(OPT_crosscheck_unqualified_lookup); Opts.StressASTScopeLookup |= Args.hasArg(OPT_stress_astscope_lookup); Opts.WarnIfASTScopeLookup |= Args.hasArg(OPT_warn_if_astscope_lookup); Opts.LazyASTScopes |= Args.hasArg(OPT_lazy_astscopes); @@ -945,6 +946,8 @@ static bool ParseTBDGenArgs(TBDGenOptions &Opts, ArgList &Args, Opts.InstallName = A->getValue(); } + Opts.IsInstallAPI = Args.hasArg(OPT_tbd_is_installapi); + if (const Arg *A = Args.getLastArg(OPT_tbd_compatibility_version)) { if (auto vers = version::Version::parseVersionString( A->getValue(), SourceLoc(), &Diags)) { diff --git a/lib/FrontendTool/FrontendTool.cpp b/lib/FrontendTool/FrontendTool.cpp index 8c846c863526c..e3f45ba415211 100644 --- a/lib/FrontendTool/FrontendTool.cpp +++ b/lib/FrontendTool/FrontendTool.cpp @@ -749,13 +749,16 @@ static void dumpAndPrintScopeMap(CompilerInvocation &Invocation, if (Invocation.getFrontendOptions().DumpScopeMapLocations.empty()) { llvm::errs() << "***Complete scope map***\n"; + scope.buildFullyExpandedTree(); scope.print(llvm::errs()); return; } // Probe each of the locations, and dump what we find. for (auto lineColumn : - Invocation.getFrontendOptions().DumpScopeMapLocations) + Invocation.getFrontendOptions().DumpScopeMapLocations) { + scope.buildFullyExpandedTree(); scope.dumpOneScopeMapLocation(lineColumn); + } } static SourceFile *getPrimaryOrMainSourceFile(CompilerInvocation &Invocation, @@ -1122,6 +1125,14 @@ static bool performCompile(CompilerInstance &Instance, if (Action == FrontendOptions::ActionType::Typecheck) { if (emitIndexData(Invocation, Instance)) return true; + // FIXME: Whole-module outputs with a non-whole-module -typecheck ought to + // be disallowed, but the driver implements -index-file mode by generating a + // regular whole-module frontend command line and modifying it to index just + // one file (by making it a primary) instead of all of them. If that + // invocation also has flags to emit whole-module supplementary outputs, the + // compiler can crash trying to access information for non-type-checked + // declarations in the non-primary files. For now, prevent those crashes by + // guarding the emission of whole-module supplementary outputs. if (opts.InputsAndOutputs.isWholeModule()) { if (emitAnyWholeModulePostTypeCheckSupplementaryOutputs(Instance, Invocation, diff --git a/lib/FrontendTool/ReferenceDependencies.cpp b/lib/FrontendTool/ReferenceDependencies.cpp index 6c73f563b646d..ef198c095afd1 100644 --- a/lib/FrontendTool/ReferenceDependencies.cpp +++ b/lib/FrontendTool/ReferenceDependencies.cpp @@ -22,6 +22,7 @@ #include "swift/AST/ModuleLoader.h" #include "swift/AST/NameLookup.h" #include "swift/AST/ReferencedNameTracker.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/Types.h" #include "swift/Basic/FileSystem.h" #include "swift/Basic/LLVM.h" diff --git a/lib/FrontendTool/TBD.cpp b/lib/FrontendTool/TBD.cpp index 41726d9d28109..b80537a24e95b 100644 --- a/lib/FrontendTool/TBD.cpp +++ b/lib/FrontendTool/TBD.cpp @@ -15,6 +15,7 @@ #include "swift/AST/Decl.h" #include "swift/AST/DiagnosticEngine.h" #include "swift/AST/DiagnosticsFrontend.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/Module.h" #include "swift/Basic/LLVM.h" #include "swift/Demangling/Demangle.h" diff --git a/lib/IDE/CodeCompletion.cpp b/lib/IDE/CodeCompletion.cpp index 0d93be13aa164..9dbcd6486be9a 100644 --- a/lib/IDE/CodeCompletion.cpp +++ b/lib/IDE/CodeCompletion.cpp @@ -23,6 +23,7 @@ #include "swift/AST/NameLookup.h" #include "swift/AST/ParameterList.h" #include "swift/AST/ProtocolConformance.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/SubstitutionMap.h" #include "swift/AST/USRGeneration.h" #include "swift/Basic/Defer.h" @@ -867,7 +868,7 @@ calculateTypeRelationForDecl(const Decl *D, Type ExpectedType, bool UseFuncResultType = true) { auto VD = dyn_cast(D); auto DC = D->getDeclContext(); - if (!VD || !VD->hasInterfaceType()) + if (!VD || !VD->getInterfaceType()) return CodeCompletionResult::ExpectedTypeRelation::Unrelated; if (auto FD = dyn_cast(VD)) { @@ -1213,11 +1214,9 @@ class CodeCompletionCallbacksImpl : public CodeCompletionCallbacks { std::vector RequestedModules; CodeCompletionConsumer &Consumer; CodeCompletionExpr *CodeCompleteTokenExpr = nullptr; - AssignExpr *AssignmentExpr; CompletionKind Kind = CompletionKind::None; Expr *ParsedExpr = nullptr; SourceLoc DotLoc; - TypeLoc ParsedTypeLoc; DeclContext *CurDeclContext = nullptr; DeclAttrKind AttrKind; @@ -1351,8 +1350,8 @@ class CodeCompletionCallbacksImpl : public CodeCompletionCallbacks { void completeTypeDeclResultBeginning() override; void completeTypeSimpleBeginning() override; - void completeTypeIdentifierWithDot(IdentTypeRepr *ITR) override; - void completeTypeIdentifierWithoutDot(IdentTypeRepr *ITR) override; + void completeTypeIdentifierWithDot() override; + void completeTypeIdentifierWithoutDot() override; void completeCaseStmtKeyword() override; void completeCaseStmtBeginning(CodeCompletionExpr *E) override; @@ -1367,7 +1366,6 @@ class CodeCompletionCallbacksImpl : public CodeCompletionCallbacks { void completeImportDecl(std::vector> &Path) override; void completeUnresolvedMember(CodeCompletionExpr *E, SourceLoc DotLoc) override; - void completeAssignmentRHS(AssignExpr *E) override; void completeCallArg(CodeCompletionExpr *E, bool isFirst) override; void completeReturnStmt(CodeCompletionExpr *E) override; void completeYieldStmt(CodeCompletionExpr *E, @@ -2047,8 +2045,8 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { auto *GenericSig = VD->getInnermostDeclContext() ->getGenericSignatureOfContext(); - assert(VD->hasValidSignature()); Type T = VD->getInterfaceType(); + assert(!T.isNull()); if (ExprType) { Type ContextTy = VD->getDeclContext()->getDeclaredInterfaceType(); @@ -2136,7 +2134,7 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { addValueBaseName(Builder, Name); setClangDeclKeywords(VD, Pairs, Builder); - if (!VD->hasValidSignature()) + if (!VD->hasInterfaceType()) return; // Add a type annotation. @@ -2432,7 +2430,7 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { addTypeAnnotation(Builder, AFT->getResult()); }; - if (!AFD || !AFD->hasInterfaceType() || + if (!AFD || !AFD->getInterfaceType() || !AFD->getInterfaceType()->is()) { // Probably, calling closure type expression. foundFunction(AFT); @@ -2799,8 +2797,7 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { setClangDeclKeywords(TAD, Pairs, Builder); addLeadingDot(Builder); Builder.addTextChunk(TAD->getName().str()); - if (TAD->hasInterfaceType()) { - auto underlyingType = TAD->getUnderlyingTypeLoc().getType(); + if (auto underlyingType = TAD->getUnderlyingType()) { if (underlyingType->hasError()) { Type parentType; if (auto nominal = TAD->getDeclContext()->getSelfNominalTypeDecl()) { @@ -2991,10 +2988,9 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { if (IsSwiftKeyPathExpr && !SwiftKeyPathFilter(D, Reason)) return; - - if (!D->hasInterfaceType()) - D->getASTContext().getLazyResolver()->resolveDeclSignature(D); - + + // FIXME(InterfaceTypeRequest): Remove this. + (void)D->getInterfaceType(); switch (Kind) { case LookupKind::ValueExpr: if (auto *CD = dyn_cast(D)) { @@ -3151,9 +3147,6 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { bool handleEnumElement(ValueDecl *D, DeclVisibilityKind Reason, DynamicLookupInfo dynamicLookupInfo) { - if (!D->hasInterfaceType()) - D->getASTContext().getLazyResolver()->resolveDeclSignature(D); - if (auto *EED = dyn_cast(D)) { addEnumElementRef(EED, Reason, dynamicLookupInfo, /*HasTypeContext=*/true); @@ -3162,8 +3155,6 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { llvm::DenseSet Elements; ED->getAllElements(Elements); for (auto *Ele : Elements) { - if (!Ele->hasInterfaceType()) - D->getASTContext().getLazyResolver()->resolveDeclSignature(Ele); addEnumElementRef(Ele, Reason, dynamicLookupInfo, /*HasTypeContext=*/true); } @@ -4337,9 +4328,6 @@ class CompletionOverrideLookup : public swift::VisibleDeclConsumer { (D->isStatic() && D->getAttrs().hasAttribute())) return; - if (!D->hasInterfaceType()) - D->getASTContext().getLazyResolver()->resolveDeclSignature(D); - bool hasIntroducer = hasFuncIntroducer || hasVarIntroducer || hasTypealiasIntroducer; @@ -4617,22 +4605,13 @@ void CodeCompletionCallbacksImpl::completeInPrecedenceGroup(SyntaxKind SK) { CurDeclContext = P.CurDeclContext; } -void CodeCompletionCallbacksImpl::completeTypeIdentifierWithDot( - IdentTypeRepr *ITR) { - if (!ITR) { - completeTypeSimpleBeginning(); - return; - } +void CodeCompletionCallbacksImpl::completeTypeIdentifierWithDot() { Kind = CompletionKind::TypeIdentifierWithDot; - ParsedTypeLoc = TypeLoc(ITR); CurDeclContext = P.CurDeclContext; } -void CodeCompletionCallbacksImpl::completeTypeIdentifierWithoutDot( - IdentTypeRepr *ITR) { - assert(ITR); +void CodeCompletionCallbacksImpl::completeTypeIdentifierWithoutDot() { Kind = CompletionKind::TypeIdentifierWithoutDot; - ParsedTypeLoc = TypeLoc(ITR); CurDeclContext = P.CurDeclContext; } @@ -4677,13 +4656,6 @@ void CodeCompletionCallbacksImpl::completeUnresolvedMember(CodeCompletionExpr *E this->DotLoc = DotLoc; } -void CodeCompletionCallbacksImpl::completeAssignmentRHS(AssignExpr *E) { - AssignmentExpr = E; - ParsedExpr = E->getDest(); - CurDeclContext = P.CurDeclContext; - Kind = CompletionKind::AssignmentRHS; -} - void CodeCompletionCallbacksImpl::completeCallArg(CodeCompletionExpr *E, bool isFirst) { CurDeclContext = P.CurDeclContext; @@ -4912,7 +4884,6 @@ void CodeCompletionCallbacksImpl::addKeywords(CodeCompletionResultSink &Sink, addDeclKeywords(Sink); addStmtKeywords(Sink, MaybeFuncBody); LLVM_FALLTHROUGH; - case CompletionKind::AssignmentRHS: case CompletionKind::ReturnStmtExpr: case CompletionKind::YieldStmtExpr: case CompletionKind::PostfixExprBeginning: @@ -5379,14 +5350,6 @@ void CodeCompletionCallbacksImpl::doneParsing() { Lookup.getUnresolvedMemberCompletions(ContextInfo.getPossibleTypes()); break; } - case CompletionKind::AssignmentRHS : { - SourceLoc Loc = P.Context.SourceMgr.getCodeCompletionLoc(); - if (auto destType = ParsedExpr->getType()) - Lookup.setExpectedTypes(destType->getRValueType(), - /*isSingleExpressionBody*/ false); - Lookup.getValueCompletionsInDeclContext(Loc, DefaultFilter); - break; - } case CompletionKind::CallArg : { ExprContextInfo ContextInfo(CurDeclContext, CodeCompleteTokenExpr); diff --git a/lib/IDE/ExprContextAnalysis.cpp b/lib/IDE/ExprContextAnalysis.cpp index 72e5b86a029c7..5ef47a964d136 100644 --- a/lib/IDE/ExprContextAnalysis.cpp +++ b/lib/IDE/ExprContextAnalysis.cpp @@ -284,12 +284,10 @@ static void collectPossibleCalleesByQualifiedLookup( continue; if (!isMemberDeclApplied(&DC, baseTy->getMetatypeInstanceType(), VD)) continue; - if (!VD->hasInterfaceType()) { - VD->getASTContext().getLazyResolver()->resolveDeclSignature(VD); - if (!VD->hasInterfaceType()) - continue; - } Type declaredMemberType = VD->getInterfaceType(); + if (!declaredMemberType) { + continue; + } if (!declaredMemberType->is()) continue; if (VD->getDeclContext()->isTypeContext()) { @@ -899,7 +897,7 @@ bool swift::ide::isReferenceableByImplicitMemberExpr( if (VD->isOperator()) return false; - if (!VD->hasInterfaceType()) + if (!VD->getInterfaceType()) return false; if (T->getOptionalObjectType() && diff --git a/lib/IDE/IDETypeChecking.cpp b/lib/IDE/IDETypeChecking.cpp index 8459f58e2382e..dd281397da363 100644 --- a/lib/IDE/IDETypeChecking.cpp +++ b/lib/IDE/IDETypeChecking.cpp @@ -10,19 +10,20 @@ // //===----------------------------------------------------------------------===// +#include "swift/AST/ASTDemangler.h" #include "swift/AST/ASTPrinter.h" #include "swift/AST/ASTContext.h" -#include "swift/AST/Identifier.h" -#include "swift/AST/Decl.h" -#include "swift/AST/GenericSignature.h" -#include "swift/AST/Types.h" #include "swift/AST/Attr.h" +#include "swift/AST/Decl.h" #include "swift/AST/Expr.h" #include "swift/AST/GenericEnvironment.h" +#include "swift/AST/GenericSignature.h" +#include "swift/AST/Identifier.h" #include "swift/AST/Module.h" #include "swift/AST/NameLookup.h" -#include "swift/AST/ASTDemangler.h" #include "swift/AST/ProtocolConformance.h" +#include "swift/AST/SourceFile.h" +#include "swift/AST/Types.h" #include "swift/Sema/IDETypeChecking.h" #include "swift/Sema/IDETypeCheckingRequests.h" #include "swift/IDE/SourceEntityWalker.h" @@ -303,15 +304,17 @@ struct SynthesizedExtensionAnalyzer::Implementation { } switch (Kind) { - case RequirementKind::Conformance: - // FIXME: This could be more accurate; check - // conformance instead of subtyping - if (!isConvertibleTo(First, Second, /*openArchetypes=*/true, *DC)) + case RequirementKind::Conformance: { + auto *M = DC->getParentModule(); + auto *Proto = Second->castTo()->getDecl(); + if (!First->isTypeParameter() && + !First->is() && + !M->conformsToProtocol(First, Proto)) return true; - else if (!isConvertibleTo(First, Second, /*openArchetypes=*/false, - *DC)) + if (!M->conformsToProtocol(First, Proto)) MergeInfo.addRequirement(GenericSig, First, Second, Kind); break; + } case RequirementKind::Superclass: if (!Second->isBindableToSuperclassOf(First)) { diff --git a/lib/IDE/ModuleInterfacePrinting.cpp b/lib/IDE/ModuleInterfacePrinting.cpp index 0b3de70e6e350..e87deadb53b05 100644 --- a/lib/IDE/ModuleInterfacePrinting.cpp +++ b/lib/IDE/ModuleInterfacePrinting.cpp @@ -20,6 +20,7 @@ #include "swift/AST/Module.h" #include "swift/AST/NameLookup.h" #include "swift/AST/PrintOptions.h" +#include "swift/AST/SourceFile.h" #include "swift/Basic/PrimitiveParsing.h" #include "swift/ClangImporter/ClangImporter.h" #include "swift/ClangImporter/ClangModule.h" diff --git a/lib/IDE/REPLCodeCompletion.cpp b/lib/IDE/REPLCodeCompletion.cpp index 6fd2d7873bb26..0b7db14712a67 100644 --- a/lib/IDE/REPLCodeCompletion.cpp +++ b/lib/IDE/REPLCodeCompletion.cpp @@ -18,6 +18,7 @@ #include "swift/AST/ASTContext.h" #include "swift/AST/DiagnosticSuppression.h" #include "swift/AST/Module.h" +#include "swift/AST/SourceFile.h" #include "swift/Basic/LLVM.h" #include "swift/Basic/SourceManager.h" #include "swift/Parse/Parser.h" diff --git a/lib/IDE/Refactoring.cpp b/lib/IDE/Refactoring.cpp index e8c460ed50ebe..d529944ea5e7a 100644 --- a/lib/IDE/Refactoring.cpp +++ b/lib/IDE/Refactoring.cpp @@ -2753,78 +2753,107 @@ bool RefactoringActionLocalizeString::performChange() { return false; } +struct MemberwiseParameter { + Identifier Name; + Type MemberType; + Expr *DefaultExpr; + + MemberwiseParameter(Identifier name, Type type, Expr *initialExpr) + : Name(name), MemberType(type), DefaultExpr(initialExpr) {} +}; + static void generateMemberwiseInit(SourceEditConsumer &EditConsumer, - SourceManager &SM, - SmallVectorImpl& memberNameVector, - SmallVectorImpl& memberTypeVector, - SourceLoc targetLocation) { - - assert(!memberTypeVector.empty()); - assert(memberTypeVector.size() == memberNameVector.size()); + SourceManager &SM, + ArrayRef memberVector, + SourceLoc targetLocation) { + assert(!memberVector.empty()); + EditConsumer.accept(SM, targetLocation, "\ninternal init("); - - for (size_t i = 0, n = memberTypeVector.size(); i < n ; i++) { - EditConsumer.accept(SM, targetLocation, memberNameVector[i] + ": " + - memberTypeVector[i]); - - if (i != memberTypeVector.size() - 1) { - EditConsumer.accept(SM, targetLocation, ", "); + auto insertMember = [&SM](const MemberwiseParameter &memberData, + llvm::raw_ostream &OS, bool wantsSeparator) { + OS << memberData.Name << ": " << memberData.MemberType.getString(); + if (auto *expr = memberData.DefaultExpr) { + if (isa(expr)) { + OS << " = nil"; + } else if (expr->getSourceRange().isValid()) { + auto range = + Lexer::getCharSourceRangeFromSourceRange( + SM, expr->getSourceRange()); + OS << " = " << SM.extractText(range); + } + } + + if (wantsSeparator) { + OS << ", "; } + }; + + // Process the initial list of members, inserting commas as appropriate. + std::string Buffer; + llvm::raw_string_ostream OS(Buffer); + for (const auto &memberData : memberVector.drop_back()) { + insertMember(memberData, OS, /*wantsSeparator*/ true); } - - EditConsumer.accept(SM, targetLocation, ") {\n"); - - for (auto varName: memberNameVector) { - EditConsumer.accept(SM, targetLocation, - "self." + varName + " = " + varName + "\n"); + + // Process the last (or perhaps, only) member. + insertMember(memberVector.back(), OS, /*wantsSeparator*/ false); + + // Synthesize the body. + OS << ") {\n"; + for (auto &member : memberVector) { + // self. = + OS << "self." << member.Name << " = " << member.Name << "\n"; } - - EditConsumer.accept(SM, targetLocation, "}\n"); + OS << "}\n"; + + // Accept the entire edit. + EditConsumer.accept(SM, targetLocation, OS.str()); } - -static SourceLoc collectMembersForInit(ResolvedCursorInfo CursorInfo, - SmallVectorImpl& memberNameVector, - SmallVectorImpl& memberTypeVector) { - + +static SourceLoc +collectMembersForInit(ResolvedCursorInfo CursorInfo, + SmallVectorImpl &memberVector) { + if (!CursorInfo.ValueD) return SourceLoc(); - ClassDecl *classDecl = dyn_cast(CursorInfo.ValueD); - if (!classDecl || classDecl->getStoredProperties().empty() || + NominalTypeDecl *nominalDecl = dyn_cast(CursorInfo.ValueD); + if (!nominalDecl || nominalDecl->getStoredProperties().empty() || CursorInfo.IsRef) { return SourceLoc(); } - - SourceLoc bracesStart = classDecl->getBraces().Start; + + SourceLoc bracesStart = nominalDecl->getBraces().Start; if (!bracesStart.isValid()) return SourceLoc(); SourceLoc targetLocation = bracesStart.getAdvancedLoc(1); if (!targetLocation.isValid()) return SourceLoc(); - - for (auto varDecl : classDecl->getStoredProperties()) { - auto parentPatternBinding = varDecl->getParentPatternBinding(); - if (!parentPatternBinding) + + for (auto varDecl : nominalDecl->getStoredProperties()) { + auto patternBinding = varDecl->getParentPatternBinding(); + if (!patternBinding) + continue; + + if (!varDecl->isMemberwiseInitialized(/*preferDeclaredProperties=*/true)) { continue; - - auto varDeclIndex = - parentPatternBinding->getPatternEntryIndexForVarDecl(varDecl); - - if (auto init = varDecl->getParentPatternBinding()->getInit(varDeclIndex)) { - if (init->getStartLoc().isValid()) - continue; } - - StringRef memberName = varDecl->getName().str(); - memberNameVector.push_back(memberName.str()); - - std::string memberType = varDecl->getType().getString(); - memberTypeVector.push_back(memberType); + + auto &entry = patternBinding->getPatternEntryForVarDecl(varDecl); + bool isExplicitlyInitialized = + entry.isInitialized() && entry.getEqualLoc().isValid(); + Expr *defaultInit = nullptr; + if (isExplicitlyInitialized || patternBinding->isDefaultInitializable()) { + defaultInit = varDecl->getParentInitializer(); + } + + memberVector.emplace_back(varDecl->getName(), + varDecl->getType(), defaultInit); } - if (memberNameVector.empty() || memberTypeVector.empty()) { + if (memberVector.empty()) { return SourceLoc(); } @@ -2834,25 +2863,18 @@ static SourceLoc collectMembersForInit(ResolvedCursorInfo CursorInfo, bool RefactoringActionMemberwiseInitLocalRefactoring:: isApplicable(ResolvedCursorInfo Tok, DiagnosticEngine &Diag) { - SmallVector memberNameVector; - SmallVector memberTypeVector; - - return collectMembersForInit(Tok, memberNameVector, - memberTypeVector).isValid(); + SmallVector memberVector; + return collectMembersForInit(Tok, memberVector).isValid(); } bool RefactoringActionMemberwiseInitLocalRefactoring::performChange() { - SmallVector memberNameVector; - SmallVector memberTypeVector; - - SourceLoc targetLocation = collectMembersForInit(CursorInfo, memberNameVector, - memberTypeVector); + SmallVector memberVector; + SourceLoc targetLocation = collectMembersForInit(CursorInfo, memberVector); if (targetLocation.isInvalid()) return true; - generateMemberwiseInit(EditConsumer, SM, memberNameVector, - memberTypeVector, targetLocation); + generateMemberwiseInit(EditConsumer, SM, memberVector, targetLocation); return false; } diff --git a/lib/IDE/SourceEntityWalker.cpp b/lib/IDE/SourceEntityWalker.cpp index cdb965e29adfd..364b3be704d20 100644 --- a/lib/IDE/SourceEntityWalker.cpp +++ b/lib/IDE/SourceEntityWalker.cpp @@ -19,6 +19,7 @@ #include "swift/AST/Module.h" #include "swift/AST/Pattern.h" #include "swift/AST/ParameterList.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/Stmt.h" #include "swift/AST/TypeRepr.h" #include "swift/AST/Types.h" diff --git a/lib/IDE/SyntaxModel.cpp b/lib/IDE/SyntaxModel.cpp index 19439a78fe6c9..60746c1f8b375 100644 --- a/lib/IDE/SyntaxModel.cpp +++ b/lib/IDE/SyntaxModel.cpp @@ -18,6 +18,7 @@ #include "swift/AST/Pattern.h" #include "swift/AST/ParameterList.h" #include "swift/AST/Module.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/Stmt.h" #include "swift/AST/TypeRepr.h" #include "swift/Basic/SourceManager.h" diff --git a/lib/IDE/TypeContextInfo.cpp b/lib/IDE/TypeContextInfo.cpp index ba0af397fedbc..53406604ac867 100644 --- a/lib/IDE/TypeContextInfo.cpp +++ b/lib/IDE/TypeContextInfo.cpp @@ -139,10 +139,8 @@ void ContextInfoCallbacks::getImplicitMembers( if (VD->isOperator()) return false; - if (!VD->hasInterfaceType()) { - TypeResolver->resolveDeclSignature(VD); - if (!VD->hasInterfaceType()) - return false; + if (!VD->getInterfaceType()) { + return false; } // Enum element decls can always be referenced by implicit member diff --git a/lib/IRGen/GenBuiltin.cpp b/lib/IRGen/GenBuiltin.cpp index 5fc6621b08e36..fecd109416b37 100644 --- a/lib/IRGen/GenBuiltin.cpp +++ b/lib/IRGen/GenBuiltin.cpp @@ -306,13 +306,22 @@ void irgen::emitBuiltinCall(IRGenFunction &IGF, const BuiltinInfo &Builtin, if (Builtin.ID == BuiltinValueKind::id) \ return emitCastOrBitCastBuiltin(IGF, resultType, out, args, \ BuiltinValueKind::id); - -#define BUILTIN_BINARY_OPERATION(id, name, attrs, overload) \ - if (Builtin.ID == BuiltinValueKind::id) { \ - llvm::Value *lhs = args.claimNext(); \ - llvm::Value *rhs = args.claimNext(); \ - llvm::Value *v = IGF.Builder.Create##id(lhs, rhs); \ - return out.add(v); \ + +#define BUILTIN_BINARY_OPERATION_OVERLOADED_STATIC(id, name, attrs, overload) \ + if (Builtin.ID == BuiltinValueKind::id) { \ + llvm::Value *lhs = args.claimNext(); \ + llvm::Value *rhs = args.claimNext(); \ + llvm::Value *v = IGF.Builder.Create##id(lhs, rhs); \ + return out.add(v); \ + } +#define BUILTIN_BINARY_OPERATION_POLYMORPHIC(id, name, attrs) \ + if (Builtin.ID == BuiltinValueKind::id) { \ + /* This builtin must be guarded so that dynamically it is never called. */ \ + IGF.emitTrap("invalid use of polymorphic builtin", /*Unreachable*/ false); \ + auto returnValue = llvm::UndefValue::get(IGF.IGM.Int8PtrTy); \ + /* Consume the arguments of the builtin. */ \ + (void)args.claimAll(); \ + return out.add(returnValue); \ } #define BUILTIN_RUNTIME_CALL(id, name, attrs) \ diff --git a/lib/IRGen/GenEnum.cpp b/lib/IRGen/GenEnum.cpp index 0f6c0e8b73996..daf017d338cfa 100644 --- a/lib/IRGen/GenEnum.cpp +++ b/lib/IRGen/GenEnum.cpp @@ -5777,10 +5777,7 @@ EnumImplStrategy::get(TypeConverter &TC, SILType type, EnumDecl *theEnum) { elementsWithPayload.push_back({elt, nativeTI, nativeTI}); continue; } - - if (!elt->hasInterfaceType()) - TC.IGM.Context.getLazyResolver()->resolveDeclSignature(elt); - + // Compute whether this gives us an apparent payload or dynamic layout. // Note that we do *not* apply substitutions from a bound generic instance // yet. We want all instances of a generic enum to share an implementation diff --git a/lib/IRGen/GenMeta.cpp b/lib/IRGen/GenMeta.cpp index a1fe16c3e40c1..dd3a00a63c3f4 100644 --- a/lib/IRGen/GenMeta.cpp +++ b/lib/IRGen/GenMeta.cpp @@ -1683,14 +1683,16 @@ namespace { } void addUnderlyingTypeAndConformances() { - auto sig = O->getOpaqueInterfaceGenericSignature() - ? O->getOpaqueInterfaceGenericSignature()->getCanonicalSignature() - : CanGenericSignature(); + auto sig = O->getOpaqueInterfaceGenericSignature(); auto underlyingType = Type(O->getUnderlyingInterfaceType()) .subst(*O->getUnderlyingTypeSubstitutions()) ->getCanonicalType(sig); + + auto contextSig = O->getGenericSignature() + ? O->getGenericSignature()->getCanonicalSignature() + : CanGenericSignature(); - B.addRelativeAddress(IGM.getTypeRef(underlyingType, sig, + B.addRelativeAddress(IGM.getTypeRef(underlyingType, contextSig, MangledTypeRefRole::Metadata).first); auto opaqueType = O->getDeclaredInterfaceType() @@ -1704,7 +1706,7 @@ namespace { auto witnessTableRef = IGM.emitWitnessTableRefString( underlyingType, underlyingConformance, - O->getGenericSignature(), + contextSig, /*setLowBit*/ false); B.addRelativeAddress(witnessTableRef); } diff --git a/lib/IRGen/GenProto.cpp b/lib/IRGen/GenProto.cpp index 01bb82e915a54..93110ba059c3b 100644 --- a/lib/IRGen/GenProto.cpp +++ b/lib/IRGen/GenProto.cpp @@ -2960,11 +2960,6 @@ NecessaryBindings::forFunctionInvocations(IRGenModule &IGM, GenericTypeRequirements::GenericTypeRequirements(IRGenModule &IGM, NominalTypeDecl *typeDecl) : TheDecl(typeDecl) { - - // FIXME: Remove this once getGenericSignature() is a request. - if (!typeDecl->hasInterfaceType()) - IGM.Context.getLazyResolver()->resolveDeclSignature(typeDecl); - // We only need to do something here if the declaration context is // somehow generic. auto ncGenerics = typeDecl->getGenericSignatureOfContext(); diff --git a/lib/IRGen/GenType.cpp b/lib/IRGen/GenType.cpp index cacdd78698f42..b9d336e2c069d 100644 --- a/lib/IRGen/GenType.cpp +++ b/lib/IRGen/GenType.cpp @@ -1920,9 +1920,6 @@ namespace { return true; for (auto field : decl->getStoredProperties()) { - if (!field->hasInterfaceType()) - IGM.Context.getLazyResolver()->resolveDeclSignature(field); - if (visit(field->getInterfaceType()->getCanonicalType())) return true; } @@ -1947,9 +1944,6 @@ namespace { if (!elt->hasAssociatedValues() || elt->isIndirect()) continue; - if (!elt->hasInterfaceType()) - IGM.Context.getLazyResolver()->resolveDeclSignature(elt); - if (visit(elt->getArgumentInterfaceType()->getCanonicalType())) return true; } diff --git a/lib/IRGen/IRGenDebugInfo.cpp b/lib/IRGen/IRGenDebugInfo.cpp index c086a5d1ae47f..17123e9b5daa0 100644 --- a/lib/IRGen/IRGenDebugInfo.cpp +++ b/lib/IRGen/IRGenDebugInfo.cpp @@ -734,6 +734,8 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo { NoLoc, NoLoc, IGM.Context.getIdentifier(ArchetypeName), NoLoc, /*genericparams*/ nullptr, IGM.Context.TheBuiltinModule); Entry->setUnderlyingType(IGM.Context.TheRawPointerType); + Entry->setValidationToChecked(); + Entry->computeType(); return Entry; } diff --git a/lib/IRGen/IRGenModule.h b/lib/IRGen/IRGenModule.h index 50ad9478319e5..54510e64ad198 100644 --- a/lib/IRGen/IRGenModule.h +++ b/lib/IRGen/IRGenModule.h @@ -23,6 +23,7 @@ #include "swift/AST/Decl.h" #include "swift/AST/Module.h" #include "swift/AST/ReferenceCounting.h" +#include "swift/AST/SourceFile.h" #include "swift/Basic/ClusteredBitVector.h" #include "swift/Basic/LLVM.h" #include "swift/Basic/OptimizationMode.h" diff --git a/lib/Index/Index.cpp b/lib/Index/Index.cpp index 5c21b602553f3..5f8a33ee410e3 100644 --- a/lib/Index/Index.cpp +++ b/lib/Index/Index.cpp @@ -19,6 +19,7 @@ #include "swift/AST/Module.h" #include "swift/AST/ParameterList.h" #include "swift/AST/ProtocolConformance.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/Types.h" #include "swift/AST/USRGeneration.h" #include "swift/Basic/SourceManager.h" @@ -925,7 +926,7 @@ bool IndexSwiftASTWalker::reportRelatedTypeRef(const TypeLoc &Ty, SymbolRoleSet IndexSymbol Info; if (!reportRef(TAD, IdLoc, Info, None)) return false; - if (auto Ty = TAD->getUnderlyingTypeLoc().getType()) { + if (auto Ty = TAD->getUnderlyingType()) { NTD = Ty->getAnyNominal(); isImplicit = true; } diff --git a/lib/Index/IndexRecord.cpp b/lib/Index/IndexRecord.cpp index ef0f97ccff04a..162e47a6a4955 100644 --- a/lib/Index/IndexRecord.cpp +++ b/lib/Index/IndexRecord.cpp @@ -13,14 +13,15 @@ #include "swift/Index/IndexRecord.h" #include "swift/AST/ASTContext.h" #include "swift/AST/Decl.h" +#include "swift/AST/DiagnosticsFrontend.h" #include "swift/AST/Expr.h" #include "swift/AST/Module.h" +#include "swift/AST/ModuleLoader.h" #include "swift/AST/ParameterList.h" #include "swift/AST/Pattern.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/Stmt.h" #include "swift/AST/Types.h" -#include "swift/AST/DiagnosticsFrontend.h" -#include "swift/AST/ModuleLoader.h" #include "swift/ClangImporter/ClangModule.h" #include "swift/Index/Index.h" #include "clang/Basic/FileManager.h" diff --git a/lib/Migrator/OptionalTryMigratorPass.cpp b/lib/Migrator/OptionalTryMigratorPass.cpp index 4767f7f12cb75..d4620b43a3f00 100644 --- a/lib/Migrator/OptionalTryMigratorPass.cpp +++ b/lib/Migrator/OptionalTryMigratorPass.cpp @@ -12,6 +12,7 @@ #include "swift/AST/ASTVisitor.h" #include "swift/AST/Expr.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/Module.h" #include "swift/AST/NameLookup.h" #include "swift/AST/ParameterList.h" diff --git a/lib/Parse/ASTGen.cpp b/lib/Parse/ASTGen.cpp index d11abc6d11dcf..8ff9a94f7f174 100644 --- a/lib/Parse/ASTGen.cpp +++ b/lib/Parse/ASTGen.cpp @@ -10,64 +10,73 @@ // //===----------------------------------------------------------------------===// -#include "swift/Basic/SourceManager.h" #include "swift/Parse/ASTGen.h" +#include "swift/Basic/SourceManager.h" +#include "swift/Parse/CodeCompletionCallbacks.h" +#include "swift/Parse/Parser.h" + using namespace swift; using namespace swift::syntax; -SourceLoc ASTGen::generate(TokenSyntax Tok, SourceLoc &Loc) { +SourceLoc ASTGen::generate(const TokenSyntax &Tok, const SourceLoc Loc) { return advanceLocBegin(Loc, Tok); } -Expr *ASTGen::generate(IntegerLiteralExprSyntax &Expr, SourceLoc &Loc) { +Expr *ASTGen::generate(const IntegerLiteralExprSyntax &Expr, + const SourceLoc Loc) { auto Digits = Expr.getDigits(); auto Text = copyAndStripUnderscores(Digits.getText()); auto DigitsLoc = advanceLocBegin(Loc, Digits); return new (Context) IntegerLiteralExpr(Text, DigitsLoc); } -Expr *ASTGen::generate(FloatLiteralExprSyntax &Expr, SourceLoc &Loc) { +Expr *ASTGen::generate(const FloatLiteralExprSyntax &Expr, + const SourceLoc Loc) { auto Digits = Expr.getFloatingDigits(); auto Text = copyAndStripUnderscores(Digits.getText()); auto DigitsLoc = advanceLocBegin(Loc, Digits); return new (Context) FloatLiteralExpr(Text, DigitsLoc); } -Expr *ASTGen::generate(NilLiteralExprSyntax &Expr, SourceLoc &Loc) { +Expr *ASTGen::generate(const NilLiteralExprSyntax &Expr, const SourceLoc Loc) { auto Nil = Expr.getNilKeyword(); auto NilLoc = advanceLocBegin(Loc, Nil); return new (Context) NilLiteralExpr(NilLoc); } -Expr *ASTGen::generate(BooleanLiteralExprSyntax &Expr, SourceLoc &Loc) { +Expr *ASTGen::generate(const BooleanLiteralExprSyntax &Expr, + const SourceLoc Loc) { auto Boolean = Expr.getBooleanLiteral(); auto Value = Boolean.getTokenKind() == tok::kw_true; auto BooleanLoc = advanceLocBegin(Loc, Boolean); return new (Context) BooleanLiteralExpr(Value, BooleanLoc); } -Expr *ASTGen::generate(PoundFileExprSyntax &Expr, SourceLoc &Loc) { +Expr *ASTGen::generate(const PoundFileExprSyntax &Expr, const SourceLoc Loc) { return generateMagicIdentifierLiteralExpression(Expr.getPoundFile(), Loc); } -Expr *ASTGen::generate(PoundLineExprSyntax &Expr, SourceLoc &Loc) { +Expr *ASTGen::generate(const PoundLineExprSyntax &Expr, const SourceLoc Loc) { return generateMagicIdentifierLiteralExpression(Expr.getPoundLine(), Loc); } -Expr *ASTGen::generate(PoundColumnExprSyntax &Expr, SourceLoc &Loc) { +Expr *ASTGen::generate(const PoundColumnExprSyntax &Expr, const SourceLoc Loc) { return generateMagicIdentifierLiteralExpression(Expr.getPoundColumn(), Loc); } -Expr *ASTGen::generate(PoundFunctionExprSyntax &Expr, SourceLoc &Loc) { +Expr *ASTGen::generate(const PoundFunctionExprSyntax &Expr, + const SourceLoc Loc) { return generateMagicIdentifierLiteralExpression(Expr.getPoundFunction(), Loc); } -Expr *ASTGen::generate(PoundDsohandleExprSyntax &Expr, SourceLoc &Loc) { - return generateMagicIdentifierLiteralExpression(Expr.getPoundDsohandle(), Loc); +Expr *ASTGen::generate(const PoundDsohandleExprSyntax &Expr, + const SourceLoc Loc) { + return generateMagicIdentifierLiteralExpression(Expr.getPoundDsohandle(), + Loc); } -Expr *ASTGen::generate(UnknownExprSyntax &Expr, SourceLoc &Loc) { +Expr *ASTGen::generate(const UnknownExprSyntax &Expr, const SourceLoc Loc) { if (Expr.getNumChildren() == 1 && Expr.getChild(0)->isToken()) { Syntax Token = *Expr.getChild(0); tok Kind = Token.getRaw()->getTokenKind(); @@ -88,11 +97,8 @@ Expr *ASTGen::generate(UnknownExprSyntax &Expr, SourceLoc &Loc) { return nullptr; } -TypeRepr *ASTGen::generate(TypeSyntax Type, SourceLoc &Loc) { - TypeRepr *TypeAST = lookupType(Type); - - if (TypeAST) - return TypeAST; +TypeRepr *ASTGen::generate(const TypeSyntax &Type, const SourceLoc Loc) { + TypeRepr *TypeAST = nullptr; if (auto SimpleIdentifier = Type.getAs()) TypeAST = generate(*SimpleIdentifier, Loc); @@ -118,6 +124,8 @@ TypeRepr *ASTGen::generate(TypeSyntax Type, SourceLoc &Loc) { TypeAST = generate(*Unwrapped, Loc); else if (auto Attributed = Type.getAs()) TypeAST = generate(*Attributed, Loc); + else if (auto CompletionTy = Type.getAs()) + TypeAST = generate(*CompletionTy, Loc); else if (auto Unknown = Type.getAs()) TypeAST = generate(*Unknown, Loc); @@ -129,7 +137,8 @@ TypeRepr *ASTGen::generate(TypeSyntax Type, SourceLoc &Loc) { return cacheType(Type, TypeAST); } -TypeRepr *ASTGen::generate(FunctionTypeSyntax Type, SourceLoc &Loc) { +TypeRepr *ASTGen::generate(const FunctionTypeSyntax &Type, + const SourceLoc Loc) { auto ArgumentTypes = generateTuple(Type.getLeftParen(), Type.getArguments(), Type.getRightParen(), Loc, /*IsFunction=*/true); @@ -145,10 +154,10 @@ TypeRepr *ASTGen::generate(FunctionTypeSyntax Type, SourceLoc &Loc) { FunctionTypeRepr(nullptr, ArgumentTypes, ThrowsLoc, ArrowLoc, ReturnType); } -TupleTypeRepr *ASTGen::generateTuple(TokenSyntax LParen, - TupleTypeElementListSyntax Elements, - TokenSyntax RParen, SourceLoc &Loc, - bool IsFunction) { +TupleTypeRepr *ASTGen::generateTuple(const TokenSyntax &LParen, + const TupleTypeElementListSyntax &Elements, + const TokenSyntax &RParen, + const SourceLoc Loc, bool IsFunction) { auto LPLoc = generate(LParen, Loc); auto RPLoc = generate(RParen, Loc); @@ -205,7 +214,8 @@ TupleTypeRepr *ASTGen::generateTuple(TokenSyntax LParen, EllipsisLoc, EllipsisIdx); } -TypeRepr *ASTGen::generate(AttributedTypeSyntax Type, SourceLoc &Loc) { +TypeRepr *ASTGen::generate(const AttributedTypeSyntax &Type, + const SourceLoc Loc) { // todo [gsoc]: improve this after refactoring attribute parsing auto TypeAST = generate(Type.getBaseType(), Loc); @@ -224,7 +234,7 @@ TypeRepr *ASTGen::generate(AttributedTypeSyntax Type, SourceLoc &Loc) { if (AttrKind == TAK_convention) { auto Argument = Attr.getArgument()->castTo(); - auto Convention = Context.getIdentifier(Argument.getText()); + auto Convention = Context.getIdentifier(Argument.getIdentifierText()); TypeAttrs.convention = Convention.str(); } @@ -261,19 +271,20 @@ TypeRepr *ASTGen::generate(AttributedTypeSyntax Type, SourceLoc &Loc) { return TypeAST; } -TypeRepr *ASTGen::generate(TupleTypeSyntax Type, SourceLoc &Loc) { +TypeRepr *ASTGen::generate(const TupleTypeSyntax &Type, const SourceLoc Loc) { return generateTuple(Type.getLeftParen(), Type.getElements(), Type.getRightParen(), Loc); } -TypeRepr *ASTGen::generate(SomeTypeSyntax Type, SourceLoc &Loc) { +TypeRepr *ASTGen::generate(const SomeTypeSyntax &Type, const SourceLoc Loc) { auto Some = Type.getSomeSpecifier(); auto SomeLoc = generate(Some, Loc); auto BaseType = generate(Type.getBaseType(), Loc); return new (Context) OpaqueReturnTypeRepr(SomeLoc, BaseType); } -TypeRepr *ASTGen::generate(CompositionTypeSyntax Type, SourceLoc &Loc) { +TypeRepr *ASTGen::generate(const CompositionTypeSyntax &Type, + const SourceLoc Loc) { auto Elements = Type.getElements(); auto FirstElem = Elements[0]; auto LastElem = Elements[Elements.size() - 1]; @@ -310,7 +321,7 @@ TypeRepr *ASTGen::generate(CompositionTypeSyntax Type, SourceLoc &Loc) { } void ASTGen::gatherTypeIdentifierComponents( - TypeSyntax Component, SourceLoc &Loc, + const TypeSyntax &Component, const SourceLoc Loc, SmallVectorImpl &Components) { if (auto SimpleIdentifier = Component.getAs()) { auto ComponentType = generateIdentifier(*SimpleIdentifier, Loc); @@ -330,7 +341,8 @@ void ASTGen::gatherTypeIdentifierComponents( } template -TypeRepr *ASTGen::generateSimpleOrMemberIdentifier(T Type, SourceLoc &Loc) { +TypeRepr *ASTGen::generateSimpleOrMemberIdentifier(const T &Type, + const SourceLoc Loc) { SmallVector Components; gatherTypeIdentifierComponents(Type, Loc, Components); std::reverse(Components.begin(), Components.end()); @@ -339,15 +351,17 @@ TypeRepr *ASTGen::generateSimpleOrMemberIdentifier(T Type, SourceLoc &Loc) { auto FirstComponent = IdentType->getComponentRange().front(); // Lookup element #0 through our current scope chains in case it is some // thing local (this returns null if nothing is found). - if (auto Entry = lookupInScope(FirstComponent->getIdentifier())) + if (auto Entry = lookupInScope(FirstComponent->getIdentifier())) { if (auto *TD = dyn_cast(Entry)) FirstComponent->setValue(TD, nullptr); + } return IdentType; } template -ComponentIdentTypeRepr *ASTGen::generateIdentifier(T Type, SourceLoc &Loc) { +ComponentIdentTypeRepr *ASTGen::generateIdentifier(const T &Type, + const SourceLoc Loc) { auto IdentifierLoc = advanceLocBegin(Loc, Type.getName()); auto Identifier = Context.getIdentifier(Type.getName().getIdentifierText()); if (auto Clause = Type.getGenericArgumentClause()) { @@ -364,20 +378,28 @@ ComponentIdentTypeRepr *ASTGen::generateIdentifier(T Type, SourceLoc &Loc) { return new (Context) SimpleIdentTypeRepr(IdentifierLoc, Identifier); } -TypeRepr *ASTGen::generate(SimpleTypeIdentifierSyntax Type, SourceLoc &Loc) { +TypeRepr *ASTGen::generate(const SimpleTypeIdentifierSyntax &Type, + const SourceLoc Loc) { if (Type.getName().getTokenKind() == tok::kw_Any) { auto AnyLoc = advanceLocBegin(Loc, Type.getName()); return CompositionTypeRepr::createEmptyComposition(Context, AnyLoc); } + if (Type.getName().getText() == "class") { + auto classLoc = advanceLocBegin(Loc, Type.getName()); + return new (Context) + SimpleIdentTypeRepr(classLoc, Context.getIdentifier("AnyObject")); + } return generateSimpleOrMemberIdentifier(Type, Loc); } -TypeRepr *ASTGen::generate(MemberTypeIdentifierSyntax Type, SourceLoc &Loc) { +TypeRepr *ASTGen::generate(const MemberTypeIdentifierSyntax &Type, + SourceLoc Loc) { return generateSimpleOrMemberIdentifier(Type, Loc); } -TypeRepr *ASTGen::generate(DictionaryTypeSyntax Type, SourceLoc &Loc) { +TypeRepr *ASTGen::generate(const DictionaryTypeSyntax &Type, + const SourceLoc Loc) { TypeRepr *ValueType = generate(Type.getValueType(), Loc); TypeRepr *KeyType = generate(Type.getKeyType(), Loc); auto LBraceLoc = advanceLocBegin(Loc, Type.getLeftSquareBracket()); @@ -387,7 +409,7 @@ TypeRepr *ASTGen::generate(DictionaryTypeSyntax Type, SourceLoc &Loc) { return new (Context) DictionaryTypeRepr(KeyType, ValueType, ColonLoc, Range); } -TypeRepr *ASTGen::generate(ArrayTypeSyntax Type, SourceLoc &Loc) { +TypeRepr *ASTGen::generate(const ArrayTypeSyntax &Type, SourceLoc Loc) { TypeRepr *ElementType = generate(Type.getElementType(), Loc); SourceLoc LBraceLoc, RBraceLoc; if (Type.getLeftSquareBracket().isPresent()) @@ -401,7 +423,8 @@ TypeRepr *ASTGen::generate(ArrayTypeSyntax Type, SourceLoc &Loc) { return new (Context) ArrayTypeRepr(ElementType, {LBraceLoc, RBraceLoc}); } -TypeRepr *ASTGen::generate(MetatypeTypeSyntax Type, SourceLoc &Loc) { +TypeRepr *ASTGen::generate(const MetatypeTypeSyntax &Type, + const SourceLoc Loc) { TypeRepr *BaseType = generate(Type.getBaseType(), Loc); auto TypeOrProtocol = Type.getTypeOrProtocol(); auto TypeOrProtocolLoc = advanceLocBegin(Loc, TypeOrProtocol); @@ -410,48 +433,59 @@ TypeRepr *ASTGen::generate(MetatypeTypeSyntax Type, SourceLoc &Loc) { return new (Context) ProtocolTypeRepr(BaseType, TypeOrProtocolLoc); } -TypeRepr *ASTGen::generate(OptionalTypeSyntax Type, SourceLoc &Loc) { +TypeRepr *ASTGen::generate(const OptionalTypeSyntax &Type, + const SourceLoc Loc) { TypeRepr *WrappedType = generate(Type.getWrappedType(), Loc); auto QuestionLoc = advanceLocBegin(Loc, Type.getQuestionMark()); return new (Context) OptionalTypeRepr(WrappedType, QuestionLoc); } -TypeRepr *ASTGen::generate(ImplicitlyUnwrappedOptionalTypeSyntax Type, - SourceLoc &Loc) { +TypeRepr *ASTGen::generate(const ImplicitlyUnwrappedOptionalTypeSyntax &Type, + const SourceLoc Loc) { TypeRepr *WrappedType = generate(Type.getWrappedType(), Loc); auto ExclamationLoc = advanceLocBegin(Loc, Type.getExclamationMark()); return new (Context) ImplicitlyUnwrappedOptionalTypeRepr(WrappedType, ExclamationLoc); } -TypeRepr *ASTGen::generate(UnknownTypeSyntax Type, SourceLoc &Loc) { +TypeRepr *ASTGen::generate(const CodeCompletionTypeSyntax &Type, + const SourceLoc Loc) { + auto base = Type.getBase(); + if (!base) + return nullptr; + + TypeRepr *parsedTyR = generate(*base, Loc); + if (parsedTyR) { + if (P.CodeCompletion) + P.CodeCompletion->setParsedTypeLoc(parsedTyR); + } + return parsedTyR; +} + +TypeRepr *ASTGen::generate(const UnknownTypeSyntax &Type, const SourceLoc Loc) { auto ChildrenCount = Type.getNumChildren(); // Recover from old-style protocol composition: // `protocol` `<` protocols `>` if (ChildrenCount >= 2) { - auto Protocol = Type.getChild(0)->getAs(); + auto keyword = Type.getChild(0)->getAs(); - if (Protocol && Protocol->getText() == "protocol") { + if (keyword && keyword->getText() == "protocol") { + auto keywordLoc = advanceLocBegin(Loc, *keyword); auto LAngle = Type.getChild(1); - - SmallVector Protocols; - for (unsigned i = 2; i < Type.getNumChildren(); i++) - if (auto PType = Type.getChild(i)->getAs()) - Protocols.push_back(*PType); - auto RAngle = Type.getChild(ChildrenCount - 1); - auto ProtocolLoc = advanceLocBegin(Loc, *Protocol); auto LAngleLoc = advanceLocBegin(Loc, *LAngle); auto RAngleLoc = advanceLocBegin(Loc, *RAngle); - SmallVector ProtocolTypes; - for (auto &&P : llvm::reverse(Protocols)) - ProtocolTypes.push_back(generate(P, Loc)); - std::reverse(std::begin(ProtocolTypes), std::end(ProtocolTypes)); + SmallVector protocols; + for (unsigned i = 2; i < Type.getNumChildren(); i++) { + if (auto elem = Type.getChild(i)->getAs()) + if (auto proto = generate(*elem, Loc)) + protocols.push_back(proto); + } - return CompositionTypeRepr::create(Context, ProtocolTypes, ProtocolLoc, + return CompositionTypeRepr::create(Context, protocols, keywordLoc, {LAngleLoc, RAngleLoc}); } } @@ -470,7 +504,8 @@ TypeRepr *ASTGen::generate(UnknownTypeSyntax Type, SourceLoc &Loc) { auto LParen = Type.getChild(0)->getAs(); if (LParen && LParen->getTokenKind() == tok::l_paren) { auto LParenLoc = advanceLocBegin(Loc, *LParen); - auto EndLoc = advanceLocBegin(Loc, *Type.getChild(Type.getNumChildren() - 1)); + auto EndLoc = + advanceLocBegin(Loc, *Type.getChild(Type.getNumChildren() - 1)); return TupleTypeRepr::createEmpty(Context, {LParenLoc, EndLoc}); } } @@ -479,8 +514,8 @@ TypeRepr *ASTGen::generate(UnknownTypeSyntax Type, SourceLoc &Loc) { return nullptr; } -SmallVector ASTGen::generate(GenericArgumentListSyntax Args, - SourceLoc &Loc) { +SmallVector +ASTGen::generate(const GenericArgumentListSyntax &Args, const SourceLoc Loc) { SmallVector Types; Types.resize(Args.size()); @@ -493,7 +528,8 @@ SmallVector ASTGen::generate(GenericArgumentListSyntax Args, return Types; } -TypeRepr *ASTGen::generate(GenericArgumentSyntax Arg, SourceLoc &Loc) { +TypeRepr *ASTGen::generate(const GenericArgumentSyntax &Arg, + const SourceLoc Loc) { return generate(Arg.getArgumentType(), Loc); } @@ -512,6 +548,164 @@ StringRef ASTGen::copyAndStripUnderscores(StringRef Orig, ASTContext &Context) { return StringRef(start, p - start); } +GenericParamList * +ASTGen::generate(const GenericParameterClauseListSyntax &clauses, + const SourceLoc Loc) { + GenericParamList *curr = nullptr; + + // The first one is the outmost generic parameter list. + for (const auto &clause : clauses) { + auto params = generate(clause, Loc); + if (!params) + continue; + params->setOuterParameters(curr); + curr = params; + } + + return curr; +} + +GenericParamList *ASTGen::generate(const GenericParameterClauseSyntax &clause, + const SourceLoc Loc) { + SmallVector params; + params.reserve(clause.getGenericParameterList().getNumChildren()); + + for (auto elem : clause.getGenericParameterList()) { + + DeclAttributes attrs; + if (auto attrsSyntax = elem.getAttributes()) { + auto attrsLoc = advanceLocBegin(Loc, *attrsSyntax->getFirstToken()); + attrs = getDeclAttributes(attrsLoc); + } + Identifier name = Context.getIdentifier(elem.getName().getIdentifierText()); + SourceLoc nameLoc = advanceLocBegin(Loc, elem.getName()); + + // We always create generic type parameters with an invalid depth. + // Semantic analysis fills in the depth when it processes the generic + // parameter list. + auto param = new (Context) + GenericTypeParamDecl(P.CurDeclContext, name, nameLoc, + GenericTypeParamDecl::InvalidDepth, params.size()); + + if (auto inherited = elem.getInheritedType()) { + if (auto ty = generate(*inherited, Loc)) { + SmallVector constraints = {generate(*inherited, Loc)}; + param->setInherited(Context.AllocateCopy(constraints)); + } + } + + // Attach attributes. + param->getAttrs() = attrs; + + // Add this parameter to the scope. + addToScope(param); + + params.push_back(param); + } + if (params.empty()) + return nullptr; + + SourceLoc whereLoc; + SmallVector requirements; + if (auto whereClause = clause.getObsoletedWhereClause()) { + requirements.reserve(whereClause->getRequirementList().size()); + for (auto elem : whereClause->getRequirementList()) { + if (auto req = generate(elem, Loc)) + requirements.push_back(*req); + } + // There's an invariant that valid 'where' loc means that there's at + // at least one valid requirement. + if (!requirements.empty()) + whereLoc = advanceLocBegin(Loc, whereClause->getWhereKeyword()); + } + + auto lAngleLoc = advanceLocBegin(Loc, clause.getLeftAngleBracket()); + auto rAngleLoc = advanceLocBegin(Loc, clause.getRightAngleBracket()); + return GenericParamList::create(Context, lAngleLoc, params, whereLoc, + requirements, rAngleLoc); +} + +Optional +ASTGen::generate(const syntax::GenericRequirementSyntax &req, + const SourceLoc Loc) { + if (auto sameTypeReq = req.getBody().getAs()) { + auto firstType = generate(sameTypeReq->getLeftTypeIdentifier(), Loc); + auto secondType = generate(sameTypeReq->getRightTypeIdentifier(), Loc); + if (!firstType || !secondType) + return None; + return RequirementRepr::getSameType( + firstType, advanceLocBegin(Loc, sameTypeReq->getEqualityToken()), + secondType); + } else if (auto conformanceReq = + req.getBody().getAs()) { + auto firstType = generate(conformanceReq->getLeftTypeIdentifier(), Loc); + auto secondType = generate(conformanceReq->getRightTypeIdentifier(), Loc); + if (!firstType || !secondType) + return None; + return RequirementRepr::getTypeConstraint( + firstType, advanceLocBegin(Loc, conformanceReq->getColon()), + secondType); + } else if (auto layoutReq = req.getBody().getAs()) { + auto firstType = generate(layoutReq->getLeftTypeIdentifier(), Loc); + auto layout = generate(layoutReq->getLayoutConstraint(), Loc); + if (!firstType || layout.isNull()) + return None; + auto colonLoc = advanceLocBegin(Loc, layoutReq->getColon()); + auto layoutLoc = advanceLocBegin(Loc, layoutReq->getLayoutConstraint()); + return RequirementRepr::getLayoutConstraint( + firstType, colonLoc, LayoutConstraintLoc(layout, layoutLoc)); + } else { + llvm_unreachable("invalid syntax kind for requirement body"); + } +} + +static LayoutConstraintKind getLayoutConstraintKind(Identifier &id, + ASTContext &Ctx) { + if (id == Ctx.Id_TrivialLayout) + return LayoutConstraintKind::TrivialOfExactSize; + if (id == Ctx.Id_TrivialAtMostLayout) + return LayoutConstraintKind::TrivialOfAtMostSize; + if (id == Ctx.Id_RefCountedObjectLayout) + return LayoutConstraintKind::RefCountedObject; + if (id == Ctx.Id_NativeRefCountedObjectLayout) + return LayoutConstraintKind::NativeRefCountedObject; + if (id == Ctx.Id_ClassLayout) + return LayoutConstraintKind::Class; + if (id == Ctx.Id_NativeClassLayout) + return LayoutConstraintKind::NativeClass; + return LayoutConstraintKind::UnknownLayout; +} + +LayoutConstraint ASTGen::generate(const LayoutConstraintSyntax &constraint, + const SourceLoc Loc) { + auto name = Context.getIdentifier(constraint.getName().getIdentifierText()); + auto constraintKind = getLayoutConstraintKind(name, Context); + assert(constraintKind != LayoutConstraintKind::UnknownLayout); + + // Non-trivial constraint kinds don't have size/alignment. + // TODO: Diagnose if it's supplied? + if (!LayoutConstraintInfo::isTrivial(constraintKind)) + return LayoutConstraint::getLayoutConstraint(constraintKind, Context); + + // '_Trivial' without explicit size/alignment. + if (!constraint.getSize()) + return LayoutConstraint::getLayoutConstraint(LayoutConstraintKind::Trivial, + Context); + + int size = 0; + if (auto sizeSyntax = constraint.getSize()) + sizeSyntax->getText().getAsInteger(10, size); + assert(size >= 0); + + int alignment = 0; + if (auto alignmentSyntax = constraint.getAlignment()) + alignmentSyntax->getText().getAsInteger(10, alignment); + assert(alignment >= 0); + + return LayoutConstraint::getLayoutConstraint(constraintKind, size, alignment, + Context); +} + SourceLoc ASTGen::advanceLocBegin(const SourceLoc &Loc, const Syntax &Node) { return Loc.getAdvancedLoc(Node.getAbsolutePosition().getOffset()); } @@ -520,14 +714,16 @@ StringRef ASTGen::copyAndStripUnderscores(StringRef Orig) { return copyAndStripUnderscores(Orig, Context); } -Expr *ASTGen::generateMagicIdentifierLiteralExpression(TokenSyntax PoundToken, - SourceLoc &Loc) { +Expr * +ASTGen::generateMagicIdentifierLiteralExpression(const TokenSyntax &PoundToken, + const SourceLoc Loc) { auto Kind = getMagicIdentifierLiteralKind(PoundToken.getTokenKind()); auto KindLoc = advanceLocBegin(Loc, PoundToken); return new (Context) MagicIdentifierLiteralExpr(Kind, KindLoc); } -MagicIdentifierLiteralExpr::Kind ASTGen::getMagicIdentifierLiteralKind(tok Kind) { +MagicIdentifierLiteralExpr::Kind +ASTGen::getMagicIdentifierLiteralKind(tok Kind) { switch (Kind) { case tok::kw___COLUMN__: case tok::pound_column: @@ -550,9 +746,11 @@ MagicIdentifierLiteralExpr::Kind ASTGen::getMagicIdentifierLiteralKind(tok Kind) } ValueDecl *ASTGen::lookupInScope(DeclName Name) { - return Context.LangOpts.EnableASTScopeLookup && Context.LangOpts.DisableParserLookup - ? nullptr - : (*ParserState)->getScopeInfo().lookupValueName(Name); + return P.lookupInScope(Name); +} + +void ASTGen::addToScope(ValueDecl *D, bool diagnoseRedefinitions) { + P.addToScope(D, diagnoseRedefinitions); } TypeRepr *ASTGen::cacheType(TypeSyntax Type, TypeRepr *TypeAST) { @@ -565,14 +763,26 @@ TypeRepr *ASTGen::lookupType(TypeSyntax Type) { return Found != TypeCache.end() ? Found->second : nullptr; } -TypeRepr *ASTGen::addType(TypeRepr *Type, const SourceLoc &Loc) { - return Types.insert({Loc, Type}).first->second; +void ASTGen::addType(TypeRepr *Type, const SourceLoc Loc) { + Types.insert({Loc, Type}); } -bool ASTGen::hasType(const SourceLoc &Loc) const { +bool ASTGen::hasType(const SourceLoc Loc) const { return Types.find(Loc) != Types.end(); } -TypeRepr *ASTGen::getType(const SourceLoc &Loc) const { +TypeRepr *ASTGen::getType(const SourceLoc Loc) const { return Types.find(Loc)->second; } + +void ASTGen::addDeclAttributes(DeclAttributes attrs, SourceLoc Loc) { + ParsedDeclAttrs.insert({Loc, attrs}); +} + +bool ASTGen::hasDeclAttributes(SourceLoc Loc) const { + return ParsedDeclAttrs.find(Loc) != ParsedDeclAttrs.end(); +} + +DeclAttributes ASTGen::getDeclAttributes(SourceLoc Loc) const { + return ParsedDeclAttrs.find(Loc)->second; +} diff --git a/lib/Parse/DebuggerContextChange.h b/lib/Parse/DebuggerContextChange.h new file mode 100644 index 0000000000000..b6ab3fe0f8ed0 --- /dev/null +++ b/lib/Parse/DebuggerContextChange.h @@ -0,0 +1,151 @@ +//===--- DebuggerContextChange.h --------------------------------*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2019 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 +// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_PARSE_DEBUGGERCONTEXTCHANGE_H +#define SWIFT_PARSE_DEBUGGERCONTEXTCHANGE_H + +#include "swift/AST/DebuggerClient.h" +#include "swift/AST/Decl.h" +#include "swift/AST/Identifier.h" +#include "swift/AST/SourceFile.h" +#include "swift/Parse/Parser.h" + +namespace swift { + +/// A RAII object for deciding whether this DeclKind needs special +/// treatment when parsing in the "debugger context", and implementing +/// that treatment. The problem arises because, when lldb +/// uses swift to parse expressions, it needs to emulate the current +/// frame's scope. We do that, for instance, by making a class extension +/// and running the code in a function in that extension. +/// +/// This causes two kinds of issues: +/// 1) Some DeclKinds require to be parsed in TopLevel contexts only. +/// 2) Sometimes the debugger wants a Decl to live beyond the current +/// function invocation, in which case it should be parsed at the +/// file scope level so it will be set up correctly for this purpose. +/// +/// Creating an instance of this object will cause it to figure out +/// whether we are in the debugger function, whether it needs to swap +/// the Decl that is currently being parsed. +/// If you have created the object, instead of returning the result +/// with makeParserResult, use the object's fixupParserResult. If +/// no swap has occurred, these methods will work the same. +/// If the decl has been moved, then Parser::markWasHandled will be +/// called on the Decl, and you should call declWasHandledAlready +/// before you consume the Decl to see if you actually need to +/// consume it. +/// If you are making one of these objects to address issue 1, call +/// the constructor that only takes a DeclKind, and it will be moved +/// unconditionally. Otherwise pass in the Name and DeclKind and the +/// DebuggerClient will be asked whether to move it or not. +class DebuggerContextChange { +protected: + Parser &P; + Identifier Name; + SourceFile *SF; + Optional CC; + +public: + DebuggerContextChange(Parser &P) : P(P), SF(nullptr) { + if (!inDebuggerContext()) + return; + else + switchContext(); + } + + DebuggerContextChange(Parser &P, Identifier &Name, DeclKind Kind) + : P(P), Name(Name), SF(nullptr) { + if (!inDebuggerContext()) + return; + bool globalize = false; + + DebuggerClient *debug_client = getDebuggerClient(); + if (!debug_client) + return; + + globalize = debug_client->shouldGlobalize(Name, Kind); + + if (globalize) + switchContext(); + } + + bool movedToTopLevel() { return CC.hasValue(); } + + template + ParserResult fixupParserResult(ParserResult &Result) { + ParserStatus Status = Result; + return fixupParserResult(Status, Result.getPtrOrNull()); + } + + template ParserResult fixupParserResult(T *D) { + if (CC.hasValue()) { + swapDecl(D); + } + return ParserResult(D); + } + + template + ParserResult fixupParserResult(ParserStatus Status, T *D) { + if (CC.hasValue() && !Status.isError()) { + // If there is an error, don't do our splicing trick, + // just return the Decl and the status for reporting. + swapDecl(D); + } + return makeParserResult(Status, D); + } + + // The destructor doesn't need to do anything, the CC's destructor will + // pop the context if we set it. + ~DebuggerContextChange() {} + +protected: + DebuggerClient *getDebuggerClient() { + ModuleDecl *PM = P.CurDeclContext->getParentModule(); + if (!PM) + return nullptr; + else + return PM->getDebugClient(); + } + + bool inDebuggerContext() { + if (!P.Context.LangOpts.DebuggerSupport) + return false; + if (!P.CurDeclContext) + return false; + auto *func_decl = dyn_cast(P.CurDeclContext); + if (!func_decl) + return false; + + if (!func_decl->getAttrs().hasAttribute()) + return false; + + return true; + } + + void switchContext() { + SF = P.CurDeclContext->getParentSourceFile(); + CC.emplace(P, SF); + } + + void swapDecl(Decl *D) { + assert(SF); + DebuggerClient *debug_client = getDebuggerClient(); + assert(debug_client); + debug_client->didGlobalize(D); + SF->Decls.push_back(D); + P.markWasHandled(D); + } +}; +} // namespace swift + +#endif diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index aa4bc7e29c883..7eff6979dc668 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -14,8 +14,10 @@ // //===----------------------------------------------------------------------===// +#include "DebuggerContextChange.h" #include "swift/Parse/Parser.h" #include "swift/Parse/CodeCompletionCallbacks.h" +#include "swift/Parse/ParsedSyntaxBuilders.h" #include "swift/Parse/ParsedSyntaxRecorder.h" #include "swift/Parse/ParseSILSupport.h" #include "swift/Parse/SyntaxParsingContext.h" @@ -29,6 +31,7 @@ #include "swift/AST/Module.h" #include "swift/AST/ParameterList.h" #include "swift/AST/ParseRequests.h" +#include "swift/AST/SourceFile.h" #include "swift/Basic/Defer.h" #include "swift/Basic/Statistic.h" #include "swift/Basic/StringExtras.h" @@ -46,142 +49,6 @@ using namespace swift; using namespace syntax; -namespace { - /// A RAII object for deciding whether this DeclKind needs special - /// treatment when parsing in the "debugger context", and implementing - /// that treatment. The problem arises because, when lldb - /// uses swift to parse expressions, it needs to emulate the current - /// frame's scope. We do that, for instance, by making a class extension - /// and running the code in a function in that extension. - /// - /// This causes two kinds of issues: - /// 1) Some DeclKinds require to be parsed in TopLevel contexts only. - /// 2) Sometimes the debugger wants a Decl to live beyond the current - /// function invocation, in which case it should be parsed at the - /// file scope level so it will be set up correctly for this purpose. - /// - /// Creating an instance of this object will cause it to figure out - /// whether we are in the debugger function, whether it needs to swap - /// the Decl that is currently being parsed. - /// If you have created the object, instead of returning the result - /// with makeParserResult, use the object's fixupParserResult. If - /// no swap has occurred, these methods will work the same. - /// If the decl has been moved, then Parser::markWasHandled will be - /// called on the Decl, and you should call declWasHandledAlready - /// before you consume the Decl to see if you actually need to - /// consume it. - /// If you are making one of these objects to address issue 1, call - /// the constructor that only takes a DeclKind, and it will be moved - /// unconditionally. Otherwise pass in the Name and DeclKind and the - /// DebuggerClient will be asked whether to move it or not. - class DebuggerContextChange { - protected: - Parser &P; - Identifier Name; - SourceFile *SF; - Optional CC; - public: - DebuggerContextChange (Parser &P) - : P(P), SF(nullptr) { - if (!inDebuggerContext()) - return; - else - switchContext(); - } - - DebuggerContextChange (Parser &P, Identifier &Name, DeclKind Kind) - : P(P), Name(Name), SF(nullptr) { - if (!inDebuggerContext()) - return; - bool globalize = false; - - DebuggerClient *debug_client = getDebuggerClient(); - if (!debug_client) - return; - - globalize = debug_client->shouldGlobalize(Name, Kind); - - if (globalize) - switchContext(); - } - - bool movedToTopLevel() { - return CC.hasValue(); - } - - template - ParserResult - fixupParserResult(ParserResult &Result) { - ParserStatus Status = Result; - return fixupParserResult(Status, Result.getPtrOrNull()); - } - - template - ParserResult - fixupParserResult(T *D) { - if (CC.hasValue()) { - swapDecl(D); - } - return ParserResult(D); - } - - template - ParserResult - fixupParserResult(ParserStatus Status, T *D) { - if (CC.hasValue() && !Status.isError()) { - // If there is an error, don't do our splicing trick, - // just return the Decl and the status for reporting. - swapDecl(D); - } - return makeParserResult(Status, D); - } - - // The destructor doesn't need to do anything, the CC's destructor will - // pop the context if we set it. - ~DebuggerContextChange () {} - protected: - - DebuggerClient *getDebuggerClient() - { - ModuleDecl *PM = P.CurDeclContext->getParentModule(); - if (!PM) - return nullptr; - else - return PM->getDebugClient(); - } - - bool inDebuggerContext() { - if (!P.Context.LangOpts.DebuggerSupport) - return false; - if (!P.CurDeclContext) - return false; - auto *func_decl = dyn_cast(P.CurDeclContext); - if (!func_decl) - return false; - - if (!func_decl->getAttrs().hasAttribute()) - return false; - - return true; - } - - void switchContext () { - SF = P.CurDeclContext->getParentSourceFile(); - CC.emplace (P, SF); - } - - void swapDecl (Decl *D) - { - assert (SF); - DebuggerClient *debug_client = getDebuggerClient(); - assert (debug_client); - debug_client->didGlobalize(D); - SF->Decls.push_back(D); - P.markWasHandled(D); - } - }; -} // end anonymous namespace - /// Main entrypoint for the parser. /// /// \verbatim @@ -4189,16 +4056,10 @@ ParserStatus Parser::parseInheritance(SmallVectorImpl &Inherited, return Status; } -enum class TokenProperty { - None, - StartsWithLess, -}; - static ParserStatus parseIdentifierDeclName(Parser &P, Identifier &Result, SourceLoc &Loc, - StringRef DeclKindName, tok ResyncT1, tok ResyncT2, - tok ResyncT3, tok ResyncT4, - TokenProperty ResyncP1) { + StringRef DeclKindName, + llvm::function_ref canRecover) { if (P.Tok.is(tok::identifier)) { Loc = P.consumeIdentifier(&Result); @@ -4237,9 +4098,7 @@ parseIdentifierDeclName(Parser &P, Identifier &Result, SourceLoc &Loc, .fixItReplace(P.Tok.getLoc(), "`" + P.Tok.getText().str() + "`"); // Recover if the next token is one of the expected tokens. - auto Next = P.peekToken(); - if (Next.isAny(ResyncT1, ResyncT2, ResyncT3, ResyncT4) || - (ResyncP1 != TokenProperty::None && P.startsWithLess(Next))) { + if (canRecover(P.peekToken())) { llvm::SmallString<32> Name(P.Tok.getText()); // Append an invalid character so that nothing can resolve to this name. Name += "#"; @@ -4256,38 +4115,6 @@ parseIdentifierDeclName(Parser &P, Identifier &Result, SourceLoc &Loc, return makeParserError(); } -static ParserStatus -parseIdentifierDeclName(Parser &P, Identifier &Result, SourceLoc &L, - StringRef DeclKindName, tok ResyncT1, tok ResyncT2) { - return parseIdentifierDeclName(P, Result, L, DeclKindName, ResyncT1, ResyncT2, - tok::NUM_TOKENS, tok::NUM_TOKENS, - TokenProperty::None); -} - -static ParserStatus -parseIdentifierDeclName(Parser &P, Identifier &Result, SourceLoc &L, - StringRef DeclKindName, tok ResyncT1, tok ResyncT2, - tok ResyncT3, tok ResyncT4) { - return parseIdentifierDeclName(P, Result, L, DeclKindName, ResyncT1, ResyncT2, - ResyncT3, ResyncT4, TokenProperty::None); -} - -static ParserStatus -parseIdentifierDeclName(Parser &P, Identifier &Result, SourceLoc &L, - StringRef DeclKindName, tok ResyncT1, tok ResyncT2, - TokenProperty ResyncP1) { - return parseIdentifierDeclName(P, Result, L, DeclKindName, ResyncT1, ResyncT2, - tok::NUM_TOKENS, tok::NUM_TOKENS, ResyncP1); -} - -static ParserStatus -parseIdentifierDeclName(Parser &P, Identifier &Result, SourceLoc &L, - StringRef DeclKindName, tok ResyncT1, tok ResyncT2, - tok ResyncT3, TokenProperty ResyncP1) { - return parseIdentifierDeclName(P, Result, L, DeclKindName, ResyncT1, ResyncT2, - ResyncT3, tok::NUM_TOKENS, ResyncP1); -} - /// Add a fix-it to remove the space in consecutive identifiers. /// Add a camel-cased option if it is different than the first option. void Parser::diagnoseConsecutiveIDs(StringRef First, SourceLoc FirstLoc, @@ -4806,8 +4633,9 @@ parseDeclTypeAlias(Parser::ParseDeclOptions Flags, DeclAttributes &Attributes) { SourceLoc IdLoc; ParserStatus Status; - Status |= parseIdentifierDeclName(*this, Id, IdLoc, "typealias", - tok::colon, tok::equal); + Status |= parseIdentifierDeclName( + *this, Id, IdLoc, "typealias", + [](const Token &next) { return next.isAny(tok::colon, tok::equal); }); if (Status.isError()) { TmpCtxt->setTransparent(); return nullptr; @@ -4871,7 +4699,7 @@ parseDeclTypeAlias(Parser::ParseDeclOptions Flags, DeclAttributes &Attributes) { Status |= UnderlyingTy; } - TAD->getUnderlyingTypeLoc() = UnderlyingTy.getPtrOrNull(); + TAD->setUnderlyingTypeRepr(UnderlyingTy.getPtrOrNull()); TAD->getAttrs() = Attributes; // Parse a 'where' clause if present, adding it to our GenericParamList. @@ -4921,9 +4749,10 @@ ParserResult Parser::parseDeclAssociatedType(Parser::ParseDeclOptions } else { AssociatedTypeLoc = consumeToken(tok::kw_associatedtype); } - - Status = parseIdentifierDeclName(*this, Id, IdLoc, "associatedtype", - tok::colon, tok::equal); + + Status = parseIdentifierDeclName( + *this, Id, IdLoc, "associatedtype", + [](const Token &next) { return next.isAny(tok::colon, tok::equal); }); if (Status.isError()) return nullptr; @@ -6144,8 +5973,10 @@ ParserResult Parser::parseDeclFunc(SourceLoc StaticLoc, // because we're aggressive about recovering/providing good diagnostics for // beginners. auto NameStatus = parseIdentifierDeclName( - *this, SimpleName, NameLoc, "function", tok::l_paren, tok::arrow, - tok::l_brace, TokenProperty::StartsWithLess); + *this, SimpleName, NameLoc, "function", [&](const Token &next) { + return next.isAny(tok::l_paren, tok::arrow, tok::l_brace) || + startsWithLess(next); + }); if (NameStatus.isError()) return nullptr; } @@ -6388,9 +6219,10 @@ ParserResult Parser::parseDeclEnum(ParseDeclOptions Flags, SourceLoc EnumNameLoc; ParserStatus Status; - Status |= parseIdentifierDeclName(*this, EnumName, EnumNameLoc, "enum", - tok::colon, tok::l_brace, - TokenProperty::StartsWithLess); + Status |= parseIdentifierDeclName( + *this, EnumName, EnumNameLoc, "enum", [&](const Token &next) { + return next.isAny(tok::colon, tok::l_brace) || startsWithLess(next); + }); if (Status.isError()) return nullptr; @@ -6494,9 +6326,11 @@ Parser::parseDeclEnumCase(ParseDeclOptions Flags, } if (Tok.is(tok::identifier)) { - Status |= parseIdentifierDeclName(*this, Name, NameLoc, "enum 'case'", - tok::l_paren, tok::kw_case, tok::colon, - tok::r_brace); + Status |= parseIdentifierDeclName( + *this, Name, NameLoc, "enum 'case'", [](const Token &next) { + return next.isAny(tok::l_paren, tok::kw_case, tok::colon, + tok::r_brace); + }); assert(Status.isSuccess()); if (DotLoc.isValid()) diagnose(DotLoc, diag::enum_case_dot_prefix) @@ -6668,9 +6502,10 @@ ParserResult Parser::parseDeclStruct(ParseDeclOptions Flags, SourceLoc StructNameLoc; ParserStatus Status; - Status |= parseIdentifierDeclName(*this, StructName, StructNameLoc, "struct", - tok::colon, tok::l_brace, - TokenProperty::StartsWithLess); + Status |= parseIdentifierDeclName( + *this, StructName, StructNameLoc, "struct", [&](const Token &next) { + return next.isAny(tok::colon, tok::l_brace) || startsWithLess(next); + }); if (Status.isError()) return nullptr; @@ -6759,9 +6594,10 @@ ParserResult Parser::parseDeclClass(ParseDeclOptions Flags, SourceLoc ClassNameLoc; ParserStatus Status; - Status |= parseIdentifierDeclName(*this, ClassName, ClassNameLoc, "class", - tok::colon, tok::l_brace, - TokenProperty::StartsWithLess); + Status |= parseIdentifierDeclName( + *this, ClassName, ClassNameLoc, "class", [&](const Token &next) { + return next.isAny(tok::colon, tok::l_brace) || startsWithLess(next); + }); if (Status.isError()) return nullptr; @@ -6878,8 +6714,9 @@ parseDeclProtocol(ParseDeclOptions Flags, DeclAttributes &Attributes) { Identifier ProtocolName; ParserStatus Status; - Status |= parseIdentifierDeclName(*this, ProtocolName, NameLoc, "protocol", - tok::colon, tok::l_brace); + Status |= parseIdentifierDeclName( + *this, ProtocolName, NameLoc, "protocol", + [&](const Token &next) { return next.isAny(tok::colon, tok::l_brace); }); if (Status.isError()) return nullptr; diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 1e5ceade9b5fc..9ec2aae577909 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -279,28 +279,6 @@ ParserResult Parser::parseExprSequence(Diag<> Message, auto *assign = new (Context) AssignExpr(equalsLoc); SequencedExprs.push_back(assign); Message = diag::expected_expr_assignment; - if (Tok.is(tok::code_complete)) { - if (CodeCompletion) { - auto RHS = new (Context) ErrorExpr( - SourceRange(Tok.getRange().getStart(), Tok.getRange().getEnd())); - assign->setSrc(RHS); - SequencedExprs.pop_back(); - assign->setDest(SequencedExprs.back()); - SequencedExprs.pop_back(); - SequencedExprs.push_back(assign); - CodeCompletion->completeAssignmentRHS(assign); - } - consumeToken(); - if (!SequencedExprs.empty() && (SequencedExprs.size() & 1) == 0) { - // Make sure we have odd number of sequence exprs. - SequencedExprs.pop_back(); - } - auto Result = SequencedExprs.size() == 1 ? - makeParserResult(SequencedExprs[0]): - makeParserResult(SequenceExpr::create(Context, SequencedExprs)); - Result.setHasCodeCompletion(); - return Result; - } break; } diff --git a/lib/Parse/ParseGeneric.cpp b/lib/Parse/ParseGeneric.cpp index 912784c0ad044..ee00e32c6aad8 100644 --- a/lib/Parse/ParseGeneric.cpp +++ b/lib/Parse/ParseGeneric.cpp @@ -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 - 2019 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 @@ -10,185 +10,185 @@ // //===----------------------------------------------------------------------===// // -// Generic Parsing and AST Building +// Generic Parsing // //===----------------------------------------------------------------------===// #include "swift/Parse/Parser.h" #include "swift/AST/DiagnosticsParse.h" -#include "swift/Parse/CodeCompletionCallbacks.h" +#include "swift/Parse/ParsedSyntaxBuilders.h" +#include "swift/Parse/ParsedSyntaxRecorder.h" #include "swift/Parse/SyntaxParsingContext.h" -#include "swift/Parse/Lexer.h" -#include "swift/Syntax/SyntaxBuilders.h" -#include "swift/Syntax/SyntaxNodes.h" + using namespace swift; using namespace swift::syntax; -/// parseGenericParameters - Parse a sequence of generic parameters, e.g., -/// < T : Comparable, U : Container> along with an optional requires clause. +/// Parse a list of generic parameters. +/// +/// generic-parameter-clause-list: +/// generic-parameter-clause generic-parameter-clause* +ParserStatus Parser::parseSILGenericParamsSyntax( + Optional &result) { + assert(isInSILMode()); + ParserStatus status; + if (!startsWithLess(Tok)) + return status; + + SmallVector clauses; + do { + auto result = parseGenericParameterClauseSyntax(); + status |= result.getStatus(); + if (!result.isNull()) + clauses.push_back(result.get()); + } while (startsWithLess(Tok)); + + result = ParsedSyntaxRecorder::makeGenericParameterClauseList(clauses, + *SyntaxContext); + return status; +} + +/// Parse a sequence of generic parameters, e.g. '' +/// along with an optional requires clause. /// -/// generic-params: -/// '<' generic-param (',' generic-param)* where-clause? '>' +/// generic-parameter-clause: +/// '<' generic-paramter (',' generic-parameter)* where-clause? '>' /// -/// generic-param: +/// generic-parameter: /// identifier -/// identifier ':' type-identifier -/// identifier ':' type-composition -/// -/// When parsing the generic parameters, this routine establishes a new scope -/// and adds those parameters to the scope. -ParserResult Parser::parseGenericParameters() { - SyntaxParsingContext GPSContext(SyntaxContext, SyntaxKind::GenericParameterClause); - // Parse the opening '<'. +/// identifier ':' type +ParsedSyntaxResult +Parser::parseGenericParameterClauseSyntax() { assert(startsWithLess(Tok) && "Generic parameter list must start with '<'"); - return parseGenericParameters(consumeStartingLess()); -} + ParsedGenericParameterClauseSyntaxBuilder builder(*SyntaxContext); + ParserStatus status; -ParserStatus -Parser::parseGenericParametersBeforeWhere(SourceLoc LAngleLoc, - SmallVectorImpl &GenericParams) { - ParserStatus Result; - SyntaxParsingContext GPSContext(SyntaxContext, SyntaxKind::GenericParameterList); - bool HasNextParam; + // Parse '<'. + SourceLoc LAngleLoc = Tok.getLoc(); + builder.useLeftAngleBracket(consumeStartingLessSyntax()); + + // Parse parameters. + bool hasNext = true; do { - SyntaxParsingContext GParamContext(SyntaxContext, SyntaxKind::GenericParameter); - // Note that we're parsing a declaration. - StructureMarkerRAII ParsingDecl(*this, Tok.getLoc(), - StructureMarkerKind::Declaration); - - if (ParsingDecl.isFailed()) { - return makeParserError(); - } + ParsedGenericParameterSyntaxBuilder paramBuilder(*SyntaxContext); // Parse attributes. - DeclAttributes attributes; - if (Tok.hasComment()) - attributes.add(new (Context) RawDocCommentAttr(Tok.getCommentRange())); - parseDeclAttributeList(attributes); + // TODO: Implement syntax attribute parsing. + DeclAttributes attrsAST; + parseDeclAttributeList(attrsAST); + auto attrs = SyntaxContext->popIf(); + if (attrs) { + paramBuilder.useAttributes(std::move(*attrs)); + Generator.addDeclAttributes(attrsAST, attrsAST.getStartLoc()); + } // Parse the name of the parameter. - Identifier Name; - SourceLoc NameLoc; - if (parseIdentifier(Name, NameLoc, - diag::expected_generics_parameter_name)) { - Result.setIsParseError(); + auto ident = Context.getIdentifier(Tok.getText()); + auto name = parseIdentifierSyntax(diag::expected_generics_parameter_name); + if (!name) { + status.setIsParseError(); break; } + paramBuilder.useName(std::move(*name)); // Parse the ':' followed by a type. - SmallVector Inherited; if (Tok.is(tok::colon)) { - (void)consumeToken(); - ParserResult Ty; - + paramBuilder.useColon(consumeTokenSyntax(tok::colon)); if (Tok.isAny(tok::identifier, tok::code_complete, tok::kw_protocol, tok::kw_Any)) { - Ty = parseType(); - } else if (Tok.is(tok::kw_class)) { - diagnose(Tok, diag::unexpected_class_constraint); - diagnose(Tok, diag::suggest_anyobject) - .fixItReplace(Tok.getLoc(), "AnyObject"); - consumeToken(); - Result.setIsParseError(); + auto tyResult = parseTypeSyntax(); + status |= tyResult.getStatus(); + if (auto ty = tyResult.getOrNull()) + paramBuilder.useInheritedType(std::move(*ty)); } else { - diagnose(Tok, diag::expected_generics_type_restriction, Name); - Result.setIsParseError(); - } - - if (Ty.hasCodeCompletion()) - return makeParserCodeCompletionStatus(); + if (Tok.is(tok::kw_class)) { + diagnose(Tok, diag::unexpected_class_constraint); + diagnose(Tok, diag::suggest_anyobject) + .fixItReplace(Tok.getLoc(), "AnyObject"); + Tok.setKind(tok::identifier); + auto ty = ParsedSyntaxRecorder::makeSimpleTypeIdentifier( + consumeTokenSyntax(), None, *SyntaxContext); + paramBuilder.useInheritedType(std::move(ty)); + } else { + diagnose(Tok, diag::expected_generics_type_restriction, ident); - if (Ty.isNonNull()) - Inherited.push_back(Ty.get()); + paramBuilder.useInheritedType( + ParsedSyntaxRecorder::makeUnknownType({}, *SyntaxContext)); + } + status.setIsParseError(); + } } - // We always create generic type parameters with an invalid depth. - // Semantic analysis fills in the depth when it processes the generic - // parameter list. - auto Param = new (Context) GenericTypeParamDecl(CurDeclContext, Name, NameLoc, - GenericTypeParamDecl::InvalidDepth, - GenericParams.size()); - if (!Inherited.empty()) - Param->setInherited(Context.AllocateCopy(Inherited)); - GenericParams.push_back(Param); - - // Attach attributes. - Param->getAttrs() = attributes; - - // Add this parameter to the scope. - addToScope(Param); - - // Parse the comma, if the list continues. - HasNextParam = consumeIf(tok::comma); - } while (HasNextParam); + // Parse ',' + hasNext = Tok.is(tok::comma); + if (hasNext) + paramBuilder.useTrailingComma(consumeTokenSyntax(tok::comma)); - return Result; -} - -ParserResult -Parser::parseGenericParameters(SourceLoc LAngleLoc) { - // Parse the generic parameter list. - SmallVector GenericParams; - auto Result = parseGenericParametersBeforeWhere(LAngleLoc, GenericParams); + builder.addGenericParameterListMember(paramBuilder.build()); + } while (hasNext); - // Return early if there was code completion token. - if (Result.hasCodeCompletion()) - return Result; - auto Invalid = Result.isError(); - - // Parse the optional where-clause. - SourceLoc WhereLoc; - SmallVector Requirements; - bool FirstTypeInComplete; - if (Tok.is(tok::kw_where) && - parseGenericWhereClause(WhereLoc, Requirements, - FirstTypeInComplete).isError()) { - Invalid = true; + // Parse optional where clause. + SourceLoc whereLoc; + if (Tok.is(tok::kw_where)) { + SmallVector requirementAST; + bool FirstTypeInComplete = false; + auto where = parseGenericWhereClauseSyntax(FirstTypeInComplete); + builder.useObsoletedWhereClause(where.get()); } - + // Parse the closing '>'. - SourceLoc RAngleLoc; if (startsWithGreater(Tok)) { - RAngleLoc = consumeStartingGreater(); + builder.useRightAngleBracket(consumeStartingGreaterSyntax()); } else { - if (!Invalid) { + if (!status.isError()) { diagnose(Tok, diag::expected_rangle_generics_param); diagnose(LAngleLoc, diag::opening_angle); - Invalid = true; } // Skip until we hit the '>'. - RAngleLoc = skipUntilGreaterInTypeList(); + if (ignoreUntilGreaterInTypeList()) + builder.useRightAngleBracket(consumeStartingGreaterSyntax()); + status.setIsParseError(); } - if (GenericParams.empty()) - return nullptr; + return makeParsedResult(builder.build(), status); +} - return makeParserResult(GenericParamList::create(Context, LAngleLoc, - GenericParams, WhereLoc, - Requirements, RAngleLoc)); +ParserResult Parser::parseGenericParameters() { + auto loc = leadingTriviaLoc(); + auto syntaxResult = parseGenericParameterClauseSyntax(); + if (syntaxResult.isNull()) + return syntaxResult.getStatus(); + SyntaxContext->addSyntax(syntaxResult.get()); + + auto clause = SyntaxContext->topNode(); + if (clause.getGenericParameterList().empty()) + return nullptr; + return makeParserResult(syntaxResult.getStatus(), + Generator.generate(clause, loc)); } ParserResult Parser::maybeParseGenericParams() { if (!startsWithLess(Tok)) return nullptr; + return parseGenericParameters(); +} - if (!isInSILMode()) - return parseGenericParameters(); - - // In SIL mode, we can have multiple generic parameter lists, with the - // first one being the outmost generic parameter list. - GenericParamList *gpl = nullptr, *outer_gpl = nullptr; - do { - gpl = parseGenericParameters().getPtrOrNull(); - if (!gpl) - return nullptr; +ParserResult Parser::parseSILGenericParams() { + assert(isInSILMode()); + auto loc = leadingTriviaLoc(); + Optional result; + auto status = parseSILGenericParamsSyntax(result); + if (!result.hasValue()) { + status.setIsParseError(); + return status; + } - if (outer_gpl) - gpl->setOuterParameters(outer_gpl); - outer_gpl = gpl; - } while (startsWithLess(Tok)); - return makeParserResult(gpl); + SyntaxContext->addSyntax(std::move(*result)); + auto list = SyntaxContext->topNode(); + auto ret = Generator.generate(list, loc); + if (!ret) + return nullptr; + return makeParserResult(status, ret); } void @@ -242,131 +242,145 @@ Parser::diagnoseWhereClauseInGenericParamList(const GenericParamList * } } -/// parseGenericWhereClause - Parse a 'where' clause, which places additional -/// constraints on generic parameters or types based on them. +/// Parse a 'where' clause, which places additional constraints on generic +/// parameters or types based on them. /// /// where-clause: -/// 'where' requirement (',' requirement) * +/// 'where' generic-requirement (',' generic-requirement) * /// -/// requirement: +/// generic-requirement: /// conformance-requirement /// same-type-requirement +/// layout-requirement /// /// conformance-requirement: -/// type-identifier ':' type-identifier -/// type-identifier ':' type-composition +/// type ':' type /// /// same-type-requirement: -/// type-identifier '==' type -ParserStatus Parser::parseGenericWhereClause( - SourceLoc &WhereLoc, - SmallVectorImpl &Requirements, - bool &FirstTypeInComplete, - bool AllowLayoutConstraints) { - SyntaxParsingContext ClauseContext(SyntaxContext, - SyntaxKind::GenericWhereClause); - ParserStatus Status; - // Parse the 'where'. - WhereLoc = consumeToken(tok::kw_where); - FirstTypeInComplete = false; - SyntaxParsingContext ReqListContext(SyntaxContext, - SyntaxKind::GenericRequirementList); - bool HasNextReq; +/// type '==' type +/// +/// layout-requirement: +/// type ':' layout-constraint +ParsedSyntaxResult +Parser::parseGenericWhereClauseSyntax(bool &FirstTypeInComplete, + bool allowLayoutConstraints) { + ParsedGenericWhereClauseSyntaxBuilder builder(*SyntaxContext); + ParserStatus status; + + // Parse 'where'. + builder.useWhereKeyword(consumeTokenSyntax(tok::kw_where)); + + bool hasNext = true; do { - SyntaxParsingContext ReqContext(SyntaxContext, SyntaxContextKind::Syntax); - // Parse the leading type. It doesn't necessarily have to be just a type - // identifier if we're dealing with a same-type constraint. - ParserResult FirstType = parseType(); - - if (FirstType.hasCodeCompletion()) { - Status.setHasCodeCompletion(); - FirstTypeInComplete = true; - } - - if (FirstType.isNull()) { - Status.setIsParseError(); + auto firstType = parseTypeSyntax(); + status |= firstType.getStatus(); + FirstTypeInComplete = firstType.hasCodeCompletion(); + if (firstType.isNull()) break; - } + + ParsedGenericRequirementSyntaxBuilder elementBuilder(*SyntaxContext); if (Tok.is(tok::colon)) { - // A conformance-requirement. - SourceLoc ColonLoc = consumeToken(); - ReqContext.setCreateSyntax(SyntaxKind::ConformanceRequirement); + auto colon = consumeTokenSyntax(tok::colon); + if (Tok.is(tok::identifier) && getLayoutConstraint(Context.getIdentifier(Tok.getText()), Context) ->isKnownLayout()) { - // Parse a layout constraint. - Identifier LayoutName; - auto LayoutLoc = consumeIdentifier(&LayoutName); - auto LayoutInfo = parseLayoutConstraint(LayoutName); - if (!LayoutInfo->isKnownLayout()) { - // There was a bug in the layout constraint. - Status.setIsParseError(); - } - auto Layout = LayoutInfo; - // Types in SIL mode may contain layout constraints. - if (!AllowLayoutConstraints && !isInSILMode()) { - diagnose(LayoutLoc, + // Layout constraint. + ParsedLayoutRequirementSyntaxBuilder layoutReqBuilder(*SyntaxContext); + layoutReqBuilder.useLeftTypeIdentifier(firstType.get()); + layoutReqBuilder.useColon(std::move(colon)); + SourceLoc layoutLoc = Tok.getLoc(); + auto layout = parseLayoutConstraintSyntax(); + status |= layout.getStatus(); + + if (!allowLayoutConstraints && !isInSILMode()) + diagnose(layoutLoc, diag::layout_constraints_only_inside_specialize_attr); - } else { - // Add the layout requirement. - Requirements.push_back(RequirementRepr::getLayoutConstraint( - FirstType.get(), ColonLoc, - LayoutConstraintLoc(Layout, LayoutLoc))); - } + assert(!layout.isNull()); + layoutReqBuilder.useLayoutConstraint(layout.get()); + elementBuilder.useBody(layoutReqBuilder.build()); } else { - // Parse the protocol or composition. - ParserResult Protocol = parseType(); - - if (Protocol.isNull()) { - Status.setIsParseError(); - if (Protocol.hasCodeCompletion()) - Status.setHasCodeCompletion(); - break; - } - - // Add the requirement. - Requirements.push_back(RequirementRepr::getTypeConstraint( - FirstType.get(), ColonLoc, Protocol.get())); + // Conformance requirement. + ParsedConformanceRequirementSyntaxBuilder conformanceReqBuilder( + *SyntaxContext); + conformanceReqBuilder.useLeftTypeIdentifier(firstType.get()); + conformanceReqBuilder.useColon(std::move(colon)); + auto secondType = parseTypeSyntax(); + status |= secondType.getStatus(); + if (!secondType.isNull()) + conformanceReqBuilder.useRightTypeIdentifier(secondType.get()); + else + conformanceReqBuilder.useRightTypeIdentifier( + ParsedSyntaxRecorder::makeUnknownType({}, *SyntaxContext)); + elementBuilder.useBody(conformanceReqBuilder.build()); } } else if ((Tok.isAnyOperator() && Tok.getText() == "==") || Tok.is(tok::equal)) { - ReqContext.setCreateSyntax(SyntaxKind::SameTypeRequirement); - // A same-type-requirement + // Same type requirement. + ParsedSameTypeRequirementSyntaxBuilder sametypeReqBuilder(*SyntaxContext); + sametypeReqBuilder.useLeftTypeIdentifier(firstType.get()); if (Tok.is(tok::equal)) { diagnose(Tok, diag::requires_single_equal) - .fixItReplace(SourceRange(Tok.getLoc()), "=="); - } - SourceLoc EqualLoc = consumeToken(); - - // Parse the second type. - ParserResult SecondType = parseType(); - if (SecondType.isNull()) { - Status.setIsParseError(); - if (SecondType.hasCodeCompletion()) - Status.setHasCodeCompletion(); - break; + .fixItReplace(SourceRange(Tok.getLoc()), "=="); + ignoreToken(); + } else { + sametypeReqBuilder.useEqualityToken(consumeTokenSyntax()); } - // Add the requirement - Requirements.push_back(RequirementRepr::getSameType(FirstType.get(), - EqualLoc, - SecondType.get())); + auto secondType = parseTypeSyntax(); + status |= secondType.getStatus(); + if (!secondType.isNull()) + sametypeReqBuilder.useRightTypeIdentifier(secondType.get()); + else + sametypeReqBuilder.useRightTypeIdentifier( + ParsedSyntaxRecorder::makeUnknownType({}, *SyntaxContext)); + elementBuilder.useBody(sametypeReqBuilder.build()); } else { diagnose(Tok, diag::expected_requirement_delim); - Status.setIsParseError(); - break; + status.setIsParseError(); + + // Fallback to conformance requirement with missing right type. + ParsedConformanceRequirementSyntaxBuilder conformanceReqBuilder( + *SyntaxContext); + conformanceReqBuilder.useLeftTypeIdentifier(firstType.get()); + conformanceReqBuilder.useRightTypeIdentifier( + ParsedSyntaxRecorder::makeUnknownType({}, *SyntaxContext)); + elementBuilder.useBody(conformanceReqBuilder.build()); } - HasNextReq = consumeIf(tok::comma); - // If there's a comma, keep parsing the list. - } while (HasNextReq); - if (Requirements.empty()) - WhereLoc = SourceLoc(); + // Parse ','. + hasNext = (status.isSuccess() && Tok.is(tok::comma)); + if (hasNext) + elementBuilder.useTrailingComma(consumeTokenSyntax()); + + builder.addRequirementListMember(elementBuilder.build()); + } while (hasNext && status.isSuccess()); - return Status; + return makeParsedResult(builder.build(), status); } +ParserStatus Parser::parseGenericWhereClause( + SourceLoc &whereLoc, SmallVectorImpl &requirements, + bool &FirstTypeInComplete, bool AllowLayoutConstraints) { + auto loc = leadingTriviaLoc(); + auto syntaxResult = parseGenericWhereClauseSyntax(FirstTypeInComplete, + AllowLayoutConstraints); + if (syntaxResult.isNull()) + return syntaxResult.getStatus(); + + SyntaxContext->addSyntax(syntaxResult.get()); + auto clause = SyntaxContext->topNode(); + + whereLoc = Generator.generate(clause.getWhereKeyword(), loc); + requirements.reserve(clause.getRequirementList().size()); + for (auto elem : clause.getRequirementList()) { + if (auto req = Generator.generate(elem, loc)) + requirements.push_back(*req); + } + + return syntaxResult.getStatus(); +} /// Parse a free-standing where clause attached to a declaration, adding it to /// a generic parameter list that may (or may not) already exist. diff --git a/lib/Parse/ParsePattern.cpp b/lib/Parse/ParsePattern.cpp index 3046decc2db7d..908cedcd5ab27 100644 --- a/lib/Parse/ParsePattern.cpp +++ b/lib/Parse/ParsePattern.cpp @@ -19,6 +19,7 @@ #include "swift/AST/ASTWalker.h" #include "swift/AST/Initializer.h" #include "swift/AST/Module.h" +#include "swift/AST/SourceFile.h" #include "swift/Basic/StringExtras.h" #include "swift/Parse/CodeCompletionCallbacks.h" #include "swift/Parse/ParsedSyntaxRecorder.h" diff --git a/lib/Parse/ParseRequests.cpp b/lib/Parse/ParseRequests.cpp index f0fc0ed2568c2..620c2e7999623 100644 --- a/lib/Parse/ParseRequests.cpp +++ b/lib/Parse/ParseRequests.cpp @@ -18,6 +18,7 @@ #include "swift/AST/Decl.h" #include "swift/AST/DeclContext.h" #include "swift/AST/Module.h" +#include "swift/AST/SourceFile.h" #include "swift/Parse/Parser.h" #include "swift/Subsystems.h" diff --git a/lib/Parse/ParseType.cpp b/lib/Parse/ParseType.cpp index 5b49573874f66..f06ab36b3ad27 100644 --- a/lib/Parse/ParseType.cpp +++ b/lib/Parse/ParseType.cpp @@ -61,81 +61,62 @@ TypeRepr *Parser::applyAttributeToType(TypeRepr *ty, return ty; } -LayoutConstraint Parser::parseLayoutConstraint(Identifier LayoutConstraintID) { - LayoutConstraint layoutConstraint = - getLayoutConstraint(LayoutConstraintID, Context); - assert(layoutConstraint->isKnownLayout() && - "Expected layout constraint definition"); - - if (!layoutConstraint->isTrivial()) - return layoutConstraint; - - SourceLoc LParenLoc; - if (!consumeIf(tok::l_paren, LParenLoc)) { - // It is a trivial without any size constraints. - return LayoutConstraint::getLayoutConstraint(LayoutConstraintKind::Trivial, - Context); - } +/// Parse layout constraint for 'where' clause in '@_specialize' attribute +/// and in SIL. +/// +/// layout-constraint: +/// identifier +/// identifier '(' integer-literal ')' +/// identifier '(' integer-literal ',' integer-literal ')' +ParsedSyntaxResult +Parser::parseLayoutConstraintSyntax() { + assert(Tok.is(tok::identifier)); + ParsedLayoutConstraintSyntaxBuilder builder(*SyntaxContext); + + builder.useName(consumeTokenSyntax(tok::identifier)); - int size = 0; - int alignment = 0; + if (!Tok.isFollowingLParen()) + return makeParsedResult(builder.build()); - auto ParseTrivialLayoutConstraintBody = [&] () -> bool { - // Parse the size and alignment. - if (Tok.is(tok::integer_literal)) { - if (Tok.getText().getAsInteger(10, size)) { - diagnose(Tok.getLoc(), diag::layout_size_should_be_positive); + auto lParenLoc = Tok.getLoc(); + builder.useLeftParen(consumeTokenSyntax(tok::l_paren)); + + auto parseTrivialConstraintBody = [&]() -> bool { + int value; + + if (!Tok.is(tok::integer_literal) || + Tok.getText().getAsInteger(10, value) || value < 0) { + diagnose(Tok, diag::layout_size_should_be_positive); + return true; + } + builder.useSize(consumeTokenSyntax(tok::integer_literal)); + + if (Tok.is(tok::comma)) { + builder.useComma(consumeTokenSyntax(tok::comma)); + + if (!Tok.is(tok::integer_literal) || + Tok.getText().getAsInteger(10, value) || value < 0) { + diagnose(Tok, diag::layout_alignment_should_be_positive); return true; } - consumeToken(); - if (consumeIf(tok::comma)) { - // parse alignment. - if (Tok.is(tok::integer_literal)) { - if (Tok.getText().getAsInteger(10, alignment)) { - diagnose(Tok.getLoc(), diag::layout_alignment_should_be_positive); - return true; - } - consumeToken(); - } else { - diagnose(Tok.getLoc(), diag::layout_alignment_should_be_positive); - return true; - } - } - } else { - diagnose(Tok.getLoc(), diag::layout_size_should_be_positive); - return true; + builder.useAlignment(consumeTokenSyntax(tok::integer_literal)); } return false; }; - if (ParseTrivialLayoutConstraintBody()) { - // There was an error during parsing. - skipUntil(tok::r_paren); - consumeIf(tok::r_paren); - return LayoutConstraint::getUnknownLayout(); - } - - if (!consumeIf(tok::r_paren)) { - // Expected a closing r_paren. - diagnose(Tok.getLoc(), diag::expected_rparen_layout_constraint); - consumeToken(); - return LayoutConstraint::getUnknownLayout(); - } - - if (size < 0) { - diagnose(Tok.getLoc(), diag::layout_size_should_be_positive); - return LayoutConstraint::getUnknownLayout(); - } - - if (alignment < 0) { - diagnose(Tok.getLoc(), diag::layout_alignment_should_be_positive); - return LayoutConstraint::getUnknownLayout(); + if (parseTrivialConstraintBody()) { + ignoreUntil(tok::r_paren); + if (Tok.is(tok::r_paren)) + builder.useRightParen(consumeTokenSyntax(tok::r_paren)); + } else { + SourceLoc rParenLoc; + auto rParen = parseMatchingTokenSyntax(tok::r_paren, rParenLoc, + diag::expected_rparen_layout_constraint, + lParenLoc); + if (rParen) + builder.useRightParen(std::move(*rParen)); } - - // Otherwise it is a trivial layout constraint with - // provided size and alignment. - return LayoutConstraint::getLayoutConstraint(layoutConstraint->getKind(), size, - alignment, Context); + return makeParsedResult(builder.build()); } /// parseTypeSimple @@ -369,7 +350,7 @@ Parser::TypeASTResult Parser::parseType(Diag<> MessageID, // the function body; otherwise, they are visible when parsing the type. if (!IsSILFuncDecl) GenericsScope.emplace(this, ScopeKind::Generics); - generics = maybeParseGenericParams().getPtrOrNull(); + generics = parseSILGenericParams().getPtrOrNull(); } // In SIL mode, parse box types { ... }. @@ -656,94 +637,87 @@ Parser::parseTypeIdentifier(bool isParsingQualifiedDeclName) { if (isParsingQualifiedDeclName && !canParseTypeQualifierForDeclName()) return makeParsedError(); + // SWIFT_ENABLE_TENSORFLOW: Condition body intentionally not indented, to + // reduce merge conflicts. if (!isParsingQualifiedDeclName || Tok.isNotAnyOperator()) { - if (Tok.isNot(tok::identifier) && Tok.isNot(tok::kw_Self)) { - // is this the 'Any' type - if (Tok.is(tok::kw_Any)) - return parseAnyType(); - - if (Tok.is(tok::code_complete)) { - if (CodeCompletion) - CodeCompletion->completeTypeSimpleBeginning(); - - auto CCTok = consumeTokenSyntax(tok::code_complete); - auto ty = ParsedSyntaxRecorder::makeUnknownType( - {&CCTok, 1}, *SyntaxContext); - return makeParsedCodeCompletion(std::move(ty)); - } + if (Tok.isNot(tok::identifier) && Tok.isNot(tok::kw_Self)) { + // is this the 'Any' type + if (Tok.is(tok::kw_Any)) + return parseAnyType(); - diagnose(Tok, diag::expected_identifier_for_type); + if (Tok.is(tok::code_complete)) { + if (CodeCompletion) + CodeCompletion->completeTypeSimpleBeginning(); - // If there is a keyword at the start of a new line, we won't want to - // skip it as a recovery but rather keep it. - if (Tok.isKeyword() && !Tok.isAtStartOfLine()) { - auto kwTok = consumeTokenSyntax(); - ParsedTypeSyntax ty = ParsedSyntaxRecorder::makeUnknownType( - {&kwTok, 1}, *SyntaxContext); - return makeParsedError(std::move(ty)); - } + auto CCTok = consumeTokenSyntax(tok::code_complete); + auto ty = ParsedSyntaxRecorder::makeCodeCompletionType( + None, None, std::move(CCTok), *SyntaxContext); + return makeParsedCodeCompletion(std::move(ty)); + } - return makeParsedError(); + diagnose(Tok, diag::expected_identifier_for_type); + + // If there is a keyword at the start of a new line, we won't want to + // skip it as a recovery but rather keep it. + if (Tok.isKeyword() && !Tok.isAtStartOfLine()) { + auto kwTok = consumeTokenSyntax(); + ParsedTypeSyntax ty = + ParsedSyntaxRecorder::makeUnknownType({&kwTok, 1}, *SyntaxContext); + return makeParsedError(std::move(ty)); } - } + return makeParsedError(); + } + } SmallVector Junk; - auto BaseLoc = leadingTriviaLoc(); - ParserStatus Status; - Optional Base; - Optional Period; - while (true) { - Optional Identifier; - if (Tok.is(tok::kw_Self)) { - Identifier = consumeIdentifierSyntax(); - } else if (isParsingQualifiedDeclName && Tok.isAnyOperator()) { - // If an operator is encountered, break and do not backtrack later. - break; - } else { - // FIXME: specialize diagnostic for 'Type': type cannot start with - // 'metatype' - // FIXME: offer a fixit: 'self' -> 'Self' - Identifier = - parseIdentifierSyntax(diag::expected_identifier_in_dotted_type); - } + auto parseComponent = + [&](Optional &Identifier, + Optional &GenericArgs) { + if (Tok.is(tok::kw_Self)) { + Identifier = consumeIdentifierSyntax(); + } else { + // FIXME: specialize diagnostic for 'Type': type cannot start with + // 'metatype' + // FIXME: offer a fixit: 'self' -> 'Self' + Identifier = + parseIdentifierSyntax(diag::expected_identifier_in_dotted_type); + } - if (Identifier) { - Optional GenericArgs; + if (!Identifier) + return makeParserError(); + + if (!startsWithLess(Tok)) + return makeParserSuccess(); - if (startsWithLess(Tok)) { SmallVector GenericArgsAST; SourceLoc LAngleLoc, RAngleLoc; auto GenericArgsResult = parseGenericArgumentClauseSyntax(); - if (GenericArgsResult.isError()) { - if (Base) - Junk.push_back(std::move(*Base)); - if (Period) - Junk.push_back(std::move(*Period)); - Junk.push_back(std::move(*Identifier)); - if (!GenericArgsResult.isNull()) - Junk.push_back(GenericArgsResult.get()); - auto ty = ParsedSyntaxRecorder::makeUnknownType(Junk, *SyntaxContext); - return makeParsedResult(std::move(ty), GenericArgsResult.getStatus()); - } - GenericArgs = GenericArgsResult.get(); - } + if (!GenericArgsResult.isNull()) + GenericArgs = GenericArgsResult.get(); + return GenericArgsResult.getStatus(); + }; - if (!Base) - Base = ParsedSyntaxRecorder::makeSimpleTypeIdentifier( - std::move(*Identifier), std::move(GenericArgs), *SyntaxContext); - else - Base = ParsedSyntaxRecorder::makeMemberTypeIdentifier( - std::move(*Base), std::move(*Period), std::move(*Identifier), - std::move(GenericArgs), *SyntaxContext); - } else { - Status.setIsParseError(); - if (Base) - Junk.push_back(std::move(*Base)); - if (Period) - Junk.push_back(std::move(*Period)); - } + ParsedSyntaxResult result; + + // Parse the base identifier. + result = [&]() { + Optional identifier; + Optional genericArgs; + auto status = parseComponent(identifier, genericArgs); + assert(identifier); + return makeParsedResult( + ParsedSyntaxRecorder::makeSimpleTypeIdentifier( + std::move(*identifier), std::move(genericArgs), *SyntaxContext), + status); + }(); + + // Parse member identifiers. + while (result.isSuccess() && Tok.isAny(tok::period, tok::period_prefix)) { + if (peekToken().isContextualKeyword("Type") || + peekToken().isContextualKeyword("Protocol")) + break; if (isParsingQualifiedDeclName) { // If we're parsing a qualified decl name, break out before parsing the @@ -760,57 +734,66 @@ Parser::parseTypeIdentifier(bool isParsingQualifiedDeclName) { break; } - // Treat 'Foo.' as an attempt to write a dotted type - // unless is 'Type'. - if ((Tok.is(tok::period) || Tok.is(tok::period_prefix))) { - if (peekToken().is(tok::code_complete)) { - Status.setHasCodeCompletion(); - break; - } - if (!peekToken().isContextualKeyword("Type") && - !peekToken().isContextualKeyword("Protocol")) { - Period = consumeTokenSyntax(); - continue; - } - } else if (Tok.is(tok::code_complete)) { - if (!Tok.isAtStartOfLine()) - Status.setHasCodeCompletion(); + // Parse '.'. + auto period = consumeTokenSyntax(); + + if (isParsingQualifiedDeclName && Tok.isAnyOperator()) { + // If an operator is encountered, break and do not backtrack later. break; } - break; - } - - if (Status.hasCodeCompletion()) { - IdentTypeRepr *ITR = nullptr; - if (Base) { - SyntaxContext->addSyntax(std::move(*Base)); - auto T = SyntaxContext->topNode(); - Junk.push_back(std::move(*SyntaxContext->popIf())); - ITR = dyn_cast(Generator.generate(T, BaseLoc)); + // Parse component; + Optional identifier; + Optional genericArgs; + auto status = parseComponent(identifier, genericArgs); + if (identifier) { + ParsedMemberTypeIdentifierSyntaxBuilder builder(*SyntaxContext); + builder.useBaseType(result.get()); + builder.usePeriod(std::move(period)); + builder.useName(std::move(*identifier)); + if (genericArgs) + builder.useGenericArgumentClause(std::move(*genericArgs)); + result = makeParsedResult(builder.build(), status); + continue; } - if (Tok.isNot(tok::code_complete)) { - // We have a dot. - auto Dot = consumeTokenSyntax(); - Junk.push_back(std::move(Dot)); - if (CodeCompletion) - CodeCompletion->completeTypeIdentifierWithDot(ITR); - } else { + assert(!genericArgs); + + if (Tok.is(tok::code_complete)) { if (CodeCompletion) - CodeCompletion->completeTypeIdentifierWithoutDot(ITR); + CodeCompletion->completeTypeIdentifierWithDot(); + + auto ty = ParsedSyntaxRecorder::makeCodeCompletionType( + result.get(), std::move(period), consumeTokenSyntax(), + *SyntaxContext); + return makeParsedCodeCompletion(std::move(ty)); } - // Eat the code completion token because we handled it. - Junk.push_back(consumeTokenSyntax(tok::code_complete)); - auto ty = ParsedSyntaxRecorder::makeUnknownType(Junk, *SyntaxContext); + + ParsedSyntax parts[] = {result.get(), std::move(period)}; + return makeParsedResult( + ParsedSyntaxRecorder::makeUnknownType({parts, 2}, *SyntaxContext), + status); + } + + if (result.isSuccess() && Tok.is(tok::code_complete) && + !Tok.isAtStartOfLine()) { + if (CodeCompletion) + CodeCompletion->completeTypeIdentifierWithoutDot(); + + auto ty = ParsedSyntaxRecorder::makeCodeCompletionType( + result.get(), None, consumeTokenSyntax(), *SyntaxContext); return makeParsedCodeCompletion(std::move(ty)); } - if (Status.isError()) { - auto ty = ParsedSyntaxRecorder::makeUnknownType(Junk, *SyntaxContext); - return makeParsedError(std::move(ty)); + + // Don't propagate malformed type as valid type. + if (!result.isSuccess()) { + auto ty = result.get(); + return makeParsedResult( + ParsedSyntaxRecorder::makeUnknownType({&ty, 1}, *SyntaxContext), + result.getStatus()); } - return makeParsedResult(std::move(*Base)); + return result; } Parser::TypeASTResult @@ -970,7 +953,7 @@ Parser::TypeResult Parser::parseOldStyleProtocolComposition() { bool IsAny = Tok.getKind() == tok::kw_Any; auto TypeResult = parseTypeIdentifier(); Status |= TypeResult.getStatus(); - if (TypeResult.isSuccess()) { + if (!TypeResult.isNull()) { auto Type = TypeResult.get(); Junk.push_back(Type.copyDeferred()); if (!IsAny) @@ -1230,6 +1213,8 @@ Parser::TypeResult Parser::parseTypeTupleBody() { }); if (!Status.isSuccess()) { + if (RParen) + Junk.push_back(std::move(*RParen)); auto ty = ParsedSyntaxRecorder::makeUnknownType(Junk, *SyntaxContext); return makeParsedResult(std::move(ty), Status); } @@ -1317,9 +1302,9 @@ Parser::TypeResult Parser::parseTypeArray(ParsedTypeSyntax Base, // Ignore integer literal between '[' and ']' ignoreIf(tok::integer_literal); - auto RSquareLoc = Tok.getLoc(); + SourceLoc RSquareLoc; auto RSquare = parseMatchingTokenSyntax( - tok::r_square, diag::expected_rbracket_array_type, LSquareLoc); + tok::r_square, RSquareLoc, diag::expected_rbracket_array_type, LSquareLoc); if (RSquare) { // If we parsed something valid, diagnose it with a fixit to rewrite it to @@ -1365,7 +1350,9 @@ Parser::TypeResult Parser::parseTypeCollection() { auto Diag = Colon ? diag::expected_rbracket_dictionary_type : diag::expected_rbracket_array_type; - auto RSquare = parseMatchingTokenSyntax(tok::r_square, Diag, LSquareLoc); + SourceLoc RSquareLoc; + auto RSquare = parseMatchingTokenSyntax(tok::r_square, RSquareLoc, Diag, + LSquareLoc); if (!RSquare) Status.setIsParseError(); diff --git a/lib/Parse/ParsedSyntaxBuilders.cpp.gyb b/lib/Parse/ParsedSyntaxBuilders.cpp.gyb index 9ab3964f2b2cb..7277a71462b2b 100644 --- a/lib/Parse/ParsedSyntaxBuilders.cpp.gyb +++ b/lib/Parse/ParsedSyntaxBuilders.cpp.gyb @@ -26,7 +26,7 @@ using namespace swift; using namespace swift::syntax; -% for node in SYNTAX_NODES: +% for node in SYNTAX_NODES + PARSEONLY_NODES: % if node.is_buildable(): % for child in node.children: % child_elt = None diff --git a/lib/Parse/ParsedSyntaxNodes.cpp.gyb b/lib/Parse/ParsedSyntaxNodes.cpp.gyb index e3bb56c91812e..f45d87d62ba39 100644 --- a/lib/Parse/ParsedSyntaxNodes.cpp.gyb +++ b/lib/Parse/ParsedSyntaxNodes.cpp.gyb @@ -23,7 +23,7 @@ using namespace swift; using namespace swift::syntax; -% for node in SYNTAX_NODES: +% for node in SYNTAX_NODES + PARSEONLY_NODES: % for child in node.children: % if child.is_optional: Optional diff --git a/lib/Parse/ParsedSyntaxRecorder.cpp.gyb b/lib/Parse/ParsedSyntaxRecorder.cpp.gyb index b305e25e7cc8f..5c5ac75d7a74e 100644 --- a/lib/Parse/ParsedSyntaxRecorder.cpp.gyb +++ b/lib/Parse/ParsedSyntaxRecorder.cpp.gyb @@ -29,7 +29,7 @@ bool ParsedSyntaxRecorder::formExactLayoutFor(syntax::SyntaxKind Kind, MutableArrayRef Elements, function_ref)> receiver) { switch (Kind) { -% for node in SYNTAX_NODES: +% for node in SYNTAX_NODES + PARSEONLY_NODES: case SyntaxKind::${node.syntax_kind}: { % if node.children: % child_count = len(node.children) @@ -77,7 +77,7 @@ bool ParsedSyntaxRecorder::formExactLayoutFor(syntax::SyntaxKind Kind, } } -% for node in SYNTAX_NODES: +% for node in SYNTAX_NODES + PARSEONLY_NODES: % if node.children: % child_params = [] % child_move_args = [] diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index ddda4f25cc4d9..707da850985a1 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -20,6 +20,7 @@ #include "swift/AST/DiagnosticsParse.h" #include "swift/AST/Module.h" #include "swift/AST/PrettyStackTrace.h" +#include "swift/AST/SourceFile.h" #include "swift/Basic/Defer.h" #include "swift/Basic/SourceManager.h" #include "swift/Basic/Timer.h" @@ -526,7 +527,7 @@ Parser::Parser(std::unique_ptr Lex, SourceFile &SF, L->getBufferID(), SF.SyntaxParsingCache, SF.getASTContext().getSyntaxArena())))), - Generator(SF.getASTContext(), &State) { + Generator(SF.getASTContext(), *this) { State = PersistentState; if (!State) { OwnedState.reset(new PersistentParserState()); @@ -1254,8 +1255,10 @@ bool Parser::parseUnsignedInteger(unsigned &Result, SourceLoc &Loc, return false; } -Optional Parser::parseTokenSyntax(tok K, const Diagnostic &D) { +Optional Parser::parseTokenSyntax(tok K, SourceLoc &TokLoc, + const Diagnostic &D) { if (Tok.is(K)) { + TokLoc = Tok.getLoc(); return consumeTokenSyntax(); } @@ -1265,7 +1268,7 @@ Optional Parser::parseTokenSyntax(tok K, const Diagnostic &D) } Optional -Parser::parseMatchingTokenSyntax(tok K, Diag<> ErrorDiag, SourceLoc OtherLoc) { +Parser::parseMatchingTokenSyntax(tok K, SourceLoc &TokLoc, Diag<> ErrorDiag, SourceLoc OtherLoc) { Diag<> OtherNote; switch (K) { case tok::r_paren: OtherNote = diag::opening_paren; break; @@ -1274,9 +1277,11 @@ Parser::parseMatchingTokenSyntax(tok K, Diag<> ErrorDiag, SourceLoc OtherLoc) { default: llvm_unreachable("unknown matching token!"); } - auto Token = parseTokenSyntax(K, ErrorDiag); - if (!Token) + auto Token = parseTokenSyntax(K, TokLoc, ErrorDiag); + if (!Token) { + TokLoc = getLocForMissingMatchingToken(); diagnose(OtherLoc, OtherNote); + } return Token; } @@ -1403,9 +1408,14 @@ Parser::parseListSyntax(tok RightK, SourceLoc LeftLoc, if (Status.isError()) { // If we've already got errors, don't emit missing RightK diagnostics. - RightLoc = Tok.is(RightK) ? consumeToken() : PreviousLoc; + if (Tok.is(RightK)) { + RightLoc = Tok.getLoc(); + Right = consumeTokenSyntax(RightK); + } else { + RightLoc = getLocForMissingMatchingToken(); + } } else { - Right = parseMatchingTokenSyntax(RightK, ErrorDiag, LeftLoc); + Right = parseMatchingTokenSyntax(RightK, RightLoc, ErrorDiag, LeftLoc); if (!Right) Status.setIsParseError(); } diff --git a/lib/Parse/SyntaxParsingContext.cpp b/lib/Parse/SyntaxParsingContext.cpp index 6cd6b507bf863..9899ee57737e8 100644 --- a/lib/Parse/SyntaxParsingContext.cpp +++ b/lib/Parse/SyntaxParsingContext.cpp @@ -16,6 +16,7 @@ #include "swift/AST/DiagnosticEngine.h" #include "swift/AST/DiagnosticsParse.h" #include "swift/AST/Module.h" +#include "swift/AST/SourceFile.h" #include "swift/Basic/Defer.h" #include "swift/Parse/ParsedSyntax.h" #include "swift/Parse/ParsedSyntaxRecorder.h" diff --git a/lib/ParseSIL/ParseSIL.cpp b/lib/ParseSIL/ParseSIL.cpp index 26ed30fff357a..12432b5f2c710 100644 --- a/lib/ParseSIL/ParseSIL.cpp +++ b/lib/ParseSIL/ParseSIL.cpp @@ -18,6 +18,7 @@ #include "swift/AST/GenericEnvironment.h" #include "swift/AST/NameLookup.h" #include "swift/AST/ProtocolConformance.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/TypeCheckRequests.h" #include "swift/Basic/Defer.h" #include "swift/Basic/Timer.h" @@ -3403,7 +3404,7 @@ bool SILParser::parseSILInstruction(SILBuilder &B) { SmallVector operandTypes; { Scope genericsScope(&P, ScopeKind::Generics); - generics = P.maybeParseGenericParams().getPtrOrNull(); + generics = P.parseSILGenericParams().getPtrOrNull(); patternEnv = handleSILGenericParams(P.Context, generics, &P.SF); if (P.parseToken(tok::l_paren, diag::expected_tok_in_sil_instr, "(")) @@ -6047,7 +6048,7 @@ bool SILParserTUState::parseSILProperty(Parser &P) { GenericEnvironment *patternEnv; Scope toplevelScope(&P, ScopeKind::TopLevel); Scope genericsScope(&P, ScopeKind::Generics); - generics = P.maybeParseGenericParams().getPtrOrNull(); + generics = P.parseSILGenericParams().getPtrOrNull(); patternEnv = handleSILGenericParams(P.Context, generics, &P.SF); if (patternEnv) { @@ -6361,7 +6362,7 @@ Optional SILParser::parseProtocolConformance( // Make sure we don't leave it uninitialized in the caller genericEnv = nullptr; - auto *genericParams = P.maybeParseGenericParams().getPtrOrNull(); + auto *genericParams = P.parseSILGenericParams().getPtrOrNull(); if (genericParams) { genericEnv = handleSILGenericParams(P.Context, genericParams, &P.SF); } diff --git a/lib/PrintAsObjC/DeclAndTypePrinter.cpp b/lib/PrintAsObjC/DeclAndTypePrinter.cpp index 27dfa5730ba74..3df71be5f8209 100644 --- a/lib/PrintAsObjC/DeclAndTypePrinter.cpp +++ b/lib/PrintAsObjC/DeclAndTypePrinter.cpp @@ -1388,23 +1388,10 @@ class DeclAndTypePrinter::Implementation // upper-bounded keys. else if (swiftNominal == ctx.getDictionaryDecl() && isNSObjectOrAnyHashable(ctx, typeArgs[0])) { - if (ModuleDecl *M = ctx.getLoadedModule(ctx.Id_Foundation)) { - if (!owningPrinter.NSCopyingType) { - SmallVector decls; - M->lookupQualified(M, ctx.getIdentifier("NSCopying"), - NL_OnlyTypes, decls); - if (decls.size() == 1 && isa(decls[0])) { - owningPrinter.NSCopyingType = cast(decls[0]) - ->getDeclaredInterfaceType(); - } else { - owningPrinter.NSCopyingType = Type(); - } - } - if (*owningPrinter.NSCopyingType) { - rewrittenArgsBuf[0] = *owningPrinter.NSCopyingType; - rewrittenArgsBuf[1] = typeArgs[1]; - typeArgs = rewrittenArgsBuf; - } + if (auto proto = ctx.getNSCopyingDecl()) { + rewrittenArgsBuf[0] = proto->getDeclaredInterfaceType(); + rewrittenArgsBuf[1] = typeArgs[1]; + typeArgs = rewrittenArgsBuf; } } diff --git a/lib/PrintAsObjC/DeclAndTypePrinter.h b/lib/PrintAsObjC/DeclAndTypePrinter.h index 8e2b6b3b46498..fc7a51f137a19 100644 --- a/lib/PrintAsObjC/DeclAndTypePrinter.h +++ b/lib/PrintAsObjC/DeclAndTypePrinter.h @@ -56,12 +56,6 @@ class DeclAndTypePrinter { /// Cached for convenience. Identifier ID_CFTypeRef; - /// The protocol type 'NSCopying', or a null type if Foundation has not been - /// imported. - /// - /// Cached for convenience. - Optional NSCopyingType; - Implementation getImpl(); public: diff --git a/lib/SIL/InstructionUtils.cpp b/lib/SIL/InstructionUtils.cpp index 093a5d0bde518..970b419e81703 100644 --- a/lib/SIL/InstructionUtils.cpp +++ b/lib/SIL/InstructionUtils.cpp @@ -14,10 +14,12 @@ #include "swift/SIL/InstructionUtils.h" #include "swift/AST/SubstitutionMap.h" #include "swift/Basic/NullablePtr.h" +#include "swift/Basic/STLExtras.h" #include "swift/SIL/DebugUtils.h" #include "swift/SIL/Projection.h" #include "swift/SIL/SILArgument.h" #include "swift/SIL/SILBasicBlock.h" +#include "swift/SIL/SILBuilder.h" #include "swift/SIL/SILVisitor.h" using namespace swift; @@ -535,3 +537,148 @@ void swift::findClosuresForFunctionValue( // Ignore other unrecognized values that feed this applied argument. } } + +bool PolymorphicBuiltinSpecializedOverloadInfo::init( + SILFunction *fn, BuiltinValueKind builtinKind, + ArrayRef oldOperandTypes, SILType oldResultType) { + assert(!isInitialized && "Expected uninitialized info"); + SWIFT_DEFER { isInitialized = true; }; + if (!isPolymorphicBuiltin(builtinKind)) + return false; + + // Ok, at this point we know that we have a true polymorphic builtin. See if + // we have an overload for its current operand type. + StringRef name = getBuiltinName(builtinKind); + StringRef prefix = "generic_"; + assert(name.startswith(prefix) && + "Invalid polymorphic builtin name! Prefix should be Generic$OP?!"); + SmallString<32> staticOverloadName; + staticOverloadName.append(name.drop_front(prefix.size())); + + // If our first argument is an address, we know we have an indirect @out + // parameter by convention since all of these polymorphic builtins today never + // take indirect parameters without an indirect out result parameter. We stash + // this information and validate that if we have an out param, that our result + // is equal to the empty tuple type. + if (oldOperandTypes[0].isAddress()) { + if (oldResultType != fn->getModule().Types.getEmptyTupleType()) + return false; + + hasOutParam = true; + SILType firstType = oldOperandTypes.front(); + + // We only handle polymorphic builtins with trivial types today. + if (!firstType.is() || !firstType.isTrivial(*fn)) { + return false; + } + + resultType = firstType.getObjectType(); + oldOperandTypes = oldOperandTypes.drop_front(); + } else { + resultType = oldResultType; + } + + // Then go through all of our values and bail if any after substitution are + // not concrete builtin types. Otherwise, stash each of them in the argTypes + // array as objects. We will convert them as appropriate. + for (SILType ty : oldOperandTypes) { + // If after specialization, we do not have a trivial builtin type, bail. + if (!ty.is() || !ty.isTrivial(*fn)) { + return false; + } + + // Otherwise, we have an object builtin type ready to go. + argTypes.push_back(ty.getObjectType()); + } + + // Ok, we have all builtin types. Infer the underlying polymorphic builtin + // name form our first argument. + CanBuiltinType builtinType = argTypes.front().getAs(); + SmallString<32> builtinTypeNameStorage; + StringRef typeName = builtinType->getTypeName(builtinTypeNameStorage, false); + staticOverloadName.append("_"); + staticOverloadName.append(typeName); + + auto &ctx = fn->getASTContext(); + staticOverloadIdentifier = ctx.getIdentifier(staticOverloadName); + + // Ok, we have our overload identifier. Grab the builtin info from the + // cache. If we did not actually found a valid builtin value kind for our + // overload, then we do not have a static overload for the passed in types, so + // return false. + builtinInfo = &fn->getModule().getBuiltinInfo(staticOverloadIdentifier); + return true; +} + +bool PolymorphicBuiltinSpecializedOverloadInfo::init(BuiltinInst *bi) { + assert(!isInitialized && "Can not init twice?!"); + SWIFT_DEFER { isInitialized = true; }; + + // First quickly make sure we have a /real/ BuiltinValueKind, not an intrinsic + // or None. + auto kind = bi->getBuiltinKind(); + if (!kind) + return false; + + SmallVector oldOperandTypes; + copy(bi->getOperandTypes(), std::back_inserter(oldOperandTypes)); + assert(bi->getNumResults() == 1 && + "We expect a tuple here instead of real args"); + SILType oldResultType = bi->getResult(0)->getType(); + return init(bi->getFunction(), *kind, oldOperandTypes, oldResultType); +} + +SILValue +swift::getStaticOverloadForSpecializedPolymorphicBuiltin(BuiltinInst *bi) { + + PolymorphicBuiltinSpecializedOverloadInfo info; + if (!info.init(bi)) + return SILValue(); + + SmallVector rawArgsData; + copy(bi->getOperandValues(), std::back_inserter(rawArgsData)); + + SILValue result = bi->getResult(0); + MutableArrayRef rawArgs = rawArgsData; + + if (info.hasOutParam) { + result = rawArgs.front(); + rawArgs = rawArgs.drop_front(); + } + + assert(bi->getNumResults() == 1 && + "We assume that builtins have a single result today. If/when this " + "changes, this code needs to be updated"); + + SILBuilderWithScope builder(bi); + + // Ok, now we know that we can convert this to our specialized + // builtin. Prepare the arguments for the specialized value, loading the + // values if needed and storing the result into an out parameter if needed. + // + // NOTE: We only support polymorphic builtins with trivial types today, so we + // use load/store trivial as a result. + SmallVector newArgs; + for (SILValue arg : rawArgs) { + if (arg->getType().isObject()) { + newArgs.push_back(arg); + continue; + } + + SILValue load = builder.emitLoadValueOperation( + bi->getLoc(), arg, LoadOwnershipQualifier::Trivial); + newArgs.push_back(load); + } + + BuiltinInst *newBI = + builder.createBuiltin(bi->getLoc(), info.staticOverloadIdentifier, + info.resultType, {}, newArgs); + + // If we have an out parameter initialize it now. + if (info.hasOutParam) { + builder.emitStoreValueOperation(newBI->getLoc(), newBI->getResult(0), + result, StoreOwnershipQualifier::Trivial); + } + + return newBI; +} diff --git a/lib/SIL/LinearLifetimeChecker.cpp b/lib/SIL/LinearLifetimeChecker.cpp index 5b8eeeaff8073..1697965957cc3 100644 --- a/lib/SIL/LinearLifetimeChecker.cpp +++ b/lib/SIL/LinearLifetimeChecker.cpp @@ -507,10 +507,9 @@ void State::checkDataflowEndState(DeadEndBlocks &deBlocks) { // Top Level Entrypoints //===----------------------------------------------------------------------===// -LinearLifetimeError swift::valueHasLinearLifetime( +LinearLifetimeError LinearLifetimeChecker::checkValue( SILValue value, ArrayRef consumingUses, ArrayRef nonConsumingUses, - SmallPtrSetImpl &visitedBlocks, DeadEndBlocks &deBlocks, ErrorBehaviorKind errorBehavior, SmallVectorImpl *leakingBlocks) { assert(!consumingUses.empty() && "Must have at least one consuming user?!"); @@ -547,7 +546,7 @@ LinearLifetimeError swift::valueHasLinearLifetime( // same block, we would have flagged. if (llvm::any_of(nonConsumingUses, [&](BranchPropagatedUser user) { return user.getParent() != value->getParentBlock() && - !deBlocks.isDeadEnd(user.getParent()); + !deadEndBlocks.isDeadEnd(user.getParent()); })) { state.error.handleUseAfterFree([&] { llvm::errs() << "Function: '" << value->getFunction()->getName() @@ -592,10 +591,10 @@ LinearLifetimeError swift::valueHasLinearLifetime( // Now that our algorithm is completely prepared, run the // dataflow... If we find a failure, return false. - state.performDataflow(deBlocks); + state.performDataflow(deadEndBlocks); // ...and then check that the end state shows that we have a valid linear // typed value. - state.checkDataflowEndState(deBlocks); + state.checkDataflowEndState(deadEndBlocks); return state.error; } diff --git a/lib/SIL/OperandOwnership.cpp b/lib/SIL/OperandOwnership.cpp index 32979d244a6e3..6486b035028b7 100644 --- a/lib/SIL/OperandOwnership.cpp +++ b/lib/SIL/OperandOwnership.cpp @@ -920,10 +920,13 @@ ANY_OWNERSHIP_BUILTIN(ErrorInMain) ANY_OWNERSHIP_BUILTIN(UnexpectedError) ANY_OWNERSHIP_BUILTIN(WillThrow) ANY_OWNERSHIP_BUILTIN(AShr) +ANY_OWNERSHIP_BUILTIN(GenericAShr) ANY_OWNERSHIP_BUILTIN(Add) +ANY_OWNERSHIP_BUILTIN(GenericAdd) ANY_OWNERSHIP_BUILTIN(Alignof) ANY_OWNERSHIP_BUILTIN(AllocRaw) ANY_OWNERSHIP_BUILTIN(And) +ANY_OWNERSHIP_BUILTIN(GenericAnd) ANY_OWNERSHIP_BUILTIN(AssertConf) ANY_OWNERSHIP_BUILTIN(AssignCopyArrayNoAlias) ANY_OWNERSHIP_BUILTIN(AssignCopyArrayFrontToBack) @@ -943,9 +946,12 @@ ANY_OWNERSHIP_BUILTIN(CopyArray) ANY_OWNERSHIP_BUILTIN(DeallocRaw) ANY_OWNERSHIP_BUILTIN(DestroyArray) ANY_OWNERSHIP_BUILTIN(ExactSDiv) +ANY_OWNERSHIP_BUILTIN(GenericExactSDiv) ANY_OWNERSHIP_BUILTIN(ExactUDiv) +ANY_OWNERSHIP_BUILTIN(GenericExactUDiv) ANY_OWNERSHIP_BUILTIN(ExtractElement) ANY_OWNERSHIP_BUILTIN(FAdd) +ANY_OWNERSHIP_BUILTIN(GenericFAdd) ANY_OWNERSHIP_BUILTIN(FCMP_OEQ) ANY_OWNERSHIP_BUILTIN(FCMP_OGE) ANY_OWNERSHIP_BUILTIN(FCMP_OGT) @@ -961,14 +967,18 @@ ANY_OWNERSHIP_BUILTIN(FCMP_ULT) ANY_OWNERSHIP_BUILTIN(FCMP_UNE) ANY_OWNERSHIP_BUILTIN(FCMP_UNO) ANY_OWNERSHIP_BUILTIN(FDiv) +ANY_OWNERSHIP_BUILTIN(GenericFDiv) ANY_OWNERSHIP_BUILTIN(FMul) +ANY_OWNERSHIP_BUILTIN(GenericFMul) ANY_OWNERSHIP_BUILTIN(FNeg) ANY_OWNERSHIP_BUILTIN(FPExt) ANY_OWNERSHIP_BUILTIN(FPToSI) ANY_OWNERSHIP_BUILTIN(FPToUI) ANY_OWNERSHIP_BUILTIN(FPTrunc) ANY_OWNERSHIP_BUILTIN(FRem) +ANY_OWNERSHIP_BUILTIN(GenericFRem) ANY_OWNERSHIP_BUILTIN(FSub) +ANY_OWNERSHIP_BUILTIN(GenericFSub) ANY_OWNERSHIP_BUILTIN(Fence) ANY_OWNERSHIP_BUILTIN(GetObjCTypeEncoding) ANY_OWNERSHIP_BUILTIN(ICMP_EQ) @@ -990,28 +1000,36 @@ ANY_OWNERSHIP_BUILTIN(IsConcrete) ANY_OWNERSHIP_BUILTIN(IsBitwiseTakable) ANY_OWNERSHIP_BUILTIN(IsSameMetatype) ANY_OWNERSHIP_BUILTIN(LShr) +ANY_OWNERSHIP_BUILTIN(GenericLShr) ANY_OWNERSHIP_BUILTIN(Mul) +ANY_OWNERSHIP_BUILTIN(GenericMul) ANY_OWNERSHIP_BUILTIN(OnFastPath) ANY_OWNERSHIP_BUILTIN(Once) ANY_OWNERSHIP_BUILTIN(OnceWithContext) ANY_OWNERSHIP_BUILTIN(Or) +ANY_OWNERSHIP_BUILTIN(GenericOr) ANY_OWNERSHIP_BUILTIN(PtrToInt) ANY_OWNERSHIP_BUILTIN(SAddOver) ANY_OWNERSHIP_BUILTIN(SDiv) +ANY_OWNERSHIP_BUILTIN(GenericSDiv) ANY_OWNERSHIP_BUILTIN(SExt) ANY_OWNERSHIP_BUILTIN(SExtOrBitCast) ANY_OWNERSHIP_BUILTIN(SIToFP) ANY_OWNERSHIP_BUILTIN(SMulOver) ANY_OWNERSHIP_BUILTIN(SRem) +ANY_OWNERSHIP_BUILTIN(GenericSRem) ANY_OWNERSHIP_BUILTIN(SSubOver) ANY_OWNERSHIP_BUILTIN(SToSCheckedTrunc) ANY_OWNERSHIP_BUILTIN(SToUCheckedTrunc) +ANY_OWNERSHIP_BUILTIN(Expect) ANY_OWNERSHIP_BUILTIN(Shl) +ANY_OWNERSHIP_BUILTIN(GenericShl) ANY_OWNERSHIP_BUILTIN(Sizeof) ANY_OWNERSHIP_BUILTIN(StaticReport) ANY_OWNERSHIP_BUILTIN(Strideof) ANY_OWNERSHIP_BUILTIN(StringObjectOr) ANY_OWNERSHIP_BUILTIN(Sub) +ANY_OWNERSHIP_BUILTIN(GenericSub) ANY_OWNERSHIP_BUILTIN(TakeArrayNoAlias) ANY_OWNERSHIP_BUILTIN(TakeArrayBackToFront) ANY_OWNERSHIP_BUILTIN(TakeArrayFrontToBack) @@ -1020,15 +1038,18 @@ ANY_OWNERSHIP_BUILTIN(TruncOrBitCast) ANY_OWNERSHIP_BUILTIN(TSanInoutAccess) ANY_OWNERSHIP_BUILTIN(UAddOver) ANY_OWNERSHIP_BUILTIN(UDiv) +ANY_OWNERSHIP_BUILTIN(GenericUDiv) ANY_OWNERSHIP_BUILTIN(UIToFP) ANY_OWNERSHIP_BUILTIN(UMulOver) ANY_OWNERSHIP_BUILTIN(URem) +ANY_OWNERSHIP_BUILTIN(GenericURem) ANY_OWNERSHIP_BUILTIN(USubOver) ANY_OWNERSHIP_BUILTIN(UToSCheckedTrunc) ANY_OWNERSHIP_BUILTIN(UToUCheckedTrunc) ANY_OWNERSHIP_BUILTIN(Unreachable) ANY_OWNERSHIP_BUILTIN(UnsafeGuaranteedEnd) ANY_OWNERSHIP_BUILTIN(Xor) +ANY_OWNERSHIP_BUILTIN(GenericXor) ANY_OWNERSHIP_BUILTIN(ZExt) ANY_OWNERSHIP_BUILTIN(ZExtOrBitCast) ANY_OWNERSHIP_BUILTIN(ZeroInitializer) diff --git a/lib/SIL/OwnershipUtils.cpp b/lib/SIL/OwnershipUtils.cpp index 291c817d9ee9e..b675bfe4ba8af 100644 --- a/lib/SIL/OwnershipUtils.cpp +++ b/lib/SIL/OwnershipUtils.cpp @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// #include "swift/SIL/OwnershipUtils.h" +#include "swift/Basic/Defer.h" #include "swift/SIL/SILArgument.h" #include "swift/SIL/SILInstruction.h" @@ -79,8 +80,76 @@ bool swift::isOwnershipForwardingInst(SILInstruction *i) { return isOwnershipForwardingValueKind(SILNodeKind(i->getKind())); } -bool swift::getUnderlyingBorrowIntroducers(SILValue inputValue, - SmallVectorImpl &out) { +//===----------------------------------------------------------------------===// +// Borrow Introducers +//===----------------------------------------------------------------------===// + +void BorrowScopeIntroducerKind::print(llvm::raw_ostream &os) const { + switch (value) { + case BorrowScopeIntroducerKind::SILFunctionArgument: + os << "SILFunctionArgument"; + return; + case BorrowScopeIntroducerKind::BeginBorrow: + os << "BeginBorrowInst"; + return; + case BorrowScopeIntroducerKind::LoadBorrow: + os << "LoadBorrowInst"; + return; + } + llvm_unreachable("Covered switch isn't covered?!"); +} + +void BorrowScopeIntroducerKind::dump() const { +#ifndef NDEBUG + print(llvm::dbgs()); +#endif +} + +void BorrowScopeIntroducingValue::getLocalScopeEndingInstructions( + SmallVectorImpl &scopeEndingInsts) const { + assert(isLocalScope() && "Should only call this given a local scope"); + + switch (kind) { + case BorrowScopeIntroducerKind::SILFunctionArgument: + llvm_unreachable("Should only call this with a local scope"); + case BorrowScopeIntroducerKind::BeginBorrow: + llvm::copy(cast(value)->getEndBorrows(), + std::back_inserter(scopeEndingInsts)); + return; + case BorrowScopeIntroducerKind::LoadBorrow: + llvm::copy(cast(value)->getEndBorrows(), + std::back_inserter(scopeEndingInsts)); + return; + } + llvm_unreachable("Covered switch isn't covered?!"); +} + +void BorrowScopeIntroducingValue::visitLocalScopeEndingUses( + function_ref visitor) const { + assert(isLocalScope() && "Should only call this given a local scope"); + switch (kind) { + case BorrowScopeIntroducerKind::SILFunctionArgument: + llvm_unreachable("Should only call this with a local scope"); + case BorrowScopeIntroducerKind::BeginBorrow: + for (auto *use : cast(value)->getUses()) { + if (isa(use->getUser())) { + visitor(use); + } + } + return; + case BorrowScopeIntroducerKind::LoadBorrow: + for (auto *use : cast(value)->getUses()) { + if (isa(use->getUser())) { + visitor(use); + } + } + return; + } + llvm_unreachable("Covered switch isn't covered?!"); +} + +bool swift::getUnderlyingBorrowIntroducingValues( + SILValue inputValue, SmallVectorImpl &out) { if (inputValue.getOwnershipKind() != ValueOwnershipKind::Guaranteed) return false; @@ -91,25 +160,11 @@ bool swift::getUnderlyingBorrowIntroducers(SILValue inputValue, SILValue v = worklist.pop_back_val(); // First check if v is an introducer. If so, stash it and continue. - if (isa(v) || - isa(v)) { - out.push_back(v); + if (auto scopeIntroducer = BorrowScopeIntroducingValue::get(v)) { + out.push_back(*scopeIntroducer); continue; } - // If we have a function argument with guaranteed convention, it is also an - // introducer. - if (auto *arg = dyn_cast(v)) { - if (arg->getOwnershipKind() == ValueOwnershipKind::Guaranteed) { - out.push_back(v); - continue; - } - - // Otherwise, we do not know how to handle this function argument, so - // bail. - return false; - } - // Otherwise if v is an ownership forwarding value, add its defining // instruction if (isGuaranteedForwardingValue(v)) { @@ -128,3 +183,36 @@ bool swift::getUnderlyingBorrowIntroducers(SILValue inputValue, return true; } + +llvm::raw_ostream &swift::operator<<(llvm::raw_ostream &os, + BorrowScopeIntroducerKind kind) { + kind.print(os); + return os; +} + +bool BorrowScopeIntroducingValue::areInstructionsWithinScope( + ArrayRef instructions, + SmallVectorImpl &scratchSpace, + SmallPtrSetImpl &visitedBlocks, + DeadEndBlocks &deadEndBlocks) const { + // Make sure that we clear our scratch space/utilities before we exit. + SWIFT_DEFER { + scratchSpace.clear(); + visitedBlocks.clear(); + }; + + // First make sure that we actually have a local scope. If we have a non-local + // scope, then we have something (like a SILFunctionArgument) where a larger + // semantic construct (in the case of SILFunctionArgument, the function + // itself) acts as the scope. So we already know that our passed in + // instructions must be in the same scope. + if (!isLocalScope()) + return true; + + // Otherwise, gather up our local scope ending instructions. + visitLocalScopeEndingUses( + [&scratchSpace](Operand *op) { scratchSpace.emplace_back(op); }); + + LinearLifetimeChecker checker(visitedBlocks, deadEndBlocks); + return checker.validateLifetime(value, scratchSpace, instructions); +} diff --git a/lib/SIL/SILConstants.cpp b/lib/SIL/SILConstants.cpp index 59045989bdcbc..4bd8bcb9b5894 100644 --- a/lib/SIL/SILConstants.cpp +++ b/lib/SIL/SILConstants.cpp @@ -20,7 +20,7 @@ using namespace swift; namespace swift { llvm::cl::opt - ConstExprLimit("constexpr-limit", llvm::cl::init(512), + ConstExprLimit("constexpr-limit", llvm::cl::init(1024), llvm::cl::desc("Number of instructions interpreted in a" " constexpr function")); } @@ -42,7 +42,7 @@ void SymbolicValue::print(llvm::raw_ostream &os, unsigned indent) const { os << "uninit\n"; return; case RK_Unknown: { - os << "unknown(" << (int)getUnknownReason() << "): "; + os << "unknown(" << (int)getUnknownReason().getKind() << "): "; getUnknownNode()->dump(); return; } @@ -571,9 +571,18 @@ SymbolicValue SymbolicValue::lookThroughSingleElementAggregates() const { } bool SymbolicValue::isUnknownDueToUnevaluatedInstructions() { - auto unknownReason = getUnknownReason(); - return (unknownReason == UnknownReason::ReturnedByUnevaluatedInstruction || - unknownReason == UnknownReason::MutatedByUnevaluatedInstruction); + auto unknownKind = getUnknownReason().getKind(); + return (unknownKind == UnknownReason::ReturnedByUnevaluatedInstruction || + unknownKind == UnknownReason::MutatedByUnevaluatedInstruction); +} + +static void getWitnessMethodName(WitnessMethodInst *witnessMethodInst, + SmallVectorImpl &methodName) { + assert(witnessMethodInst); + SILDeclRef witnessMember = witnessMethodInst->getMember(); + if (witnessMember.hasDecl()) { + witnessMember.getDecl()->getFullName().getString(methodName); + } } /// Given that this is an 'Unknown' value, emit diagnostic notes providing @@ -587,12 +596,20 @@ void SymbolicValue::emitUnknownDiagnosticNotes(SILLocation fallbackLoc) { ASTContext &ctx = unknownNode->getModule()->getASTContext(); // Extract the location of the instruction/construct that triggered the error - // during interpretation, if available. - Optional triggerLoc = None; - if (auto badInst = dyn_cast(unknownNode)) { - triggerLoc = skipInternalLocations(badInst->getDebugLocation()) - .getLocation() - .getSourceLoc(); + // during interpretation, if available. If the instruction is internal to + // stdlib and has an invalid location, find the innermost call that has a + // valid location. + SourceLoc triggerLoc; + bool triggerLocSkipsInternalLocs = false; + if (auto *badInst = dyn_cast(unknownNode)) { + SILDebugLocation debugLoc = badInst->getDebugLocation(); + SourceLoc initialSourceLoc = debugLoc.getLocation().getSourceLoc(); + if (initialSourceLoc.isValid()) { + triggerLoc = initialSourceLoc; + } else { + triggerLocSkipsInternalLocs = true; + triggerLoc = skipInternalLocations(debugLoc).getLocation().getSourceLoc(); + } } // Determine the top-level expression where the error happens and use it as @@ -602,7 +619,7 @@ void SymbolicValue::emitUnknownDiagnosticNotes(SILLocation fallbackLoc) { // the faulty top-level expression location cannot be found. auto diagLoc = errorCallStack.empty() - ? (triggerLoc ? triggerLoc.getValue() : fallbackLoc.getSourceLoc()) + ? (triggerLoc.isValid() ? triggerLoc : fallbackLoc.getSourceLoc()) : errorCallStack.front(); if (diagLoc.isInvalid()) { return; @@ -611,79 +628,119 @@ void SymbolicValue::emitUnknownDiagnosticNotes(SILLocation fallbackLoc) { // Emit a note at the trigger location as well if it is different from the // top-level expression. bool emitTriggerLocInDiag = - triggerLoc ? diagLoc != triggerLoc.getValue() : false; + triggerLoc.isValid() ? diagLoc != triggerLoc : false; - switch (unknownReason) { + switch (unknownReason.getKind()) { case UnknownReason::Default: diagnose(ctx, diagLoc, diag::constexpr_unknown_reason_default); if (emitTriggerLocInDiag) - diagnose(ctx, *triggerLoc, diag::constexpr_unevaluable_operation); + diagnose(ctx, triggerLoc, diag::constexpr_unevaluable_operation, + triggerLocSkipsInternalLocs); return; case UnknownReason::TooManyInstructions: diagnose(ctx, diagLoc, diag::constexpr_too_many_instructions, ConstExprLimit); if (emitTriggerLocInDiag) - diagnose(ctx, *triggerLoc, diag::constexpr_limit_exceeding_instruction); + diagnose(ctx, triggerLoc, diag::constexpr_limit_exceeding_instruction, + triggerLocSkipsInternalLocs); return; case UnknownReason::Loop: diagnose(ctx, diagLoc, diag::constexpr_loop_found_note); if (emitTriggerLocInDiag) - diagnose(ctx, *triggerLoc, diag::constexpr_loop_instruction); + diagnose(ctx, triggerLoc, diag::constexpr_loop_instruction, + triggerLocSkipsInternalLocs); return; case UnknownReason::Overflow: diagnose(ctx, diagLoc, diag::constexpr_overflow); if (emitTriggerLocInDiag) - diagnose(ctx, *triggerLoc, diag::constexpr_overflow_operation); + diagnose(ctx, triggerLoc, diag::constexpr_overflow_operation, + triggerLocSkipsInternalLocs); return; - case UnknownReason::Trap: - diagnose(ctx, diagLoc, diag::constexpr_trap); + case UnknownReason::Trap: { + const char *message = unknownReason.getTrapMessage(); + diagnose(ctx, diagLoc, diag::constexpr_trap, StringRef(message)); if (emitTriggerLocInDiag) - diagnose(ctx, *triggerLoc, diag::constexpr_trap_operation); + diagnose(ctx, triggerLoc, diag::constexpr_trap_operation, + triggerLocSkipsInternalLocs); return; + } case UnknownReason::InvalidOperandValue: diagnose(ctx, diagLoc, diag::constexpr_invalid_operand_seen); if (emitTriggerLocInDiag) - diagnose(ctx, *triggerLoc, diag::constexpr_operand_invalid_here); + diagnose(ctx, triggerLoc, diag::constexpr_operand_invalid_here, + triggerLocSkipsInternalLocs); return; case UnknownReason::NotTopLevelConstant: { // For top-level errors, trigger loc is better than diagLoc. - auto loc = emitTriggerLocInDiag ? *triggerLoc : diagLoc; + auto loc = emitTriggerLocInDiag ? triggerLoc : diagLoc; diagnose(ctx, loc, diag::constexpr_value_unknown_at_top_level); return; } case UnknownReason::MutipleTopLevelWriters: { // For top-level errors, trigger loc is better than diagLoc. - auto loc = emitTriggerLocInDiag ? *triggerLoc : diagLoc; + auto loc = emitTriggerLocInDiag ? triggerLoc : diagLoc; diagnose(ctx, loc, diag::constexpr_multiple_writers_found_at_top_level); return; } - case UnknownReason::UnsupportedInstruction: - diagnose(ctx, diagLoc, diag::constexpr_unsupported_instruction_found); + case UnknownReason::UnsupportedInstruction: { + // Get the name of the unsupported instruction. + auto *unsupportedInst = dyn_cast(unknownNode); + assert(unsupportedInst); + SmallString<4> instName(getSILInstructionName(unsupportedInst->getKind())); + if (auto *builtinInst = dyn_cast(unsupportedInst)) { + instName.append(" "); + instName.append(builtinInst->getName().str()); + } + + diagnose(ctx, diagLoc, diag::constexpr_unsupported_instruction_found, + instName); if (emitTriggerLocInDiag) - diagnose(ctx, *triggerLoc, - diag::constexpr_unsupported_instruction_found_here); + diagnose(ctx, triggerLoc, + diag::constexpr_unsupported_instruction_found_here, + triggerLocSkipsInternalLocs); return; - case UnknownReason::CalleeImplementationUnknown: - diagnose(ctx, diagLoc, diag::constexpr_unknown_function_called); + } + case UnknownReason::CalleeImplementationUnknown: { + SILFunction *callee = unknownReason.getCalleeWithoutImplmentation(); + std::string demangledCalleeName = + Demangle::demangleSymbolAsString(callee->getName()); + diagnose(ctx, diagLoc, diag::constexpr_found_callee_with_no_body, + StringRef(demangledCalleeName)); if (emitTriggerLocInDiag) - diagnose(ctx, *triggerLoc, diag::constexpr_unknown_function_called_here); + diagnose(ctx, triggerLoc, diag::constexpr_callee_with_no_body, + triggerLocSkipsInternalLocs); return; + } case UnknownReason::UntrackedSILValue: diagnose(ctx, diagLoc, diag::constexpr_untracked_sil_value_use_found); if (emitTriggerLocInDiag) - diagnose(ctx, *triggerLoc, diag::constexpr_untracked_sil_value_used_here); + diagnose(ctx, triggerLoc, diag::constexpr_untracked_sil_value_used_here, + triggerLocSkipsInternalLocs); return; - case UnknownReason::UnknownWitnessMethodConformance: - diagnose(ctx, diagLoc, - diag::constexpr_witness_call_with_no_conformance_found); + case UnknownReason::UnknownWitnessMethodConformance: { + SmallString<8> witnessMethodName; + getWitnessMethodName(dyn_cast(unknownNode), + witnessMethodName); + diagnose(ctx, diagLoc, diag::constexpr_unresolvable_witness_call, + witnessMethodName); if (emitTriggerLocInDiag) - diagnose(ctx, *triggerLoc, diag::constexpr_witness_call_found_here); + diagnose(ctx, triggerLoc, + diag::constexpr_witness_call_with_no_conformance, + triggerLocSkipsInternalLocs); return; - case UnknownReason::UnresolvableWitnessMethod: - diagnose(ctx, diagLoc, diag::constexpr_witness_call_with_no_target_found); + } + case UnknownReason::NoWitnesTableEntry: { + SmallString<8> witnessMethodName; + getWitnessMethodName(dyn_cast(unknownNode), + witnessMethodName); + + diagnose(ctx, diagLoc, diag::constexpr_unresolvable_witness_call, + StringRef(witnessMethodName)); if (emitTriggerLocInDiag) - diagnose(ctx, *triggerLoc, diag::constexpr_witness_call_found_here); + diagnose(ctx, triggerLoc, diag::constexpr_no_witness_table_entry, + triggerLocSkipsInternalLocs); return; + } case UnknownReason::ReturnedByUnevaluatedInstruction: diagnose(ctx, diagLoc, diag::constexpr_returned_by_unevaluated_instruction); break; diff --git a/lib/SIL/SILFunctionType.cpp b/lib/SIL/SILFunctionType.cpp index cd882b6127183..00ce447a3e1ca 100644 --- a/lib/SIL/SILFunctionType.cpp +++ b/lib/SIL/SILFunctionType.cpp @@ -949,7 +949,7 @@ static std::pair updateResultTypeForForeignError( /// If we ever add that ability, it will be a different capture list /// from the function to which the argument is attached. static void -lowerCaptureContextParameters(TypeConverter &TC, AnyFunctionRef function, +lowerCaptureContextParameters(TypeConverter &TC, SILDeclRef function, CanGenericSignature genericSig, ResilienceExpansion expansion, SmallVectorImpl &inputs) { @@ -959,8 +959,7 @@ lowerCaptureContextParameters(TypeConverter &TC, AnyFunctionRef function, // canonicalize references to the generic parameters that may appear in // non-canonical types in that context. We need the original generic // signature from the AST for that. - auto origGenericSig = function.getGenericSignature(); - + auto origGenericSig = function.getAnyFunctionRef()->getGenericSignature(); auto loweredCaptures = TC.getLoweredLocalCaptures(function); for (auto capture : loweredCaptures.getCaptures()) { @@ -1233,18 +1232,12 @@ static CanSILFunctionType getSILFunctionType( yields, coroutineKind); // Lower the capture context parameters, if any. - // - // *NOTE* Currently default arg generators can not capture anything. - // If we ever add that ability, it will be a different capture list - // from the function to which the argument is attached. - if (constant && !constant->isDefaultArgGenerator()) { - if (auto function = constant->getAnyFunctionRef()) { - auto expansion = ResilienceExpansion::Maximal; - if (constant->isSerialized()) - expansion = ResilienceExpansion::Minimal; - lowerCaptureContextParameters(TC, *function, genericSig, expansion, - inputs); - } + if (constant && constant->getAnyFunctionRef()) { + auto expansion = ResilienceExpansion::Maximal; + if (constant->isSerialized()) + expansion = ResilienceExpansion::Minimal; + lowerCaptureContextParameters(TC, *constant, genericSig, expansion, + inputs); } auto calleeConvention = ParameterConvention::Direct_Unowned; diff --git a/lib/SIL/SILOwnershipVerifier.cpp b/lib/SIL/SILOwnershipVerifier.cpp index 258c884610df8..a5105483c7f09 100644 --- a/lib/SIL/SILOwnershipVerifier.cpp +++ b/lib/SIL/SILOwnershipVerifier.cpp @@ -93,11 +93,11 @@ class SILValueOwnershipChecker { /// The list of lifetime ending users that we found. Only valid if check is /// successful. - SmallVector lifetimeEndingUsers; + SmallVector lifetimeEndingUsers; /// The list of non lifetime ending users that we found. Only valid if check /// is successful. - SmallVector regularUsers; + SmallVector regularUsers; /// The list of implicit non lifetime ending users that we found. This /// consists of instructions like end_borrow that end a scoped lifetime. We @@ -105,7 +105,7 @@ class SILValueOwnershipChecker { /// destroyed while that sub-scope is valid. /// /// TODO: Rename to SubBorrowScopeUsers? - SmallVector implicitRegularUsers; + SmallVector implicitRegularUsers; /// The set of blocks that we have visited. SmallPtrSetImpl &visitedBlocks; @@ -133,53 +133,25 @@ class SILValueOwnershipChecker { if (!result.getValue()) return false; + SmallVector allLifetimeEndingUsers; + llvm::copy(lifetimeEndingUsers, std::back_inserter(allLifetimeEndingUsers)); SmallVector allRegularUsers; llvm::copy(regularUsers, std::back_inserter(allRegularUsers)); llvm::copy(implicitRegularUsers, std::back_inserter(allRegularUsers)); - auto linearLifetimeResult = - valueHasLinearLifetime(value, lifetimeEndingUsers, allRegularUsers, - visitedBlocks, deadEndBlocks, errorBehavior); + + LinearLifetimeChecker checker(visitedBlocks, deadEndBlocks); + auto linearLifetimeResult = checker.checkValue( + value, allLifetimeEndingUsers, allRegularUsers, errorBehavior); result = !linearLifetimeResult.getFoundError(); return result.getValue(); } - using user_array_transform = - std::function; - using user_array = TransformArrayRef; - - /// A function that returns a range of lifetime ending users found for the - /// given value. - user_array getLifetimeEndingUsers() const { - assert(result.hasValue() && "Can not call until check() is called"); - assert(result.getValue() && "Can not call if check() returned false"); - - user_array_transform transform( - [](BranchPropagatedUser user) -> SILInstruction * { - return user.getInst(); - }); - return user_array(ArrayRef(lifetimeEndingUsers), - transform); - } - - /// A function that returns a range of regular (i.e. "non lifetime ending") - /// users found for the given value. - user_array getRegularUsers() const { - assert(result.hasValue() && "Can not call until check() is called"); - assert(result.getValue() && "Can not call if check() returned false"); - - user_array_transform transform( - [](BranchPropagatedUser user) -> SILInstruction * { - return user.getInst(); - }); - return user_array(ArrayRef(regularUsers), transform); - } - private: bool checkUses(); - bool gatherUsers(SmallVectorImpl &lifetimeEndingUsers, - SmallVectorImpl ®ularUsers, - SmallVectorImpl &implicitRegularUsers); + bool gatherUsers(SmallVectorImpl &lifetimeEndingUsers, + SmallVectorImpl ®ularUsers, + SmallVectorImpl &implicitRegularUsers); bool checkValueWithoutLifetimeEndingUses(); @@ -188,10 +160,10 @@ class SILValueOwnershipChecker { bool isGuaranteedFunctionArgWithLifetimeEndingUses( SILFunctionArgument *arg, - const SmallVectorImpl &lifetimeEndingUsers) const; + const SmallVectorImpl &lifetimeEndingUsers) const; bool isSubobjectProjectionWithLifetimeEndingUses( SILValue value, - const SmallVectorImpl &lifetimeEndingUsers) const; + const SmallVectorImpl &lifetimeEndingUsers) const; /// Depending on our initialization, either return false or call Func and /// throw an error. @@ -212,9 +184,9 @@ class SILValueOwnershipChecker { } // end anonymous namespace bool SILValueOwnershipChecker::gatherUsers( - SmallVectorImpl &lifetimeEndingUsers, - SmallVectorImpl &nonLifetimeEndingUsers, - SmallVectorImpl &implicitRegularUsers) { + SmallVectorImpl &lifetimeEndingUsers, + SmallVectorImpl &nonLifetimeEndingUsers, + SmallVectorImpl &implicitRegularUsers) { // See if Value is guaranteed. If we are guaranteed and not forwarding, then // we need to look through subobject uses for more uses. Otherwise, if we are @@ -229,19 +201,7 @@ bool SILValueOwnershipChecker::gatherUsers( // Then gather up our initial list of users. SmallVector users; - std::copy(value->use_begin(), value->use_end(), std::back_inserter(users)); - - auto addCondBranchToList = [](SmallVectorImpl &list, - CondBranchInst *cbi, unsigned operandIndex) { - if (cbi->isConditionOperandIndex(operandIndex)) { - list.emplace_back(cbi); - return; - } - - bool isTrueOperand = cbi->isTrueOperandIndex(operandIndex); - list.emplace_back(cbi, isTrueOperand ? CondBranchInst::TrueIdx - : CondBranchInst::FalseIdx); - }; + llvm::copy(value->getUses(), std::back_inserter(users)); bool foundError = false; while (!users.empty()) { @@ -298,19 +258,10 @@ bool SILValueOwnershipChecker::gatherUsers( opOwnershipKindMap.getLifetimeConstraint(ownershipKind); if (lifetimeConstraint == UseLifetimeConstraint::MustBeInvalidated) { LLVM_DEBUG(llvm::dbgs() << " Lifetime Ending User: " << *user); - if (auto *cbi = dyn_cast(user)) { - addCondBranchToList(lifetimeEndingUsers, cbi, op->getOperandNumber()); - } else { - lifetimeEndingUsers.emplace_back(user); - } + lifetimeEndingUsers.push_back(op); } else { LLVM_DEBUG(llvm::dbgs() << " Regular User: " << *user); - if (auto *cbi = dyn_cast(user)) { - addCondBranchToList(nonLifetimeEndingUsers, cbi, - op->getOperandNumber()); - } else { - nonLifetimeEndingUsers.emplace_back(user); - } + nonLifetimeEndingUsers.push_back(op); } // If our base value is not guaranteed, we do not to try to visit @@ -327,12 +278,14 @@ bool SILValueOwnershipChecker::gatherUsers( // For correctness reasons we use indices to make sure that we can // append to NonLifetimeEndingUsers without needing to deal with // iterator invalidation. - SmallVector endBorrowInsts; for (unsigned i : indices(nonLifetimeEndingUsers)) { if (auto *bbi = dyn_cast( - nonLifetimeEndingUsers[i].getInst())) { - llvm::copy(bbi->getEndBorrows(), - std::back_inserter(implicitRegularUsers)); + nonLifetimeEndingUsers[i]->getUser())) { + for (auto *use : bbi->getUses()) { + if (isa(use->getUser())) { + implicitRegularUsers.push_back(use); + } + } } } } @@ -412,8 +365,8 @@ bool SILValueOwnershipChecker::gatherUsers( // them to ensure that all of BBArg's uses are completely // enclosed within the end_borrow of this argument. for (auto *op : succArg->getUses()) { - if (auto *ebi = dyn_cast(op->getUser())) { - implicitRegularUsers.push_back(ebi); + if (isa(op->getUser())) { + implicitRegularUsers.push_back(op); } } } @@ -524,8 +477,7 @@ bool SILValueOwnershipChecker::checkValueWithoutLifetimeEndingUses() { bool SILValueOwnershipChecker::isGuaranteedFunctionArgWithLifetimeEndingUses( SILFunctionArgument *arg, - const llvm::SmallVectorImpl &lifetimeEndingUsers) - const { + const llvm::SmallVectorImpl &lifetimeEndingUsers) const { if (arg->getOwnershipKind() != ValueOwnershipKind::Guaranteed) return true; @@ -533,8 +485,8 @@ bool SILValueOwnershipChecker::isGuaranteedFunctionArgWithLifetimeEndingUses( llvm::errs() << " Function: '" << arg->getFunction()->getName() << "'\n" << " Guaranteed function parameter with life ending uses!\n" << " Value: " << *arg; - for (const auto &user : lifetimeEndingUsers) { - llvm::errs() << " Lifetime Ending User: " << *user; + for (const auto *use : lifetimeEndingUsers) { + llvm::errs() << " Lifetime Ending User: " << *use->getUser(); } llvm::errs() << '\n'; }); @@ -542,15 +494,14 @@ bool SILValueOwnershipChecker::isGuaranteedFunctionArgWithLifetimeEndingUses( bool SILValueOwnershipChecker::isSubobjectProjectionWithLifetimeEndingUses( SILValue value, - const llvm::SmallVectorImpl &lifetimeEndingUsers) - const { + const llvm::SmallVectorImpl &lifetimeEndingUsers) const { return handleError([&] { llvm::errs() << " Function: '" << value->getFunction()->getName() << "'\n" << " Subobject projection with life ending uses!\n" << " Value: " << *value; - for (const auto &user : lifetimeEndingUsers) { - llvm::errs() << " Lifetime Ending User: " << *user; + for (const auto *use : lifetimeEndingUsers) { + llvm::errs() << " Lifetime Ending User: " << *use->getUser(); } llvm::errs() << '\n'; }); diff --git a/lib/SIL/SILProfiler.cpp b/lib/SIL/SILProfiler.cpp index 3120ddabe2e5f..b6ce5e18b3b1a 100644 --- a/lib/SIL/SILProfiler.cpp +++ b/lib/SIL/SILProfiler.cpp @@ -15,6 +15,7 @@ #include "swift/AST/Decl.h" #include "swift/AST/Expr.h" #include "swift/AST/Module.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/Stmt.h" #include "swift/Parse/Lexer.h" #include "swift/SIL/FormalLinkage.h" diff --git a/lib/SIL/SILType.cpp b/lib/SIL/SILType.cpp index 9778c3b74df80..be1cada7c67c8 100644 --- a/lib/SIL/SILType.cpp +++ b/lib/SIL/SILType.cpp @@ -139,18 +139,13 @@ bool SILType::canRefCast(SILType operTy, SILType resultTy, SILModule &M) { SILType SILType::getFieldType(VarDecl *field, TypeConverter &TC) const { - auto baseTy = getASTType(); - - if (!field->hasInterfaceType()) - TC.Context.getLazyResolver()->resolveDeclSignature(field); - AbstractionPattern origFieldTy = TC.getAbstractionPattern(field); CanType substFieldTy; if (field->hasClangNode()) { substFieldTy = origFieldTy.getType(); } else { substFieldTy = - baseTy->getTypeOfMember(&TC.M, field, nullptr)->getCanonicalType(); + getASTType()->getTypeOfMember(&TC.M, field, nullptr)->getCanonicalType(); } auto loweredTy = TC.getLoweredRValueType(origFieldTy, substFieldTy); @@ -175,9 +170,6 @@ SILType SILType::getEnumElementType(EnumElementDecl *elt, return SILType(objectType, getCategory()); } - if (!elt->hasInterfaceType()) - TC.Context.getLazyResolver()->resolveDeclSignature(elt); - // If the case is indirect, then the payload is boxed. if (elt->isIndirect() || elt->getParentEnum()->isIndirect()) { auto box = TC.getBoxTypeForEnumElement(*this, elt); diff --git a/lib/SIL/SILVerifier.cpp b/lib/SIL/SILVerifier.cpp index 2ea6d9db98923..728ed55f0a477 100644 --- a/lib/SIL/SILVerifier.cpp +++ b/lib/SIL/SILVerifier.cpp @@ -507,7 +507,27 @@ struct ImmutableAddressUseVerifier { if (inst->isTypeDependentOperand(*use)) continue; + // TODO: Can this switch be restructured so break -> error, continue -> + // next iteration, return -> return the final result. switch (inst->getKind()) { + case SILInstructionKind::BuiltinInst: { + // If we are processing a polymorphic builtin that takes an address, + // skip the builtin. This is because the builtin must be specialized to + // a non-memory reading builtin that works on trivial object values + // before the diagnostic passes end (or be DCEed) or we emit a + // diagnostic. + if (auto builtinKind = cast(inst)->getBuiltinKind()) { + if (isPolymorphicBuiltin(*builtinKind)) { + break; + } + } + + // Otherwise this is a builtin that we are not expecting to see, so bail + // and assert. + llvm::errs() << "Unhandled, unexpected builtin instruction: " << *inst; + llvm_unreachable("invoking standard assertion failure"); + break; + } case SILInstructionKind::MarkDependenceInst: case SILInstructionKind::LoadBorrowInst: case SILInstructionKind::DebugValueAddrInst: @@ -1691,8 +1711,10 @@ class SILVerifier : public SILVerifierBase { void checkBuiltinInst(BuiltinInst *BI) { // Check for special constraints on llvm intrinsics. - if (BI->getIntrinsicInfo().ID != llvm::Intrinsic::not_intrinsic) + if (BI->getIntrinsicInfo().ID != llvm::Intrinsic::not_intrinsic) { verifyLLVMIntrinsic(BI, BI->getIntrinsicInfo().ID); + return; + } } void checkFunctionRefBaseInst(FunctionRefBaseInst *FRI) { diff --git a/lib/SIL/TypeLowering.cpp b/lib/SIL/TypeLowering.cpp index cc4f6b03f9317..08729f590c368 100644 --- a/lib/SIL/TypeLowering.cpp +++ b/lib/SIL/TypeLowering.cpp @@ -22,6 +22,7 @@ #include "swift/AST/LazyResolver.h" #include "swift/AST/Module.h" #include "swift/AST/NameLookup.h" +#include "swift/AST/ParameterList.h" #include "swift/AST/Pattern.h" #include "swift/AST/PropertyWrappers.h" #include "swift/AST/Types.h" @@ -1362,10 +1363,6 @@ namespace { // Classify the type according to its stored properties. for (auto field : D->getStoredProperties()) { - // FIXME: Remove this once getInterfaceType() is a request. - if (!field->hasInterfaceType()) - TC.Context.getLazyResolver()->resolveDeclSignature(field); - auto substFieldType = field->getInterfaceType().subst(subMap)->getCanonicalType(); @@ -1408,11 +1405,7 @@ namespace { properties.setNonTrivial(); continue; } - - // FIXME: Remove this once getInterfaceType() is a request. - if (!elt->hasInterfaceType()) - TC.Context.getLazyResolver()->resolveDeclSignature(elt); - + auto substEltType = elt->getArgumentInterfaceType().subst(subMap)->getCanonicalType(); @@ -1831,6 +1824,30 @@ getTypeLoweringForExpansion(TypeKey key, return nullptr; } +static GenericSignature * +getEffectiveGenericSignature(DeclContext *dc, + CaptureInfo captureInfo) { + if (dc->getParent()->isLocalContext() && + !captureInfo.hasGenericParamCaptures()) + return nullptr; + + return dc->getGenericSignatureOfContext(); +} + +static GenericSignature * +getEffectiveGenericSignature(AnyFunctionRef fn, + CaptureInfo captureInfo) { + return getEffectiveGenericSignature(fn.getAsDeclContext(), captureInfo); +} + +static CanGenericSignature +getCanonicalSignatureOrNull(GenericSignature *sig) { + if (!sig || sig->areAllParamsConcrete()) + return nullptr; + + return sig->getCanonicalSignature(); +} + /// Get the type of a global variable accessor function, () -> RawPointer. static CanAnyFunctionType getGlobalAccessorType(CanType varType) { ASTContext &C = varType->getASTContext(); @@ -1839,17 +1856,17 @@ static CanAnyFunctionType getGlobalAccessorType(CanType varType) { /// Get the type of a default argument generator, () -> T. static CanAnyFunctionType getDefaultArgGeneratorInterfaceType( - TypeConverter &TC, - ValueDecl *VD, - DeclContext *DC, - unsigned DefaultArgIndex) { - auto resultTy = getParameterAt(VD, DefaultArgIndex)->getInterfaceType(); + SILDeclRef c) { + auto *vd = c.getDecl(); + auto resultTy = getParameterAt(vd, + c.defaultArgIndex)->getInterfaceType(); assert(resultTy && "Didn't find default argument?"); // The result type might be written in terms of type parameters // that have been made fully concrete. CanType canResultTy = resultTy->getCanonicalType( - DC->getGenericSignatureOfContext()); + vd->getInnermostDeclContext() + ->getGenericSignatureOfContext()); // Remove @noescape from function return types. A @noescape // function return type is a contradiction. @@ -1860,19 +1877,21 @@ static CanAnyFunctionType getDefaultArgGeneratorInterfaceType( } // Get the generic signature from the surrounding context. - CanGenericSignature sig; - if (auto *afd = dyn_cast(VD)) { - auto funcInfo = TC.getConstantInfo(SILDeclRef(VD)); - sig = funcInfo.FormalType.getOptGenericSignature(); - } else { - sig = TC.getEffectiveGenericSignature(DC); + auto *sig = vd->getInnermostDeclContext()->getGenericSignatureOfContext(); + if (auto *afd = dyn_cast(vd)) { + auto *param = getParameterAt(afd, c.defaultArgIndex); + if (param->getDefaultValue()) { + auto &captureInfo = param->getDefaultArgumentCaptureInfo(); + sig = getEffectiveGenericSignature(afd, captureInfo); + } } - return CanAnyFunctionType::get(sig, {}, canResultTy); + + return CanAnyFunctionType::get(getCanonicalSignatureOrNull(sig), + {}, canResultTy); } /// Get the type of a stored property initializer, () -> T. static CanAnyFunctionType getStoredPropertyInitializerInterfaceType( - TypeConverter &TC, VarDecl *VD) { auto *DC = VD->getDeclContext(); CanType resultTy = @@ -1887,14 +1906,14 @@ static CanAnyFunctionType getStoredPropertyInitializerInterfaceType( resultTy = originalProperty->getValueInterfaceType()->getCanonicalType(); } - auto sig = TC.getEffectiveGenericSignature(DC); + auto sig = DC->getGenericSignatureOfContext(); - return CanAnyFunctionType::get(sig, {}, resultTy); + return CanAnyFunctionType::get(getCanonicalSignatureOrNull(sig), + {}, resultTy); } /// Get the type of a destructor function. -static CanAnyFunctionType getDestructorInterfaceType(TypeConverter &TC, - DestructorDecl *dd, +static CanAnyFunctionType getDestructorInterfaceType(DestructorDecl *dd, bool isDeallocating, bool isForeign) { auto classType = dd->getDeclContext()->getDeclaredInterfaceType() @@ -1912,29 +1931,29 @@ static CanAnyFunctionType getDestructorInterfaceType(TypeConverter &TC, extInfo = extInfo .withSILRepresentation(SILFunctionTypeRepresentation::Method); - auto &C = TC.Context; + auto &C = dd->getASTContext(); CanType resultTy = (isDeallocating ? TupleType::getEmpty(C) : C.TheNativeObjectType); CanType methodTy = CanFunctionType::get({}, resultTy); - auto sig = TC.getEffectiveGenericSignature(dd); + auto sig = dd->getGenericSignatureOfContext(); FunctionType::Param args[] = {FunctionType::Param(classType)}; - return CanAnyFunctionType::get(sig, llvm::makeArrayRef(args), + return CanAnyFunctionType::get(getCanonicalSignatureOrNull(sig), + llvm::makeArrayRef(args), methodTy, extInfo); } /// Retrieve the type of the ivar initializer or destroyer method for /// a class. -static CanAnyFunctionType getIVarInitDestroyerInterfaceType(TypeConverter &TC, - ClassDecl *cd, +static CanAnyFunctionType getIVarInitDestroyerInterfaceType(ClassDecl *cd, bool isObjC, bool isDestroyer) { auto classType = cd->getDeclaredInterfaceType() ->getCanonicalType(cd->getGenericSignatureOfContext()); auto resultType = (isDestroyer - ? TupleType::getEmpty(TC.Context) + ? TupleType::getEmpty(cd->getASTContext()) : classType); auto extInfo = AnyFunctionType::ExtInfo(FunctionType::Representation::Thin, /*throws*/ false); @@ -1943,62 +1962,32 @@ static CanAnyFunctionType getIVarInitDestroyerInterfaceType(TypeConverter &TC, : SILFunctionTypeRepresentation::Method); resultType = CanFunctionType::get({}, resultType, extInfo); - auto sig = TC.getEffectiveGenericSignature(cd); + auto sig = cd->getGenericSignature(); FunctionType::Param args[] = {FunctionType::Param(classType)}; - return CanAnyFunctionType::get(sig, llvm::makeArrayRef(args), + return CanAnyFunctionType::get(getCanonicalSignatureOrNull(sig), + llvm::makeArrayRef(args), resultType, extInfo); } -GenericEnvironment * -TypeConverter::getEffectiveGenericEnvironment(AnyFunctionRef fn, - CaptureInfo captureInfo) { - auto dc = fn.getAsDeclContext(); - - if (getEffectiveGenericSignature(fn, captureInfo)) - return dc->getGenericEnvironmentOfContext(); - - return nullptr; -} - -CanGenericSignature -TypeConverter::getEffectiveGenericSignature(DeclContext *dc) { - if (auto sig = dc->getGenericSignatureOfContext()) { - if (sig->areAllParamsConcrete()) - return nullptr; - return sig->getCanonicalSignature(); - } - - return nullptr; -} - -CanGenericSignature -TypeConverter::getEffectiveGenericSignature(AnyFunctionRef fn, - CaptureInfo captureInfo) { - auto dc = fn.getAsDeclContext(); - - if (dc->getParent()->isLocalContext() && - !captureInfo.hasGenericParamCaptures()) - return nullptr; - - return getEffectiveGenericSignature(dc); -} - -CanAnyFunctionType -TypeConverter::getFunctionInterfaceTypeWithCaptures(CanAnyFunctionType funcType, - AnyFunctionRef theClosure) { +static CanAnyFunctionType +getFunctionInterfaceTypeWithCaptures(TypeConverter &TC, + CanAnyFunctionType funcType, + SILDeclRef constant) { // Get transitive closure of value captured by this function, and any // captured functions. - auto captureInfo = getLoweredLocalCaptures(theClosure); + auto captureInfo = TC.getLoweredLocalCaptures(constant); // Capture generic parameters from the enclosing context if necessary. - CanGenericSignature genericSig = getEffectiveGenericSignature(theClosure, - captureInfo); + auto closure = *constant.getAnyFunctionRef(); + auto *genericSig = getEffectiveGenericSignature(closure, captureInfo); auto innerExtInfo = AnyFunctionType::ExtInfo(FunctionType::Representation::Thin, funcType->throws()); - return CanAnyFunctionType::get(genericSig, funcType.getParams(), - funcType.getResult(), innerExtInfo); + return CanAnyFunctionType::get( + getCanonicalSignatureOrNull(genericSig), + funcType.getParams(), funcType.getResult(), + innerExtInfo); } CanAnyFunctionType TypeConverter::makeConstantInterfaceType(SILDeclRef c) { @@ -2014,33 +2003,25 @@ CanAnyFunctionType TypeConverter::makeConstantInterfaceType(SILDeclRef c) { } auto *vd = c.loc.dyn_cast(); - - if (vd && !vd->hasInterfaceType()) { - Context.getLazyResolver()->resolveDeclSignature(vd); - } - switch (c.kind) { case SILDeclRef::Kind::Func: { + CanAnyFunctionType funcTy; if (auto *ACE = c.loc.dyn_cast()) { // FIXME: Closures could have an interface type computed by Sema. - auto funcTy = cast(ACE->getType()->getCanonicalType()); funcTy = cast( - funcTy->mapTypeOutOfContext() - ->getCanonicalType()); - return getFunctionInterfaceTypeWithCaptures(funcTy, ACE); + ACE->getType()->mapTypeOutOfContext()->getCanonicalType()); + } else { + funcTy = cast( + vd->getInterfaceType()->getCanonicalType()); } - - FuncDecl *func = cast(vd); - auto funcTy = cast( - func->getInterfaceType()->getCanonicalType()); - return getFunctionInterfaceTypeWithCaptures(funcTy, func); + return getFunctionInterfaceTypeWithCaptures(*this, funcTy, c); } case SILDeclRef::Kind::EnumElement: { auto funcTy = cast( - vd->getInterfaceType()->getCanonicalType()); - auto sig = getEffectiveGenericSignature(vd->getDeclContext()); - return CanAnyFunctionType::get(sig, + vd->getInterfaceType()->getCanonicalType()); + auto sig = vd->getDeclContext()->getGenericSignatureOfContext(); + return CanAnyFunctionType::get(getCanonicalSignatureOrNull(sig), funcTy->getParams(), funcTy.getResult(), funcTy->getExtInfo()); @@ -2050,20 +2031,19 @@ CanAnyFunctionType TypeConverter::makeConstantInterfaceType(SILDeclRef c) { auto *cd = cast(vd); auto funcTy = cast( cd->getInterfaceType()->getCanonicalType()); - return getFunctionInterfaceTypeWithCaptures(funcTy, cd); + return getFunctionInterfaceTypeWithCaptures(*this, funcTy, c); } case SILDeclRef::Kind::Initializer: { auto *cd = cast(vd); auto funcTy = cast( cd->getInitializerInterfaceType()->getCanonicalType()); - return getFunctionInterfaceTypeWithCaptures(funcTy, cd); + return getFunctionInterfaceTypeWithCaptures(*this, funcTy, c); } case SILDeclRef::Kind::Destroyer: case SILDeclRef::Kind::Deallocator: - return getDestructorInterfaceType(*this, - cast(vd), + return getDestructorInterfaceType(cast(vd), c.kind == SILDeclRef::Kind::Deallocator, c.isForeign); @@ -2074,74 +2054,60 @@ CanAnyFunctionType TypeConverter::makeConstantInterfaceType(SILDeclRef c) { return getGlobalAccessorType(var->getInterfaceType()->getCanonicalType()); } case SILDeclRef::Kind::DefaultArgGenerator: - return getDefaultArgGeneratorInterfaceType(*this, vd, - vd->getInnermostDeclContext(), - c.defaultArgIndex); + return getDefaultArgGeneratorInterfaceType(c); case SILDeclRef::Kind::StoredPropertyInitializer: - return getStoredPropertyInitializerInterfaceType(*this, - cast(vd)); + return getStoredPropertyInitializerInterfaceType(cast(vd)); case SILDeclRef::Kind::IVarInitializer: - return getIVarInitDestroyerInterfaceType(*this, - cast(vd), + return getIVarInitDestroyerInterfaceType(cast(vd), c.isForeign, false); case SILDeclRef::Kind::IVarDestroyer: - return getIVarInitDestroyerInterfaceType(*this, - cast(vd), + return getIVarInitDestroyerInterfaceType(cast(vd), c.isForeign, true); } llvm_unreachable("Unhandled SILDeclRefKind in switch."); } -/// Get the generic environment for an entity. -GenericEnvironment * -TypeConverter::getConstantGenericEnvironment(SILDeclRef c) { +GenericSignature * +TypeConverter::getConstantGenericSignature(SILDeclRef c) { auto *vd = c.loc.dyn_cast(); /// Get the function generic params, including outer params. switch (c.kind) { - case SILDeclRef::Kind::Func: { - if (auto *ACE = c.getAbstractClosureExpr()) { - auto captureInfo = getLoweredLocalCaptures(ACE); - - return getEffectiveGenericEnvironment(ACE, captureInfo); - } - FuncDecl *func = cast(vd); - auto captureInfo = getLoweredLocalCaptures(func); - - return getEffectiveGenericEnvironment(func, captureInfo); - } - case SILDeclRef::Kind::EnumElement: { - auto eltDecl = cast(vd); - return eltDecl->getDeclContext()->getGenericEnvironmentOfContext(); - } + case SILDeclRef::Kind::Func: case SILDeclRef::Kind::Allocator: case SILDeclRef::Kind::Initializer: case SILDeclRef::Kind::Destroyer: case SILDeclRef::Kind::Deallocator: { - auto *afd = cast(vd); - auto captureInfo = getLoweredLocalCaptures(afd); - return getEffectiveGenericEnvironment(afd, captureInfo); + auto captureInfo = getLoweredLocalCaptures(c); + return getEffectiveGenericSignature( + *c.getAnyFunctionRef(), captureInfo); } - case SILDeclRef::Kind::GlobalAccessor: - return vd->getDeclContext()->getGenericEnvironmentOfContext(); case SILDeclRef::Kind::IVarInitializer: case SILDeclRef::Kind::IVarDestroyer: - return cast(vd)->getGenericEnvironmentOfContext(); - case SILDeclRef::Kind::DefaultArgGenerator: + return cast(vd)->getGenericSignature(); + case SILDeclRef::Kind::DefaultArgGenerator: { // Use the generic environment of the original function. - if (auto *afd = dyn_cast(c.getDecl())) - return getConstantGenericEnvironment(SILDeclRef(c.getDecl())); - return c.getDecl()->getInnermostDeclContext() - ->getGenericEnvironmentOfContext(); + auto captureInfo = getLoweredLocalCaptures(c); + return getEffectiveGenericSignature( + vd->getInnermostDeclContext(), captureInfo); + } + case SILDeclRef::Kind::EnumElement: + case SILDeclRef::Kind::GlobalAccessor: case SILDeclRef::Kind::StoredPropertyInitializer: - // Use the generic environment of the containing type. - return c.getDecl()->getDeclContext()->getGenericEnvironmentOfContext(); + return vd->getDeclContext()->getGenericSignatureOfContext(); } llvm_unreachable("Unhandled SILDeclRefKind in switch."); } +GenericEnvironment * +TypeConverter::getConstantGenericEnvironment(SILDeclRef c) { + if (auto *sig = getConstantGenericSignature(c)) + return sig->getGenericEnvironment(); + return nullptr; +} + SILType TypeConverter::getSubstitutedStorageType(AbstractStorageDecl *value, Type lvalueType) { // The l-value type is the result of applying substitutions to @@ -2231,21 +2197,15 @@ getAnyFunctionRefFromCapture(CapturedValue capture) { } bool -TypeConverter::hasLoweredLocalCaptures(AnyFunctionRef fn) { +TypeConverter::hasLoweredLocalCaptures(SILDeclRef fn) { return !getLoweredLocalCaptures(fn).getCaptures().empty(); } CaptureInfo -TypeConverter::getLoweredLocalCaptures(AnyFunctionRef fn) { - // First, bail out if there are no local captures at all. - if (!fn.getCaptureInfo().hasLocalCaptures() && - !fn.getCaptureInfo().hasOpaqueValueCapture() && - !fn.getCaptureInfo().hasDynamicSelfCapture()) { - CaptureInfo info; - info.setGenericParamCaptures( - fn.getCaptureInfo().hasGenericParamCaptures()); - return info; - }; +TypeConverter::getLoweredLocalCaptures(SILDeclRef fn) { + fn.isForeign = 0; + fn.isCurried = 0; + fn.isDirectReference = 0; // See if we've cached the lowered capture list for this function. auto found = LoweredCaptures.find(fn); @@ -2264,20 +2224,20 @@ TypeConverter::getLoweredLocalCaptures(AnyFunctionRef fn) { DynamicSelfType *capturesDynamicSelf = nullptr; OpaqueValueExpr *capturesOpaqueValue = nullptr; - std::function collectFunctionCaptures - = [&](AnyFunctionRef curFn) { - if (!visitedFunctions.insert(curFn).second) - return; - - if (curFn.getCaptureInfo().hasGenericParamCaptures()) + std::function collectCaptures; + std::function collectFunctionCaptures; + std::function collectConstantCaptures; + + collectCaptures = [&](const CaptureInfo &captureInfo) { + if (captureInfo.hasGenericParamCaptures()) capturesGenericParams = true; - if (curFn.getCaptureInfo().hasDynamicSelfCapture()) - capturesDynamicSelf = curFn.getCaptureInfo().getDynamicSelfType(); - if (curFn.getCaptureInfo().hasOpaqueValueCapture()) - capturesOpaqueValue = curFn.getCaptureInfo().getOpaqueValue(); + if (captureInfo.hasDynamicSelfCapture()) + capturesDynamicSelf = captureInfo.getDynamicSelfType(); + if (captureInfo.hasOpaqueValueCapture()) + capturesOpaqueValue = captureInfo.getOpaqueValue(); SmallVector localCaptures; - curFn.getCaptureInfo().getLocalCaptures(localCaptures); + captureInfo.getLocalCaptures(localCaptures); for (auto capture : localCaptures) { // If the capture is of another local function, grab its transitive // captures instead. @@ -2390,7 +2350,47 @@ TypeConverter::getLoweredLocalCaptures(AnyFunctionRef fn) { } } }; - collectFunctionCaptures(fn); + + collectFunctionCaptures = [&](AnyFunctionRef curFn) { + if (!visitedFunctions.insert(curFn).second) + return; + + collectCaptures(curFn.getCaptureInfo()); + + // A function's captures also include its default arguments, because + // when we reference a function we don't track which default arguments + // are referenced too. + // + // FIXME: This should be more fine-grained -- we should only need the + // captures for default arguments that are actually referenced. + if (auto *AFD = curFn.getAbstractFunctionDecl()) { + for (auto *P : *AFD->getParameters()) { + if (P->getDefaultValue()) + collectCaptures(P->getDefaultArgumentCaptureInfo()); + } + } + }; + + collectConstantCaptures = [&](SILDeclRef curFn) { + if (curFn.isDefaultArgGenerator()) { + if (auto *afd = dyn_cast(curFn.getDecl())) { + auto *param = getParameterAt(afd, curFn.defaultArgIndex); + if (param->getDefaultValue()) + collectCaptures(param->getDefaultArgumentCaptureInfo()); + return; + } + + if (curFn.getDecl()->getInnermostDeclContext() + ->getGenericSignatureOfContext()) + capturesGenericParams = true; + + return; + } + + collectFunctionCaptures(*curFn.getAnyFunctionRef()); + }; + + collectConstantCaptures(fn); SmallVector resultingCaptures; for (auto capturePair : captures) { @@ -2413,15 +2413,12 @@ TypeConverter::getLoweredLocalCaptures(AnyFunctionRef fn) { } // Cache the uniqued set of transitive captures. - auto inserted = LoweredCaptures.insert({fn, CaptureInfo()}); + CaptureInfo info{Context, resultingCaptures, capturesDynamicSelf, + capturesOpaqueValue, capturesGenericParams}; + auto inserted = LoweredCaptures.insert({fn, info}); assert(inserted.second && "already in map?!"); - auto &cachedCaptures = inserted.first->second; - cachedCaptures.setGenericParamCaptures(capturesGenericParams); - cachedCaptures.setDynamicSelfType(capturesDynamicSelf); - cachedCaptures.setOpaqueValue(capturesOpaqueValue); - cachedCaptures.setCaptures(Context.AllocateCopy(resultingCaptures)); - - return cachedCaptures; + (void)inserted; + return info; } /// Given that type1 is known to be a subtype of type2, check if the two @@ -2635,7 +2632,8 @@ TypeConverter::getInterfaceBoxTypeForCapture(ValueDecl *captured, CanType loweredInterfaceType, bool isMutable) { auto &C = M.getASTContext(); - auto signature = getEffectiveGenericSignature(captured->getDeclContext()); + auto signature = getCanonicalSignatureOrNull( + captured->getDeclContext()->getGenericSignatureOfContext()); // If the type is not dependent at all, we can form a concrete box layout. // We don't need to capture the generic environment. @@ -2717,12 +2715,8 @@ CanSILBoxType TypeConverter::getBoxTypeForEnumElement(SILType enumType, assert(elt->isIndirect() || elt->getParentEnum()->isIndirect()); auto &C = M.getASTContext(); - - // FIXME: Remove this once getInterfaceType() is a request. - if (!elt->hasInterfaceType()) - Context.getLazyResolver()->resolveDeclSignature(elt); - - auto boxSignature = getEffectiveGenericSignature(enumDecl); + auto boxSignature = getCanonicalSignatureOrNull( + enumDecl->getGenericSignature()); if (boxSignature == CanGenericSignature()) { auto eltIntfTy = elt->getArgumentInterfaceType(); @@ -2792,9 +2786,6 @@ static void countNumberOfInnerFields(unsigned &fieldsCount, TypeConverter &TC, if (elt->isIndirect()) continue; - if (!elt->hasInterfaceType()) - TC.Context.getLazyResolver()->resolveDeclSignature(elt); - // Although one might assume enums have a fields count of 1 // Which holds true for current uses of this code // (we shouldn't expand enums) diff --git a/lib/SIL/ValueOwnership.cpp b/lib/SIL/ValueOwnership.cpp index b3b0355c217af..e9e7982477146 100644 --- a/lib/SIL/ValueOwnership.cpp +++ b/lib/SIL/ValueOwnership.cpp @@ -378,15 +378,21 @@ struct ValueOwnershipKindBuiltinVisitor // UnsafeGuaranteedEnd. This provides the guarantee that we want. CONSTANT_OWNERSHIP_BUILTIN(Owned, UnsafeGuaranteed) CONSTANT_OWNERSHIP_BUILTIN(Any, AShr) +CONSTANT_OWNERSHIP_BUILTIN(Any, GenericAShr) CONSTANT_OWNERSHIP_BUILTIN(Any, Add) +CONSTANT_OWNERSHIP_BUILTIN(Any, GenericAdd) CONSTANT_OWNERSHIP_BUILTIN(Any, And) +CONSTANT_OWNERSHIP_BUILTIN(Any, GenericAnd) CONSTANT_OWNERSHIP_BUILTIN(Any, AssumeNonNegative) CONSTANT_OWNERSHIP_BUILTIN(Any, AssumeTrue) CONSTANT_OWNERSHIP_BUILTIN(Any, BitCast) CONSTANT_OWNERSHIP_BUILTIN(Any, CondFailMessage) CONSTANT_OWNERSHIP_BUILTIN(Any, ExactSDiv) +CONSTANT_OWNERSHIP_BUILTIN(Any, GenericExactSDiv) CONSTANT_OWNERSHIP_BUILTIN(Any, ExactUDiv) +CONSTANT_OWNERSHIP_BUILTIN(Any, GenericExactUDiv) CONSTANT_OWNERSHIP_BUILTIN(Any, FAdd) +CONSTANT_OWNERSHIP_BUILTIN(Any, GenericFAdd) CONSTANT_OWNERSHIP_BUILTIN(Any, FCMP_OEQ) CONSTANT_OWNERSHIP_BUILTIN(Any, FCMP_OGE) CONSTANT_OWNERSHIP_BUILTIN(Any, FCMP_OGT) @@ -400,14 +406,18 @@ CONSTANT_OWNERSHIP_BUILTIN(Any, FCMP_ULE) CONSTANT_OWNERSHIP_BUILTIN(Any, FCMP_ULT) CONSTANT_OWNERSHIP_BUILTIN(Any, FCMP_UNE) CONSTANT_OWNERSHIP_BUILTIN(Any, FDiv) +CONSTANT_OWNERSHIP_BUILTIN(Any, GenericFDiv) CONSTANT_OWNERSHIP_BUILTIN(Any, FMul) +CONSTANT_OWNERSHIP_BUILTIN(Any, GenericFMul) CONSTANT_OWNERSHIP_BUILTIN(Any, FNeg) CONSTANT_OWNERSHIP_BUILTIN(Any, FPExt) CONSTANT_OWNERSHIP_BUILTIN(Any, FPToSI) CONSTANT_OWNERSHIP_BUILTIN(Any, FPToUI) CONSTANT_OWNERSHIP_BUILTIN(Any, FPTrunc) CONSTANT_OWNERSHIP_BUILTIN(Any, FRem) +CONSTANT_OWNERSHIP_BUILTIN(Any, GenericFRem) CONSTANT_OWNERSHIP_BUILTIN(Any, FSub) +CONSTANT_OWNERSHIP_BUILTIN(Any, GenericFSub) CONSTANT_OWNERSHIP_BUILTIN(Any, ICMP_EQ) CONSTANT_OWNERSHIP_BUILTIN(Any, ICMP_NE) CONSTANT_OWNERSHIP_BUILTIN(Any, ICMP_SGE) @@ -420,28 +430,39 @@ CONSTANT_OWNERSHIP_BUILTIN(Any, ICMP_ULE) CONSTANT_OWNERSHIP_BUILTIN(Any, ICMP_ULT) CONSTANT_OWNERSHIP_BUILTIN(Any, IntToPtr) CONSTANT_OWNERSHIP_BUILTIN(Any, LShr) +CONSTANT_OWNERSHIP_BUILTIN(Any, GenericLShr) CONSTANT_OWNERSHIP_BUILTIN(Any, Mul) +CONSTANT_OWNERSHIP_BUILTIN(Any, GenericMul) CONSTANT_OWNERSHIP_BUILTIN(Any, Or) +CONSTANT_OWNERSHIP_BUILTIN(Any, GenericOr) CONSTANT_OWNERSHIP_BUILTIN(Any, PtrToInt) CONSTANT_OWNERSHIP_BUILTIN(Any, SAddOver) CONSTANT_OWNERSHIP_BUILTIN(Any, SDiv) +CONSTANT_OWNERSHIP_BUILTIN(Any, GenericSDiv) CONSTANT_OWNERSHIP_BUILTIN(Any, SExt) CONSTANT_OWNERSHIP_BUILTIN(Any, SExtOrBitCast) CONSTANT_OWNERSHIP_BUILTIN(Any, SIToFP) CONSTANT_OWNERSHIP_BUILTIN(Any, SMulOver) CONSTANT_OWNERSHIP_BUILTIN(Any, SRem) +CONSTANT_OWNERSHIP_BUILTIN(Any, GenericSRem) CONSTANT_OWNERSHIP_BUILTIN(Any, SSubOver) +CONSTANT_OWNERSHIP_BUILTIN(Any, Expect) CONSTANT_OWNERSHIP_BUILTIN(Any, Shl) +CONSTANT_OWNERSHIP_BUILTIN(Any, GenericShl) CONSTANT_OWNERSHIP_BUILTIN(Any, Sub) +CONSTANT_OWNERSHIP_BUILTIN(Any, GenericSub) CONSTANT_OWNERSHIP_BUILTIN(Any, Trunc) CONSTANT_OWNERSHIP_BUILTIN(Any, TruncOrBitCast) CONSTANT_OWNERSHIP_BUILTIN(Any, UAddOver) CONSTANT_OWNERSHIP_BUILTIN(Any, UDiv) +CONSTANT_OWNERSHIP_BUILTIN(Any, GenericUDiv) CONSTANT_OWNERSHIP_BUILTIN(Any, UIToFP) CONSTANT_OWNERSHIP_BUILTIN(Any, UMulOver) CONSTANT_OWNERSHIP_BUILTIN(Any, URem) +CONSTANT_OWNERSHIP_BUILTIN(Any, GenericURem) CONSTANT_OWNERSHIP_BUILTIN(Any, USubOver) CONSTANT_OWNERSHIP_BUILTIN(Any, Xor) +CONSTANT_OWNERSHIP_BUILTIN(Any, GenericXor) CONSTANT_OWNERSHIP_BUILTIN(Any, ZExt) CONSTANT_OWNERSHIP_BUILTIN(Any, ZExtOrBitCast) CONSTANT_OWNERSHIP_BUILTIN(Any, FCMP_ORD) diff --git a/lib/SILGen/SILGen.cpp b/lib/SILGen/SILGen.cpp index 48bc555fb36f5..bfc831c0376de 100644 --- a/lib/SILGen/SILGen.cpp +++ b/lib/SILGen/SILGen.cpp @@ -25,6 +25,7 @@ #include "swift/AST/PropertyWrappers.h" #include "swift/AST/ProtocolConformance.h" #include "swift/AST/ResilienceExpansion.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/TypeCheckRequests.h" #include "swift/Basic/Statistic.h" #include "swift/Basic/Timer.h" diff --git a/lib/SILGen/SILGenApply.cpp b/lib/SILGen/SILGenApply.cpp index f3930475d215f..f959d492c5e01 100644 --- a/lib/SILGen/SILGenApply.cpp +++ b/lib/SILGen/SILGenApply.cpp @@ -1111,7 +1111,7 @@ class SILGenApply : public Lowering::ExprVisitor { .asForeign(!isConstructorWithGeneratedAllocatorThunk(e->getDecl()) && requiresForeignEntryPoint(e->getDecl())); - auto captureInfo = SGF.SGM.Types.getLoweredLocalCaptures(afd); + auto captureInfo = SGF.SGM.Types.getLoweredLocalCaptures(constant); if (afd->getDeclContext()->isLocalContext() && !captureInfo.hasGenericParamCaptures()) subs = SubstitutionMap(); @@ -1142,7 +1142,8 @@ class SILGenApply : public Lowering::ExprVisitor { // If the decl ref requires captures, emit the capture params. if (!captureInfo.getCaptures().empty()) { SmallVector captures; - SGF.emitCaptures(e, afd, CaptureEmission::ImmediateApplication, + SGF.emitCaptures(e, SILDeclRef(afd), + CaptureEmission::ImmediateApplication, captures); applyCallee->setCaptures(std::move(captures)); } @@ -1163,17 +1164,18 @@ class SILGenApply : public Lowering::ExprVisitor { // really producing a closure object. SILDeclRef constant(e); + auto captureInfo = SGF.SGM.M.Types.getLoweredLocalCaptures(constant); + SubstitutionMap subs; - if (e->getCaptureInfo().hasGenericParamCaptures()) + if (captureInfo.hasGenericParamCaptures()) subs = SGF.getForwardingSubstitutionMap(); setCallee(Callee::forDirect(SGF, constant, subs, e)); // If the closure requires captures, emit them. - bool hasCaptures = SGF.SGM.M.Types.hasLoweredLocalCaptures(e); - if (hasCaptures) { + if (!captureInfo.getCaptures().empty()) { SmallVector captures; - SGF.emitCaptures(e, e, CaptureEmission::ImmediateApplication, + SGF.emitCaptures(e, constant, CaptureEmission::ImmediateApplication, captures); applyCallee->setCaptures(std::move(captures)); } @@ -4038,6 +4040,26 @@ CallEmission::applySpecializedEmitter(SpecializedEmitter &specializedEmitter, return firstLevelResult; } + Optional resultPlan; + Optional argScope; + Optional calleeTypeInfo; + SILLocation loc = uncurriedSites[0].Loc; + SILFunctionConventions substConv(substFnType, SGF.SGM.M); + + // If we have a named builtin and have an indirect out parameter, compute a + // result plan/arg scope before we prepare arguments. + if (!specializedEmitter.isLateEmitter() && + substConv.hasIndirectSILResults()) { + calleeTypeInfo.emplace(callee.getTypeInfo(SGF, false /*isCurried*/)); + + calleeTypeInfo->origResultType = origFormalType.getFunctionResultType(); + calleeTypeInfo->substResultType = callee.getSubstFormalType().getResult(); + + resultPlan.emplace(ResultPlanBuilder::computeResultPlan( + SGF, *calleeTypeInfo, loc, uncurriedContext)); + argScope.emplace(SGF, loc); + } + // Emit the arguments. SmallVector uncurriedArgs; Optional uncurriedLoc; @@ -4047,36 +4069,64 @@ CallEmission::applySpecializedEmitter(SpecializedEmitter &specializedEmitter, firstLevelResult.foreignSelf, uncurriedArgs, uncurriedLoc, formalApplyType); - // If we have a late emitter, just delegate to that emitter and return. + // If we have a late emitter, now that we have emitted our arguments, call the + // emitter. if (specializedEmitter.isLateEmitter()) { auto emitter = specializedEmitter.getLateEmitter(); - ManagedValue mv = emitter(SGF, *uncurriedLoc, - callee.getSubstitutions(), + ManagedValue mv = emitter(SGF, loc, callee.getSubstitutions(), uncurriedArgs, uncurriedContext); - firstLevelResult.value = - RValue(SGF, *uncurriedLoc, formalApplyType.getResult(), mv); + firstLevelResult.value = RValue(SGF, loc, formalApplyType.getResult(), mv); return firstLevelResult; } - // Named Builtins. + // Otherwise, we must have a named builtin. assert(specializedEmitter.isNamedBuiltin()); auto builtinName = specializedEmitter.getBuiltinName(); - SmallVector consumedArgs; + + // Prepare our raw args. + SmallVector rawArgs; + + // First get the indirect result addrs and add them to rawArgs. We want to be + // able to handle them specially later as well, so we keep them in two arrays. + if (resultPlan.hasValue()) + (*resultPlan)->gatherIndirectResultAddrs(SGF, loc, rawArgs); + + // Then add all arguments to our array, copying them if they are not at +1 + // yet. for (auto arg : uncurriedArgs) { // Named builtins are by default assumed to take all arguments at +1 i.e., // as Owned or Trivial. Named builtins that don't follow this convention // must use a specialized emitter. - auto maybePlusOne = arg.ensurePlusOne(SGF, uncurriedLoc.getValue()); - consumedArgs.push_back(maybePlusOne.forward(SGF)); + auto maybePlusOne = arg.ensurePlusOne(SGF, loc); + rawArgs.push_back(maybePlusOne.forward(SGF)); + } + + SILValue rawResult = + SGF.B.createBuiltin(loc, builtinName, substConv.getSILResultType(), + callee.getSubstitutions(), rawArgs); + + if (argScope.hasValue()) + std::move(argScope)->pop(); + + // If we have a direct result, it will consist of a single value even if + // formally we have multiple values. We could handle this better today by + // using multiple return values instead of a tuple. + SmallVector directResultsArray; + if (!substConv.hasIndirectSILResults()) { + directResultsArray.push_back(SGF.emitManagedRValueWithCleanup(rawResult)); + } + + ArrayRef directResultsFinal(directResultsArray); + + // Then finish our value. + if (resultPlan.hasValue()) { + firstLevelResult.value = + std::move(*resultPlan) + ->finish(SGF, loc, formalApplyType.getResult(), directResultsFinal); + } else { + firstLevelResult.value = RValue( + SGF, *uncurriedLoc, formalApplyType.getResult(), directResultsFinal[0]); } - SILFunctionConventions substConv(substFnType, SGF.SGM.M); - auto resultVal = SGF.B.createBuiltin(uncurriedLoc.getValue(), builtinName, - substConv.getSILResultType(), - callee.getSubstitutions(), - consumedArgs); - firstLevelResult.value = - RValue(SGF, *uncurriedLoc, formalApplyType.getResult(), - SGF.emitManagedRValueWithCleanup(resultVal)); return firstLevelResult; } @@ -5197,7 +5247,7 @@ static Callee getBaseAccessorFunctionRef(SILGenFunction &SGF, // The accessor might be a local function that does not capture any // generic parameters, in which case we don't want to pass in any // substitutions. - auto captureInfo = SGF.SGM.Types.getLoweredLocalCaptures(decl); + auto captureInfo = SGF.SGM.Types.getLoweredLocalCaptures(constant); if (decl->getDeclContext()->isLocalContext() && !captureInfo.hasGenericParamCaptures()) { subs = SubstitutionMap(); @@ -5259,11 +5309,10 @@ emitSpecializedAccessorFunctionRef(SILGenFunction &SGF, substitutions, isOnSelfParameter); // Collect captures if the accessor has them. - auto accessorFn = cast(constant.getDecl()); - if (SGF.SGM.M.Types.hasLoweredLocalCaptures(accessorFn)) { + if (SGF.SGM.M.Types.hasLoweredLocalCaptures(constant)) { assert(!selfValue && "local property has self param?!"); SmallVector captures; - SGF.emitCaptures(loc, accessorFn, CaptureEmission::ImmediateApplication, + SGF.emitCaptures(loc, constant, CaptureEmission::ImmediateApplication, captures); callee.setCaptures(std::move(captures)); } diff --git a/lib/SILGen/SILGenBuiltin.cpp b/lib/SILGen/SILGenBuiltin.cpp index 964f69089a79c..ec535bb664da2 100644 --- a/lib/SILGen/SILGenBuiltin.cpp +++ b/lib/SILGen/SILGenBuiltin.cpp @@ -22,6 +22,7 @@ #include "swift/AST/ASTContext.h" #include "swift/AST/Builtins.h" #include "swift/AST/DiagnosticsSIL.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/GenericEnvironment.h" #include "swift/AST/Module.h" #include "swift/AST/ReferenceCounting.h" diff --git a/lib/SILGen/SILGenConstructor.cpp b/lib/SILGen/SILGenConstructor.cpp index cebc6627e6c28..a9cbe49fb156f 100644 --- a/lib/SILGen/SILGenConstructor.cpp +++ b/lib/SILGen/SILGenConstructor.cpp @@ -288,7 +288,8 @@ void SILGenFunction::emitValueConstructor(ConstructorDecl *ctor) { emitProlog(ctor->getParameters(), /*selfParam=*/nullptr, ctor->getResultInterfaceType(), ctor, - ctor->hasThrows()); + ctor->hasThrows(), + ctor->getThrowsLoc()); emitConstructorMetatypeArg(*this, ctor); // Create a basic block to jump to for the implicit 'self' return. @@ -638,7 +639,7 @@ void SILGenFunction::emitClassConstructorInitializer(ConstructorDecl *ctor) { // FIXME: Handle self along with the other body patterns. uint16_t ArgNo = emitProlog(ctor->getParameters(), /*selfParam=*/nullptr, TupleType::getEmpty(F.getASTContext()), ctor, - ctor->hasThrows()); + ctor->hasThrows(), ctor->getThrowsLoc()); SILType selfTy = getLoweredLoadableType(selfDecl->getType()); ManagedValue selfArg = B.createInputFunctionArgument(selfTy, selfDecl); diff --git a/lib/SILGen/SILGenExpr.cpp b/lib/SILGen/SILGenExpr.cpp index d78225732369c..620360bbb9249 100644 --- a/lib/SILGen/SILGenExpr.cpp +++ b/lib/SILGen/SILGenExpr.cpp @@ -1549,8 +1549,7 @@ ManagedValue emitCFunctionPointer(SILGenFunction &SGF, SILConstantInfo constantInfo = SGF.getConstantInfo(constant); // C function pointers cannot capture anything from their context. - auto captures = SGF.SGM.Types.getLoweredLocalCaptures( - *constant.getAnyFunctionRef()); + auto captures = SGF.SGM.Types.getLoweredLocalCaptures(constant); if (captures.hasGenericParamCaptures() || captures.hasDynamicSelfCapture() || @@ -2198,9 +2197,6 @@ SILGenFunction::emitApplyOfDefaultArgGenerator(SILLocation loc, SILDeclRef generator = SILDeclRef::getDefaultArgGenerator(defaultArgsOwner.getDecl(), destIndex); - - // TODO: Should apply the default arg generator's captures, but Sema doesn't - // track them. auto fnRef = ManagedValue::forUnmanaged(emitGlobalFunctionRef(loc,generator)); auto fnType = fnRef.getType().castTo(); @@ -2215,8 +2211,13 @@ SILGenFunction::emitApplyOfDefaultArgGenerator(SILLocation loc, ResultPlanPtr resultPtr = ResultPlanBuilder::computeResultPlan(*this, calleeTypeInfo, loc, C); ArgumentScope argScope(*this, loc); + + SmallVector captures; + emitCaptures(loc, generator, CaptureEmission::ImmediateApplication, + captures); + return emitApply(std::move(resultPtr), std::move(argScope), loc, fnRef, - subs, {}, calleeTypeInfo, ApplyOptions::None, C); + subs, captures, calleeTypeInfo, ApplyOptions::None, C); } RValue SILGenFunction::emitApplyOfStoredPropertyInitializer( diff --git a/lib/SILGen/SILGenFunction.cpp b/lib/SILGen/SILGenFunction.cpp index 015aefa47928f..65bed08759832 100644 --- a/lib/SILGen/SILGenFunction.cpp +++ b/lib/SILGen/SILGenFunction.cpp @@ -20,6 +20,7 @@ #include "SILGenFunctionBuilder.h" #include "Scope.h" #include "swift/AST/ClangModuleLoader.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/Initializer.h" #include "swift/AST/PropertyWrappers.h" #include "swift/SIL/SILArgument.h" @@ -168,7 +169,7 @@ SILGenFunction::emitSiblingMethodRef(SILLocation loc, } void SILGenFunction::emitCaptures(SILLocation loc, - AnyFunctionRef closure, + SILDeclRef closure, CaptureEmission purpose, SmallVectorImpl &capturedArgs) { auto captureInfo = SGM.Types.getLoweredLocalCaptures(closure); @@ -229,8 +230,21 @@ void SILGenFunction::emitCaptures(SILLocation loc, if (found == VarLocs.end()) { auto &Diags = getASTContext().Diags; - Diags.diagnose(closure.getLoc(), - closure.isDeferBody() + SourceLoc loc; + bool isDeferBody; + if (closure.kind == SILDeclRef::Kind::DefaultArgGenerator) { + auto *param = getParameterAt(closure.getDecl(), + closure.defaultArgIndex); + loc = param->getLoc(); + isDeferBody = false; + } else { + auto f = *closure.getAnyFunctionRef(); + loc = f.getLoc(); + isDeferBody = f.isDeferBody(); + } + + Diags.diagnose(loc, + isDeferBody ? diag::capture_before_declaration_defer : diag::capture_before_declaration, vd->getBaseName().getIdentifier()); @@ -359,10 +373,7 @@ ManagedValue SILGenFunction::emitClosureValue(SILLocation loc, SILDeclRef constant, CanType expectedType, SubstitutionMap subs) { - auto closure = *constant.getAnyFunctionRef(); - auto captureInfo = closure.getCaptureInfo(); - auto loweredCaptureInfo = SGM.Types.getLoweredLocalCaptures(closure); - auto hasCaptures = SGM.Types.hasLoweredLocalCaptures(closure); + auto loweredCaptureInfo = SGM.Types.getLoweredLocalCaptures(constant); auto constantInfo = getConstantInfo(constant); SILValue functionRef = emitGlobalFunctionRef(loc, constant, constantInfo); @@ -371,6 +382,7 @@ SILGenFunction::emitClosureValue(SILLocation loc, SILDeclRef constant, // Apply substitutions. auto pft = constantInfo.SILFnType; + auto closure = *constant.getAnyFunctionRef(); auto *dc = closure.getAsDeclContext()->getParent(); if (dc->isLocalContext() && !loweredCaptureInfo.hasGenericParamCaptures()) { // If the lowered function type is not polymorphic but we were given @@ -395,11 +407,12 @@ SILGenFunction::emitClosureValue(SILLocation loc, SILDeclRef constant, // globals, but we still need to mark them as escaping so that DI can flag // uninitialized uses. if (this == SGM.TopLevelSGF) { + auto captureInfo = closure.getCaptureInfo(); SGM.emitMarkFunctionEscapeForTopLevelCodeGlobals( loc, captureInfo); } - if (!hasCaptures && !wasSpecialized) { + if (loweredCaptureInfo.getCaptures().empty() && !wasSpecialized) { auto result = ManagedValue::forUnmanaged(functionRef); return emitOrigToSubstValue(loc, result, AbstractionPattern(expectedType), @@ -407,7 +420,7 @@ SILGenFunction::emitClosureValue(SILLocation loc, SILDeclRef constant, } SmallVector capturedArgs; - emitCaptures(loc, closure, CaptureEmission::PartialApplication, + emitCaptures(loc, constant, CaptureEmission::PartialApplication, capturedArgs); // The partial application takes ownership of the context parameters. @@ -439,8 +452,9 @@ SILGenFunction::emitClosureValue(SILLocation loc, SILDeclRef constant, void SILGenFunction::emitFunction(FuncDecl *fd) { MagicFunctionName = SILGenModule::getMagicFunctionName(fd); - emitProlog(fd, fd->getParameters(), fd->getImplicitSelfDecl(), - fd->getResultInterfaceType(), fd->hasThrows()); + auto captureInfo = SGM.M.Types.getLoweredLocalCaptures(SILDeclRef(fd)); + emitProlog(captureInfo, fd->getParameters(), fd->getImplicitSelfDecl(), fd, + fd->getResultInterfaceType(), fd->hasThrows(), fd->getThrowsLoc()); Type resultTy = fd->mapTypeIntoContext(fd->getResultInterfaceType()); prepareEpilog(resultTy, fd->hasThrows(), CleanupLocation(fd)); @@ -456,8 +470,10 @@ void SILGenFunction::emitClosure(AbstractClosureExpr *ace) { MagicFunctionName = SILGenModule::getMagicFunctionName(ace); auto resultIfaceTy = ace->getResultType()->mapTypeOutOfContext(); - emitProlog(ace, ace->getParameters(), /*selfParam=*/nullptr, - resultIfaceTy, ace->isBodyThrowing()); + auto captureInfo = SGM.M.Types.getLoweredLocalCaptures( + SILDeclRef(ace)); + emitProlog(captureInfo, ace->getParameters(), /*selfParam=*/nullptr, + ace, resultIfaceTy, ace->isBodyThrowing(), ace->getLoc()); prepareEpilog(ace->getResultType(), ace->isBodyThrowing(), CleanupLocation(ace)); emitProfilerIncrement(ace); @@ -668,10 +684,13 @@ void SILGenFunction::emitGeneratorFunction(SILDeclRef function, Expr *value, } } + CaptureInfo captureInfo; + if (function.getAnyFunctionRef()) + captureInfo = SGM.M.Types.getLoweredLocalCaptures(function); auto *dc = function.getDecl()->getInnermostDeclContext(); auto interfaceType = value->getType()->mapTypeOutOfContext(); - emitProlog(/*paramList=*/nullptr, /*selfParam=*/nullptr, interfaceType, - dc, false); + emitProlog(captureInfo, /*paramList=*/nullptr, /*selfParam=*/nullptr, + dc, interfaceType, /*throws=*/false, SourceLoc()); if (EmitProfilerIncrement) emitProfilerIncrement(value); prepareEpilog(value->getType(), false, CleanupLocation::get(Loc)); @@ -701,7 +720,7 @@ void SILGenFunction::emitGeneratorFunction(SILDeclRef function, VarDecl *var) { } emitProlog(/*paramList*/ nullptr, /*selfParam*/ nullptr, interfaceType, dc, - false); + /*throws=*/false, SourceLoc()); prepareEpilog(varType, false, CleanupLocation::get(loc)); auto pbd = var->getParentPatternBinding(); diff --git a/lib/SILGen/SILGenFunction.h b/lib/SILGen/SILGenFunction.h index a52e09069a4fc..26e036368f4b3 100644 --- a/lib/SILGen/SILGenFunction.h +++ b/lib/SILGen/SILGenFunction.h @@ -770,12 +770,14 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction /// emitProlog - Generates prolog code to allocate and clean up mutable /// storage for closure captures and local arguments. - void emitProlog(AnyFunctionRef TheClosure, + void emitProlog(const CaptureInfo &captureInfo, ParameterList *paramList, ParamDecl *selfParam, - Type resultType, bool throws); + DeclContext *DC, Type resultType, + bool throws, SourceLoc throwsLoc); /// returns the number of variables in paramPatterns. uint16_t emitProlog(ParameterList *paramList, ParamDecl *selfParam, - Type resultType, DeclContext *DeclCtx, bool throws); + Type resultType, DeclContext *DC, + bool throws, SourceLoc throwsLoc); /// Create SILArguments in the entry block that bind a single value /// of the given parameter suitably for being forwarded. @@ -1211,7 +1213,7 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction bool isBaseGuaranteed = false); void emitCaptures(SILLocation loc, - AnyFunctionRef TheClosure, + SILDeclRef closure, CaptureEmission purpose, SmallVectorImpl &captures); diff --git a/lib/SILGen/SILGenLValue.cpp b/lib/SILGen/SILGenLValue.cpp index 6cdec0efc1cc4..5849093e0314b 100644 --- a/lib/SILGen/SILGenLValue.cpp +++ b/lib/SILGen/SILGenLValue.cpp @@ -1384,7 +1384,9 @@ namespace { VarDecl *field = dyn_cast(Storage); VarDecl *backingVar = field->getPropertyWrapperBackingProperty(); assert(backingVar); - CanType ValType = backingVar->getType()->getCanonicalType(); + CanType ValType = + SGF.F.mapTypeIntoContext(backingVar->getInterfaceType()) + ->getCanonicalType(); SILType varStorageType = SGF.SGM.Types.getSubstitutedStorageType(backingVar, ValType); auto typeData = @@ -1407,7 +1409,7 @@ namespace { assert(field->getAttachedPropertyWrappers().size() == 1); auto wrapperInfo = field->getAttachedPropertyWrapperTypeInfo(0); auto ctor = wrapperInfo.wrappedValueInit; - SubstitutionMap subs = backingVar->getType()->getMemberSubstitutionMap( + SubstitutionMap subs = ValType->getMemberSubstitutionMap( SGF.getModule().getSwiftModule(), ctor); Type ity = ctor->getInterfaceType(); @@ -1418,8 +1420,8 @@ namespace { .asForeign(requiresForeignEntryPoint(ctor)); RValue initFuncRV = SGF.emitApplyPropertyWrapperAllocator(loc, subs,initRef, - backingVar->getType(), - CanAnyFunctionType(substIty)); + ValType, + CanAnyFunctionType(substIty)); ManagedValue initFn = std::move(initFuncRV).getAsSingleValue(SGF, loc); // Create the allocating setter function. It captures the base address. diff --git a/lib/SILGen/SILGenProlog.cpp b/lib/SILGen/SILGenProlog.cpp index bc9be3f02f5db..656ad9cdbf33c 100644 --- a/lib/SILGen/SILGenProlog.cpp +++ b/lib/SILGen/SILGenProlog.cpp @@ -338,7 +338,7 @@ void SILGenFunction::bindParametersForForwarding(const ParameterList *params, } static void emitCaptureArguments(SILGenFunction &SGF, - AnyFunctionRef closure, + GenericSignature *origGenericSig, CapturedValue capture, uint16_t ArgNo) { @@ -349,9 +349,9 @@ static void emitCaptureArguments(SILGenFunction &SGF, // Local function to get the captured variable type within the capturing // context. auto getVarTypeInCaptureContext = [&]() -> Type { - auto interfaceType = VD->getInterfaceType(); - return GenericEnvironment::mapTypeIntoContext( - closure.getGenericEnvironment(), interfaceType); + auto interfaceType = VD->getInterfaceType()->getCanonicalType( + origGenericSig); + return SGF.F.mapTypeIntoContext(interfaceType); }; auto expansion = SGF.F.getResilienceExpansion(); @@ -420,12 +420,15 @@ static void emitCaptureArguments(SILGenFunction &SGF, } } -void SILGenFunction::emitProlog(AnyFunctionRef TheClosure, +void SILGenFunction::emitProlog(const CaptureInfo &captureInfo, ParameterList *paramList, ParamDecl *selfParam, - Type resultType, bool throws) { + DeclContext *DC, + Type resultType, + bool throws, + SourceLoc throwsLoc) { uint16_t ArgNo = emitProlog(paramList, selfParam, resultType, - TheClosure.getAsDeclContext(), throws); + DC, throws, throwsLoc); // Emit an unreachable instruction if a parameter type is // uninhabited @@ -442,7 +445,6 @@ void SILGenFunction::emitProlog(AnyFunctionRef TheClosure, // Emit the capture argument variables. These are placed last because they // become the first curry level of the SIL function. - auto captureInfo = SGM.Types.getLoweredLocalCaptures(TheClosure); for (auto capture : captureInfo.getCaptures()) { if (capture.isDynamicSelfMetadata()) { auto selfMetatype = MetatypeType::get( @@ -457,8 +459,7 @@ void SILGenFunction::emitProlog(AnyFunctionRef TheClosure, if (capture.isOpaqueValue()) { OpaqueValueExpr *opaqueValue = capture.getOpaqueValue(); Type type = opaqueValue->getType()->mapTypeOutOfContext(); - type = GenericEnvironment::mapTypeIntoContext( - TheClosure.getGenericEnvironment(), type); + type = F.mapTypeIntoContext(type); auto &lowering = getTypeLowering(type); SILType ty = lowering.getLoweredType(); SILValue val = F.begin()->createFunctionArgument(ty); @@ -471,7 +472,8 @@ void SILGenFunction::emitProlog(AnyFunctionRef TheClosure, continue; } - emitCaptureArguments(*this, TheClosure, capture, ++ArgNo); + emitCaptureArguments(*this, DC->getGenericSignatureOfContext(), + capture, ++ArgNo); } } @@ -512,7 +514,8 @@ uint16_t SILGenFunction::emitProlog(ParameterList *paramList, ParamDecl *selfParam, Type resultType, DeclContext *DC, - bool throws) { + bool throws, + SourceLoc throwsLoc) { // Create the indirect result parameters. auto *genericSig = DC->getGenericSignatureOfContext(); resultType = resultType->getCanonicalType(genericSig); @@ -533,15 +536,13 @@ uint16_t SILGenFunction::emitProlog(ParameterList *paramList, // Record the ArgNo of the artificial $error inout argument. unsigned ArgNo = emitter.getNumArgs(); if (throws) { - RegularLocation Loc = RegularLocation::getAutoGeneratedLocation(); - if (auto *AFD = dyn_cast(DC)) - Loc = AFD->getThrowsLoc(); - else if (auto *ACE = dyn_cast(DC)) - Loc = ACE->getLoc(); - auto NativeErrorTy = SILType::getExceptionType(getASTContext()); + auto NativeErrorTy = SILType::getExceptionType(getASTContext()); ManagedValue Undef = emitUndef(NativeErrorTy); SILDebugVariable DbgVar("$error", /*Constant*/ false, ++ArgNo); - B.createDebugValue(Loc, Undef.getValue(), DbgVar); + RegularLocation loc = RegularLocation::getAutoGeneratedLocation(); + if (throwsLoc.isValid()) + loc = throwsLoc; + B.createDebugValue(loc, Undef.getValue(), DbgVar); } return ArgNo; diff --git a/lib/SILGen/SILGenThunk.cpp b/lib/SILGen/SILGenThunk.cpp index a5d53d8f5248a..6cb747a4e79ff 100644 --- a/lib/SILGen/SILGenThunk.cpp +++ b/lib/SILGen/SILGenThunk.cpp @@ -26,6 +26,7 @@ #include "Scope.h" #include "swift/AST/ASTMangler.h" #include "swift/AST/DiagnosticsSIL.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/GenericEnvironment.h" #include "swift/SIL/PrettyStackTrace.h" #include "swift/SIL/SILArgument.h" @@ -236,7 +237,7 @@ void SILGenFunction::emitCurryThunk(SILDeclRef thunk) { auto *vd = thunk.getDecl(); if (auto *fd = dyn_cast(vd)) { - assert(!SGM.M.Types.hasLoweredLocalCaptures(fd) && + assert(!SGM.M.Types.hasLoweredLocalCaptures(SILDeclRef(fd)) && "methods cannot have captures"); (void) fd; } diff --git a/lib/SILGen/SILGenType.cpp b/lib/SILGen/SILGenType.cpp index ce6659e23a229..5ffd428d02bea 100644 --- a/lib/SILGen/SILGenType.cpp +++ b/lib/SILGen/SILGenType.cpp @@ -25,6 +25,7 @@ #include "swift/AST/GenericEnvironment.h" #include "swift/AST/ProtocolConformance.h" #include "swift/AST/PrettyStackTrace.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/SubstitutionMap.h" #include "swift/AST/TypeMemberVisitor.h" #include "swift/SIL/FormalLinkage.h" diff --git a/lib/SILOptimizer/Analysis/DestructorAnalysis.cpp b/lib/SILOptimizer/Analysis/DestructorAnalysis.cpp index d5b9e43fdb50f..73705b794edcf 100644 --- a/lib/SILOptimizer/Analysis/DestructorAnalysis.cpp +++ b/lib/SILOptimizer/Analysis/DestructorAnalysis.cpp @@ -74,11 +74,6 @@ bool DestructorAnalysis::isSafeType(CanType Ty) { // Check the stored properties. for (auto SP : Struct->getStoredProperties()) { - // FIXME: Remove this once getInterfaceType() is a request. - if (!SP->hasInterfaceType()) { - ASTContext &Ctx = Mod->getSwiftModule()->getASTContext(); - Ctx.getLazyResolver()->resolveDeclSignature(SP); - } if (!isSafeType(SP->getInterfaceType()->getCanonicalType())) return cacheResult(Ty, false); } diff --git a/lib/SILOptimizer/Mandatory/DataflowDiagnostics.cpp b/lib/SILOptimizer/Mandatory/DataflowDiagnostics.cpp index 7098b0195276e..d459043eff3d8 100644 --- a/lib/SILOptimizer/Mandatory/DataflowDiagnostics.cpp +++ b/lib/SILOptimizer/Mandatory/DataflowDiagnostics.cpp @@ -10,21 +10,22 @@ // //===----------------------------------------------------------------------===// -#include "swift/SILOptimizer/PassManager/Passes.h" -#include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/ConstExpr.h" #include "swift/AST/ASTContext.h" #include "swift/AST/DiagnosticEngine.h" -#include "swift/AST/DiagnosticsSema.h" #include "swift/AST/DiagnosticsSIL.h" +#include "swift/AST/DiagnosticsSema.h" #include "swift/AST/Expr.h" #include "swift/AST/Stmt.h" +#include "swift/SIL/InstructionUtils.h" +#include "swift/SIL/SILConstants.h" #include "swift/SIL/SILFunction.h" #include "swift/SIL/SILInstruction.h" #include "swift/SIL/SILLocation.h" #include "swift/SIL/SILModule.h" #include "swift/SIL/SILVisitor.h" -#include "swift/SIL/SILConstants.h" +#include "swift/SILOptimizer/PassManager/Passes.h" +#include "swift/SILOptimizer/PassManager/Transforms.h" +#include "swift/SILOptimizer/Utils/ConstExpr.h" using namespace swift; @@ -175,6 +176,67 @@ static void diagnosePoundAssert(const SILInstruction *I, } } +static void diagnoseUnspecializedPolymorphicBuiltins(SILInstruction *inst) { + // We only validate if we are in a non-transparent function. + if (inst->getFunction()->isTransparent()) + return; + + auto *bi = dyn_cast(inst); + if (!bi) + return; + + auto kind = bi->getBuiltinKind(); + if (!kind) + return; + + if (!isPolymorphicBuiltin(*kind)) + return; + + const auto &builtinInfo = bi->getBuiltinInfo(); + + // First that the parameters were acceptable so we can emit a nice error to + // guide the user. + for (SILValue value : bi->getOperandValues()) { + SILType type = value->getType(); + SourceLoc loc; + if (auto *inst = value->getDefiningInstruction()) { + loc = inst->getLoc().getSourceLoc(); + } else { + loc = bi->getLoc().getSourceLoc(); + } + + if (!type.is() || !type.isTrivial(*bi->getFunction())) { + diagnose(bi->getModule().getASTContext(), loc, + diag::polymorphic_builtin_passed_non_trivial_non_builtin_type, + type.getASTType()); + return; + } + } + + // Ok, we have a valid type for a polymorphic builtin. Make sure we actually + // have a static overload for this type. + PolymorphicBuiltinSpecializedOverloadInfo overloadInfo; + bool ableToMapToStaticOverload = overloadInfo.init(bi); + (void)ableToMapToStaticOverload; + assert(ableToMapToStaticOverload); + if (!overloadInfo.doesOverloadExist()) { + diagnose(bi->getModule().getASTContext(), bi->getLoc().getSourceLoc(), + diag::polymorphic_builtin_passed_type_without_static_overload, + overloadInfo.staticOverloadIdentifier, + getBuiltinName(builtinInfo.ID), + overloadInfo.argTypes.front().getASTType()); + return; + } + + // Otherwise, something happen that we did not understand. This can only + // happen if we specialize the generic type in the builtin /after/ constant + // propagation runs at -Onone but before dataflow diagnostics. This is an + // error in implementation, so we assert. + llvm_unreachable("Found generic builtin with known static overload that it " + "could be transformed to. Did this builtin get its generic " + "type specialized /after/ constant propagation?"); +} + namespace { class EmitDFDiagnostics : public SILFunctionTransform { ~EmitDFDiagnostics() override {} @@ -186,21 +248,25 @@ class EmitDFDiagnostics : public SILFunctionTransform { return; SILModule &M = getFunction()->getModule(); - for (auto &BB : *getFunction()) + for (auto &BB : *getFunction()) { for (auto &I : BB) { diagnoseUnreachable(&I, M.getASTContext()); diagnoseStaticReports(&I, M); + diagnoseUnspecializedPolymorphicBuiltins(&I); } + } if (M.getASTContext().LangOpts.EnableExperimentalStaticAssert) { SymbolicValueBumpAllocator allocator; - ConstExprEvaluator constantEvaluator(allocator); + ConstExprEvaluator constantEvaluator(allocator, + getOptions().AssertConfig); for (auto &BB : *getFunction()) for (auto &I : BB) diagnosePoundAssert(&I, M, constantEvaluator); } } }; + } // end anonymous namespace diff --git a/lib/SILOptimizer/Mandatory/DiagnoseStaticExclusivity.cpp b/lib/SILOptimizer/Mandatory/DiagnoseStaticExclusivity.cpp index 496cdf123ecde..f4f6247e4aad5 100644 --- a/lib/SILOptimizer/Mandatory/DiagnoseStaticExclusivity.cpp +++ b/lib/SILOptimizer/Mandatory/DiagnoseStaticExclusivity.cpp @@ -75,9 +75,9 @@ class RecordedAccess { union { BeginAccessInst *Inst; struct { - SILAccessKind ClosureAccessKind; - SILLocation ClosureAccessLoc; - }; + SILAccessKind AccessKind; + SILLocation AccessLoc; + } Closure; }; const IndexTrieNode *SubPath; @@ -89,7 +89,7 @@ class RecordedAccess { RecordedAccess(SILAccessKind ClosureAccessKind, SILLocation ClosureAccessLoc, const IndexTrieNode *SubPath) : RecordKind(RecordedAccessKind::NoescapeClosureCapture), - ClosureAccessKind(ClosureAccessKind), ClosureAccessLoc(ClosureAccessLoc), + Closure({ClosureAccessKind, ClosureAccessLoc}), SubPath(SubPath) { } RecordedAccessKind getRecordKind() const { @@ -106,7 +106,7 @@ class RecordedAccess { case RecordedAccessKind::BeginInstruction: return Inst->getAccessKind(); case RecordedAccessKind::NoescapeClosureCapture: - return ClosureAccessKind; + return Closure.AccessKind; }; llvm_unreachable("unhandled kind"); } @@ -116,7 +116,7 @@ class RecordedAccess { case RecordedAccessKind::BeginInstruction: return Inst->getLoc(); case RecordedAccessKind::NoescapeClosureCapture: - return ClosureAccessLoc; + return Closure.AccessLoc; }; llvm_unreachable("unhandled kind"); } diff --git a/lib/SILOptimizer/Mandatory/Differentiation.cpp b/lib/SILOptimizer/Mandatory/Differentiation.cpp index 73b9c89bd6215..d032bc90a6427 100644 --- a/lib/SILOptimizer/Mandatory/Differentiation.cpp +++ b/lib/SILOptimizer/Mandatory/Differentiation.cpp @@ -32,7 +32,7 @@ #include "swift/AST/Expr.h" #include "swift/AST/GenericEnvironment.h" #include "swift/AST/GenericSignatureBuilder.h" -#include "swift/AST/Module.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/ParameterList.h" #include "swift/AST/SubstitutionMap.h" #include "swift/AST/TypeCheckRequests.h" diff --git a/lib/SILOptimizer/Mandatory/MandatoryInlining.cpp b/lib/SILOptimizer/Mandatory/MandatoryInlining.cpp index de9993b97515a..d22c2c4caca0b 100644 --- a/lib/SILOptimizer/Mandatory/MandatoryInlining.cpp +++ b/lib/SILOptimizer/Mandatory/MandatoryInlining.cpp @@ -75,7 +75,7 @@ insertAfterApply(SILInstruction *applySite, /// apply site, or the callee value are control dependent in any way. This /// requires us to need to be very careful. See inline comments. static void fixupReferenceCounts( - PartialApplyInst *pai, SILInstruction *applySite, SILValue calleeValue, + PartialApplyInst *pai, FullApplySite applySite, SILValue calleeValue, ArrayRef captureArgConventions, MutableArrayRef capturedArgs, bool isCalleeGuaranteed) { @@ -108,7 +108,7 @@ static void fixupReferenceCounts( continue; } - auto *f = applySite->getFunction(); + auto *f = applySite.getFunction(); // See if we have a trivial value. In such a case, just continue. We do not // need to fix up anything. @@ -150,9 +150,10 @@ static void fixupReferenceCounts( // just cares about the block the value is in. In a forthcoming commit, I // am going to change this to use a different API on the linear lifetime // checker that makes this clearer. - auto error = - valueHasLinearLifetime(pai, {applySite}, {}, visitedBlocks, - deadEndBlocks, errorBehavior, &leakingBlocks); + LinearLifetimeChecker checker(visitedBlocks, deadEndBlocks); + auto error = checker.checkValue( + pai, {BranchPropagatedUser(applySite.getCalleeOperand())}, {}, + errorBehavior, &leakingBlocks); if (error.getFoundLeak()) { while (!leakingBlocks.empty()) { auto *leakingBlock = leakingBlocks.pop_back_val(); @@ -173,12 +174,13 @@ static void fixupReferenceCounts( // insert a destroy after the apply since the leak will just cover the // other path. if (!error.getFoundOverConsume()) { - insertAfterApply(applySite, [&](SILBasicBlock::iterator iter) { - if (hasOwnership) { - SILBuilderWithScope(iter).createEndBorrow(loc, argument); - } - SILBuilderWithScope(iter).emitDestroyValueOperation(loc, copy); - }); + insertAfterApply( + applySite.getInstruction(), [&](SILBasicBlock::iterator iter) { + if (hasOwnership) { + SILBuilderWithScope(iter).createEndBorrow(loc, argument); + } + SILBuilderWithScope(iter).emitDestroyValueOperation(loc, copy); + }); } v = argument; break; @@ -201,9 +203,9 @@ static void fixupReferenceCounts( // just cares about the block the value is in. In a forthcoming commit, I // am going to change this to use a different API on the linear lifetime // checker that makes this clearer. - auto error = - valueHasLinearLifetime(pai, {applySite}, {}, visitedBlocks, - deadEndBlocks, errorBehavior, &leakingBlocks); + LinearLifetimeChecker checker(visitedBlocks, deadEndBlocks); + auto error = checker.checkValue(pai, {applySite.getCalleeOperand()}, {}, + errorBehavior, &leakingBlocks); if (error.getFoundError()) { while (!leakingBlocks.empty()) { auto *leakingBlock = leakingBlocks.pop_back_val(); @@ -213,9 +215,10 @@ static void fixupReferenceCounts( } } - insertAfterApply(applySite, [&](SILBasicBlock::iterator iter) { - SILBuilderWithScope(iter).emitDestroyValueOperation(loc, v); - }); + insertAfterApply( + applySite.getInstruction(), [&](SILBasicBlock::iterator iter) { + SILBuilderWithScope(iter).emitDestroyValueOperation(loc, v); + }); break; } @@ -240,9 +243,9 @@ static void fixupReferenceCounts( // just cares about the block the value is in. In a forthcoming commit, I // am going to change this to use a different API on the linear lifetime // checker that makes this clearer. - auto error = - valueHasLinearLifetime(pai, {applySite}, {}, visitedBlocks, - deadEndBlocks, errorBehavior, &leakingBlocks); + LinearLifetimeChecker checker(visitedBlocks, deadEndBlocks); + auto error = checker.checkValue(pai, {applySite.getCalleeOperand()}, {}, + errorBehavior, &leakingBlocks); if (error.getFoundError()) { while (!leakingBlocks.empty()) { auto *leakingBlock = leakingBlocks.pop_back_val(); @@ -260,9 +263,10 @@ static void fixupReferenceCounts( // Destroy the callee as the apply would have done if our function is not // callee guaranteed. if (!isCalleeGuaranteed) { - insertAfterApply(applySite, [&](SILBasicBlock::iterator iter) { - SILBuilderWithScope(iter).emitDestroyValueOperation(loc, calleeValue); - }); + insertAfterApply( + applySite.getInstruction(), [&](SILBasicBlock::iterator iter) { + SILBuilderWithScope(iter).emitDestroyValueOperation(loc, calleeValue); + }); } } @@ -923,9 +927,8 @@ runOnFunctionRecursively(SILOptFunctionBuilder &FuncBuilder, // We need to insert the copies before the partial_apply since if we can // not remove the partial_apply the captured values will be dead by the // time we hit the call site. - fixupReferenceCounts(PAI, InnerAI.getInstruction(), CalleeValue, - CapturedArgConventions, CapturedArgs, - IsCalleeGuaranteed); + fixupReferenceCounts(PAI, InnerAI, CalleeValue, CapturedArgConventions, + CapturedArgs, IsCalleeGuaranteed); } // Register a callback to record potentially unused function values after diff --git a/lib/SILOptimizer/Mandatory/OSLogOptimization.cpp b/lib/SILOptimizer/Mandatory/OSLogOptimization.cpp index 481ccc7105f8e..09551d05779b2 100644 --- a/lib/SILOptimizer/Mandatory/OSLogOptimization.cpp +++ b/lib/SILOptimizer/Mandatory/OSLogOptimization.cpp @@ -186,9 +186,10 @@ class FoldState { SmallVector constantSILValues; public: - FoldState(SILFunction *fun, SILInstruction *beginInst, + FoldState(SILFunction *fun, unsigned assertConfig, SILInstruction *beginInst, ArrayRef endInsts) - : constantEvaluator(allocator, fun), beginInstruction(beginInst), + : constantEvaluator(allocator, fun, assertConfig), + beginInstruction(beginInst), endInstructions(endInsts.begin(), endInsts.end()) {} void addConstantSILValue(SILValue value) { @@ -249,7 +250,7 @@ static bool shouldAttemptEvaluation(SILInstruction *inst) { return false; return calleeFun->hasSemanticsAttrThatStartsWith("string.") || - calleeFun->hasSemanticsAttrThatStartsWith("oslog."); + calleeFun->hasSemanticsAttr("constant_evaluable"); } /// Skip or evaluate the given instruction based on the evaluation policy and @@ -627,13 +628,14 @@ static bool detectAndDiagnoseErrors(Optional errorInfo, /// Constant evaluate instructions starting from 'start' and fold the uses /// of the value 'oslogMessage'. Stop when oslogMessageValue is released. static void constantFold(SILInstruction *start, - SingleValueInstruction *oslogMessage) { + SingleValueInstruction *oslogMessage, + unsigned assertConfig) { // Initialize fold state. SmallVector lifetimeEndInsts; getLifetimeEndInstructionsOfSILValue(oslogMessage, lifetimeEndInsts); - FoldState state(start->getFunction(), start, lifetimeEndInsts); + FoldState state(start->getFunction(), assertConfig, start, lifetimeEndInsts); auto errorInfo = collectConstants(state); @@ -738,6 +740,7 @@ class OSLogOptimization : public SILFunctionTransform { /// The entry point to the transformation. void run() override { auto &fun = *getFunction(); + unsigned assertConfig = getOptions().AssertConfig; // Don't rerun optimization on deserialized functions or stdlib functions. if (fun.wasDeserializedCanonical()) { @@ -778,7 +781,7 @@ class OSLogOptimization : public SILFunctionTransform { continue; } - constantFold(interpolationStart, oslogInit); + constantFold(interpolationStart, oslogInit, assertConfig); } } }; diff --git a/lib/SILOptimizer/Mandatory/PredictableMemOpt.cpp b/lib/SILOptimizer/Mandatory/PredictableMemOpt.cpp index 1d0198392af22..df5a0c7142148 100644 --- a/lib/SILOptimizer/Mandatory/PredictableMemOpt.cpp +++ b/lib/SILOptimizer/Mandatory/PredictableMemOpt.cpp @@ -759,6 +759,10 @@ AvailableValueAggregator::addMissingDestroysForCopiedValues( if (!B.hasOwnership()) return svi; + assert((isa(svi) || isa(svi)) && + "Expected to have a /real/ load here since we assume that we have a " + "unary operand instruction"); + SmallPtrSet visitedBlocks; SmallVector leakingBlocks; bool foundLoop = false; @@ -780,9 +784,10 @@ AvailableValueAggregator::addMissingDestroysForCopiedValues( // Then perform the linear lifetime check. If we succeed, continue. We have // no further work to do. auto errorKind = ownership::ErrorBehaviorKind::ReturnFalse; - auto error = - valueHasLinearLifetime(cvi, {svi}, {}, visitedBlocks, deadEndBlocks, - errorKind, &leakingBlocks); + LinearLifetimeChecker checker(visitedBlocks, deadEndBlocks); + auto error = checker.checkValue( + cvi, {BranchPropagatedUser(&svi->getAllOperands()[0])}, {}, errorKind, + &leakingBlocks); if (!error.getFoundError()) continue; diff --git a/lib/SILOptimizer/Mandatory/SemanticARCOpts.cpp b/lib/SILOptimizer/Mandatory/SemanticARCOpts.cpp index 6b363b9bf44dd..3894db7761087 100644 --- a/lib/SILOptimizer/Mandatory/SemanticARCOpts.cpp +++ b/lib/SILOptimizer/Mandatory/SemanticARCOpts.cpp @@ -299,18 +299,6 @@ bool SemanticARCOptVisitor::visitBeginBorrowInst(BeginBorrowInst *bbi) { return true; } -static bool canHandleOperand(SILValue operand, SmallVectorImpl &out) { - if (!getUnderlyingBorrowIntroducers(operand, out)) - return false; - - /// TODO: Add support for begin_borrow, load_borrow. - auto canHandleValue = [](SILValue v) -> bool { - return isa(v) || isa(v) || - isa(v); - }; - return all_of(out, canHandleValue); -} - // Eliminate a copy of a borrowed value, if: // // 1. All of the copies users do not consume the copy (and thus can accept a @@ -344,11 +332,13 @@ static bool canHandleOperand(SILValue operand, SmallVectorImpl &out) { // // TODO: This needs a better name. bool SemanticARCOptVisitor::performGuaranteedCopyValueOptimization(CopyValueInst *cvi) { - SmallVector borrowIntroducers; + SmallVector borrowScopeIntroducers; - // Whitelist the operands that we know how to support and make sure - // our operand is actually guaranteed. - if (!canHandleOperand(cvi->getOperand(), borrowIntroducers)) + // Find all borrow introducers for our copy operand. If we are unable to find + // all of the reproducers (due to pattern matching failure), conservatively + // return false. We can not optimize. + if (!getUnderlyingBorrowIntroducingValues(cvi->getOperand(), + borrowScopeIntroducers)) return false; // Then go over all of our uses and see if the value returned by our copy @@ -361,10 +351,13 @@ bool SemanticARCOptVisitor::performGuaranteedCopyValueOptimization(CopyValueInst if (!isDeadLiveRange(cvi, destroys, &guaranteedForwardingInsts)) return false; - // Next check if we have any destroys at all of our copy_value and an operand - // that is not a function argument. Otherwise, due to the way we ignore dead - // end blocks, we may eliminate the copy_value, creating a use of the borrowed - // value after the end_borrow. + // Next check if we do not have any destroys of our copy_value and are + // processing a local borrow scope. In such a case, due to the way we ignore + // dead end blocks, we may eliminate the copy_value, creating a use of the + // borrowed value after the end_borrow. To avoid this, in such cases we + // bail. In contrast, a non-local borrow scope does not have any end scope + // instructions, implying we can avoid this hazard and still optimize in such + // a case. // // DISCUSSION: Consider the following SIL: // @@ -411,48 +404,35 @@ bool SemanticARCOptVisitor::performGuaranteedCopyValueOptimization(CopyValueInst // destroy_value /after/ the end_borrow we will not optimize here. This means // that this bug can only occur if the copy_value is only post-dominated by // dead end blocks that use the value in a non-consuming way. - if (destroys.empty() && llvm::any_of(borrowIntroducers, [](SILValue v) { - return !isa(v); - })) { + // + // TODO: There may be some way of sinking this into the loop below. + if (destroys.empty() && + llvm::any_of(borrowScopeIntroducers, + [](BorrowScopeIntroducingValue borrowScope) { + return borrowScope.isLocalScope(); + })) { return false; } - // If we reached this point, then we know that all of our users can - // accept a guaranteed value and our owned value is destroyed only - // by destroy_value. Check if all of our destroys are joint - // post-dominated by the end_borrow set. If they do not, then the - // copy_value is lifetime extending the guaranteed value, we can not - // eliminate it. + // If we reached this point, then we know that all of our users can accept a + // guaranteed value and our owned value is destroyed only by + // destroy_value. Check if all of our destroys are joint post-dominated by the + // our end borrow scope set. If they do not, then the copy_value is lifetime + // extending the guaranteed value, we can not eliminate it. { - SmallVector destroysForLinearLifetimeCheck( - destroys.begin(), destroys.end()); - SmallVector endBorrowInsts; + SmallVector destroysForLinearLifetimeCheck; + for (auto *dvi : destroys) { + destroysForLinearLifetimeCheck.push_back(&dvi->getAllOperands()[0]); + } + SmallVector scratchSpace; SmallPtrSet visitedBlocks; - for (SILValue v : borrowIntroducers) { - if (isa(v)) { - continue; - } - - SWIFT_DEFER { - endBorrowInsts.clear(); - visitedBlocks.clear(); - }; - - if (auto *lbi = dyn_cast(v)) { - llvm::copy(lbi->getEndBorrows(), std::back_inserter(endBorrowInsts)); - } else if (auto *bbi = dyn_cast(v)) { - llvm::copy(bbi->getEndBorrows(), std::back_inserter(endBorrowInsts)); - } else { - llvm_unreachable("Unhandled borrow introducer?!"); - } - - // Make sure that our destroys are properly nested within our end - // borrows. Otherwise, we can not optimize. - auto result = valueHasLinearLifetime( - v, endBorrowInsts, destroysForLinearLifetimeCheck, visitedBlocks, - getDeadEndBlocks(), ownership::ErrorBehaviorKind::ReturnFalse); - if (result.getFoundError()) - return false; + if (llvm::any_of(borrowScopeIntroducers, + [&](BorrowScopeIntroducingValue borrowScope) { + return !borrowScope.areInstructionsWithinScope( + destroysForLinearLifetimeCheck, scratchSpace, + visitedBlocks, getDeadEndBlocks()); + })) { + return false; } } @@ -681,24 +661,24 @@ class StorageGuaranteesLoadVisitor SmallVector baseEndBorrows; for (auto *use : borrowInst->getUses()) { if (isa(use->getUser())) { - baseEndBorrows.push_back(BranchPropagatedUser(use->getUser())); + baseEndBorrows.emplace_back(use); } } SmallVector valueDestroys; for (auto *use : Load->getUses()) { if (isa(use->getUser())) { - valueDestroys.push_back(BranchPropagatedUser(use->getUser())); + valueDestroys.emplace_back(use); } } SmallPtrSet visitedBlocks; - - auto result = valueHasLinearLifetime(baseObject, baseEndBorrows, - valueDestroys, visitedBlocks, - ARCOpt.getDeadEndBlocks(), - ownership::ErrorBehaviorKind::ReturnFalse); - return answer(result.getFoundError()); + + LinearLifetimeChecker checker(visitedBlocks, ARCOpt.getDeadEndBlocks()); + // Returns true on success. So we invert. + bool foundError = + !checker.validateLifetime(baseObject, baseEndBorrows, valueDestroys); + return answer(foundError); } // TODO: Handle other access kinds? diff --git a/lib/SILOptimizer/Transforms/AccessEnforcementReleaseSinking.cpp b/lib/SILOptimizer/Transforms/AccessEnforcementReleaseSinking.cpp index 05c33e6c05d0e..f28a9c32ff6cf 100644 --- a/lib/SILOptimizer/Transforms/AccessEnforcementReleaseSinking.cpp +++ b/lib/SILOptimizer/Transforms/AccessEnforcementReleaseSinking.cpp @@ -89,8 +89,7 @@ static bool isBarrier(SILInstruction *inst) { #define BUILTIN_CAST_OPERATION(Id, Name, Attrs) BUILTIN_NO_BARRIER(Id) #define BUILTIN_CAST_OR_BITCAST_OPERATION(Id, Name, Attrs) \ BUILTIN_NO_BARRIER(Id) -#define BUILTIN_BINARY_OPERATION(Id, Name, Attrs, Overload) \ - BUILTIN_NO_BARRIER(Id) +#define BUILTIN_BINARY_OPERATION(Id, Name, Attrs) BUILTIN_NO_BARRIER(Id) #define BUILTIN_BINARY_OPERATION_WITH_OVERFLOW(Id, Name, UncheckedID, Attrs, \ Overload) \ BUILTIN_NO_BARRIER(Id) @@ -105,6 +104,11 @@ static bool isBarrier(SILInstruction *inst) { case BuiltinValueKind::Id: \ return true; // A runtime call could be anything. +#define BUILTIN_SANITIZER_OPERATION(Id, Name, Attrs) BUILTIN_NO_BARRIER(Id) +#define BUILTIN_TYPE_CHECKER_OPERATION(Id, Name) BUILTIN_NO_BARRIER(Id) +#define BUILTIN_TYPE_TRAIT_OPERATION(Id, Name) BUILTIN_NO_BARRIER(Id) +#include "swift/AST/Builtins.def" + // Handle BUILTIN_MISC_OPERATIONs individually. case BuiltinValueKind::Sizeof: case BuiltinValueKind::Strideof: @@ -158,12 +162,6 @@ static bool isBarrier(SILInstruction *inst) { case BuiltinValueKind::UnsafeGuaranteed: case BuiltinValueKind::UnsafeGuaranteedEnd: return true; - -#define BUILTIN_SANITIZER_OPERATION(Id, Name, Attrs) BUILTIN_NO_BARRIER(Id) -#define BUILTIN_TYPE_CHECKER_OPERATION(Id, Name) BUILTIN_NO_BARRIER(Id) -#define BUILTIN_TYPE_TRAIT_OPERATION(Id, Name) BUILTIN_NO_BARRIER(Id) - -#include "swift/AST/Builtins.def" } } return false; diff --git a/lib/SILOptimizer/Transforms/SimplifyCFG.cpp b/lib/SILOptimizer/Transforms/SimplifyCFG.cpp index 06971c0f91f78..64e5545b264ac 100644 --- a/lib/SILOptimizer/Transforms/SimplifyCFG.cpp +++ b/lib/SILOptimizer/Transforms/SimplifyCFG.cpp @@ -209,6 +209,79 @@ static bool isUsedOutsideOfBlock(SILValue V, SILBasicBlock *BB) { return false; } +// Populate 'projections' with the chain of address projections leading +// to and including 'inst'. +// +// Populate 'inBlockDefs' with all the non-address value definitions in +// the block that will be used outside this block after projection sinking. +// +// Return true on success, even if projections is empty. +bool SinkAddressProjections::analyzeAddressProjections(SILInstruction *inst) { + projections.clear(); + inBlockDefs.clear(); + + SILBasicBlock *bb = inst->getParent(); + auto pushOperandVal = [&](SILValue def) { + if (def->getParentBlock() != bb) + return true; + + if (!def->getType().isAddress()) { + inBlockDefs.insert(def); + return true; + } + if (auto *addressProj = dyn_cast(def)) { + if (addressProj->isTriviallyDuplicatable()) { + projections.push_back(addressProj); + return true; + } + } + // Can't handle a multi-value or unclonable address producer. + return false; + }; + // Check the given instruction for any address-type results. + for (auto result : inst->getResults()) { + if (!isUsedOutsideOfBlock(result, bb)) + continue; + if (!pushOperandVal(result)) + return false; + } + // Recurse upward through address projections. + for (unsigned idx = 0; idx < projections.size(); ++idx) { + // Only one address result/operand can be handled per instruction. + if (projections.size() != idx + 1) + return false; + + for (SILValue operandVal : projections[idx]->getOperandValues()) + pushOperandVal(operandVal); + } + return true; +} + +// Clone the projections gathered by 'analyzeAddressProjections' at +// their use site outside this block. +bool SinkAddressProjections::cloneProjections() { + if (projections.empty()) + return false; + + SILBasicBlock *bb = projections.front()->getParent(); + SmallVector usesToReplace; + // Clone projections in last-to-first order. + for (unsigned idx = 0; idx < projections.size(); ++idx) { + auto *oldProj = projections[idx]; + assert(oldProj->getParent() == bb); + usesToReplace.clear(); + for (Operand *use : oldProj->getUses()) { + if (use->getUser()->getParent() != bb) + usesToReplace.push_back(use); + } + for (Operand *use : usesToReplace) { + auto *newProj = oldProj->clone(use->getUser()); + use->set(cast(newProj)); + } + } + return true; +} + /// Helper function to perform SSA updates in case of jump threading. void swift::updateSSAAfterCloning(BasicBlockCloner &Cloner, SILBasicBlock *SrcBB, SILBasicBlock *DestBB) { @@ -1024,20 +1097,31 @@ bool SimplifyCFG::tryJumpThreading(BranchInst *BI) { // If it looks potentially interesting, decide whether we *can* do the // operation and whether the block is small enough to be worth duplicating. int copyCosts = 0; - for (auto &Inst : *DestBB) { - copyCosts += getThreadingCost(&Inst); + SinkAddressProjections sinkProj; + for (auto ii = DestBB->begin(), ie = DestBB->end(); ii != ie;) { + copyCosts += getThreadingCost(&*ii); if (ThreadingBudget <= copyCosts) return false; - // We need to update ssa if a value is used outside the duplicated block. - if (!NeedToUpdateSSA) { - for (auto result : Inst.getResults()) { - if (isUsedOutsideOfBlock(result, DestBB)) { - NeedToUpdateSSA = true; - break; - } - } - } + // If this is an address projection with outside uses, sink it before + // checking for SSA update. + if (!sinkProj.analyzeAddressProjections(&*ii)) + return false; + + sinkProj.cloneProjections(); + // After cloning check if any of the non-address defs in the cloned block + // (including the current instruction) now have uses outside the + // block. Do this even if nothing was cloned. + if (!sinkProj.getInBlockDefs().empty()) + NeedToUpdateSSA = true; + + auto nextII = std::next(ii); + recursivelyDeleteTriviallyDeadInstructions( + &*ii, false, [&nextII](SILInstruction *deadInst) { + if (deadInst->getIterator() == nextII) + ++nextII; + }); + ii = nextII; } // Don't jump thread through a potential header - this can produce irreducible diff --git a/lib/SILOptimizer/UtilityPasses/CMakeLists.txt b/lib/SILOptimizer/UtilityPasses/CMakeLists.txt index 31887874dd4d9..c33fb8245cb25 100644 --- a/lib/SILOptimizer/UtilityPasses/CMakeLists.txt +++ b/lib/SILOptimizer/UtilityPasses/CMakeLists.txt @@ -10,6 +10,7 @@ silopt_register_sources( ComputeDominanceInfo.cpp ComputeLoopInfo.cpp ConstantEvaluatorTester.cpp + ConstantEvaluableSubsetChecker.cpp EpilogueARCMatcherDumper.cpp EpilogueRetainReleaseMatcherDumper.cpp EscapeAnalysisDumper.cpp diff --git a/lib/SILOptimizer/UtilityPasses/ConstantEvaluableSubsetChecker.cpp b/lib/SILOptimizer/UtilityPasses/ConstantEvaluableSubsetChecker.cpp new file mode 100644 index 0000000000000..54ba6d88c4057 --- /dev/null +++ b/lib/SILOptimizer/UtilityPasses/ConstantEvaluableSubsetChecker.cpp @@ -0,0 +1,189 @@ +//===--ConstantEvaluableSubsetChecker.cpp - Test Constant Evaluable Swift--===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2019 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 a pass for checking the constant evaluability of Swift +// code snippets. This pass is only used in tests and is not part of the +// compilation pipeline. + +#define DEBUG_TYPE "sil-constant-evaluable-subset-checker" +#include "swift/AST/DiagnosticsSIL.h" +#include "swift/AST/Module.h" +#include "swift/Demangling/Demangle.h" +#include "swift/SIL/CFG.h" +#include "swift/SIL/SILConstants.h" +#include "swift/SIL/SILInstruction.h" +#include "swift/SILOptimizer/PassManager/Passes.h" +#include "swift/SILOptimizer/PassManager/Transforms.h" +#include "swift/SILOptimizer/Utils/ConstExpr.h" + +using namespace swift; + +namespace { + +static const StringRef constantEvaluableSemanticsAttr = "constant_evaluable"; +static const StringRef testDriverSemanticsAttr = "test_driver"; + +template +static InFlightDiagnostic diagnose(ASTContext &Context, SourceLoc loc, + Diag diag, U &&... args) { + return Context.Diags.diagnose(loc, diag, std::forward(args)...); +} + +static std::string demangleSymbolName(StringRef name) { + Demangle::DemangleOptions options; + options.QualifyEntities = false; + return Demangle::demangleSymbolAsString(name, options); +} + +/// A SILModule pass that invokes the constant evaluator on all functions in a +/// SILModule with the semantics attribute "test_driver". Each "test_driver" +/// must invoke one or more functions in the module annotated as +/// "constant_evaluable" with constant arguments. +class ConstantEvaluableSubsetChecker : public SILModuleTransform { + + llvm::SmallPtrSet constantEvaluableFunctions; + llvm::SmallPtrSet evaluatedFunctions; + + /// Evaluate the body of \c fun with the constant evaluator. \c fun must be + /// annotated as "test_driver" and must invoke one or more functions annotated + /// as "constant_evaluable" with constant arguments. Emit diagnostics if the + /// evaluation of any "constant_evaluable" function called in the body of + /// \c fun fails. + void constantEvaluateDriver(SILFunction *fun) { + ASTContext &astContext = fun->getASTContext(); + + // Create a step evaluator and run it on the function. + SymbolicValueBumpAllocator allocator; + ConstExprStepEvaluator stepEvaluator(allocator, fun, + getOptions().AssertConfig, + /*trackCallees*/ true); + bool previousEvaluationHadFatalError = false; + + for (auto currI = fun->getEntryBlock()->begin();;) { + auto *inst = &(*currI); + + if (isa(inst)) + break; + + assert(!previousEvaluationHadFatalError && + "cannot continue evaluation of test driver as previous call " + "resulted in non-skippable evaluation error."); + + auto *applyInst = dyn_cast(inst); + SILFunction *callee = nullptr; + if (applyInst) { + callee = applyInst->getReferencedFunctionOrNull(); + } + + Optional nextInstOpt; + Optional errorVal; + + if (!applyInst || !callee || + !callee->hasSemanticsAttr(constantEvaluableSemanticsAttr)) { + std::tie(nextInstOpt, errorVal) = + stepEvaluator.tryEvaluateOrElseMakeEffectsNonConstant(currI); + if (!nextInstOpt) { + // This indicates an error in the test driver. + errorVal->emitUnknownDiagnosticNotes(inst->getLoc()); + assert(false && "non-constant control flow in the test driver"); + } + currI = nextInstOpt.getValue(); + continue; + } + + // Here, a function annotated as "constant_evaluable" is called. + llvm::errs() << "@" << demangleSymbolName(callee->getName()) << "\n"; + std::tie(nextInstOpt, errorVal) = + stepEvaluator.tryEvaluateOrElseMakeEffectsNonConstant(currI); + + if (errorVal) { + SourceLoc instLoc = inst->getLoc().getSourceLoc(); + diagnose(astContext, instLoc, diag::not_constant_evaluable); + errorVal->emitUnknownDiagnosticNotes(inst->getLoc()); + } + + if (nextInstOpt) { + currI = nextInstOpt.getValue(); + continue; + } + + // Here, a non-skippable error like "instruction-limit exceeded" has been + // encountered during evaluation. Proceed to the next instruction but + // ensure that an assertion failure occurs if there is any instruction + // to evaluate after this instruction. + ++currI; + previousEvaluationHadFatalError = true; + } + + // For every function seen during the evaluation of this constant evaluable + // function: + // 1. Record it so as to detect whether the test drivers in the SILModule + // cover all function annotated as "constant_evaluable". + // + // 2. If the callee is annotated as constant_evaluable and is imported from + // a different Swift module (other than stdlib), check that the function is + // marked as Onone. Otherwise, it could have been optimized, which will + // break constant evaluability. + for (SILFunction *callee : stepEvaluator.getFuncsCalledDuringEvaluation()) { + evaluatedFunctions.insert(callee); + + SILModule &calleeModule = callee->getModule(); + if (callee->isAvailableExternally() && + callee->hasSemanticsAttr(constantEvaluableSemanticsAttr) && + callee->getOptimizationMode() != OptimizationMode::NoOptimization) { + diagnose(calleeModule.getASTContext(), + callee->getLocation().getSourceLoc(), + diag::constexpr_imported_func_not_onone, + demangleSymbolName(callee->getName())); + } + } + } + + void run() override { + SILModule *module = getModule(); + assert(module); + + for (SILFunction &fun : *module) { + // Record functions annotated as constant evaluable. + if (fun.hasSemanticsAttr(constantEvaluableSemanticsAttr)) { + constantEvaluableFunctions.insert(&fun); + continue; + } + + // Evaluate test drivers. + if (!fun.hasSemanticsAttr(testDriverSemanticsAttr)) + continue; + constantEvaluateDriver(&fun); + } + + // Assert that every function annotated as "constant_evaluable" was convered + // by a test driver. + bool error = false; + for (SILFunction *constEvalFun : constantEvaluableFunctions) { + if (!evaluatedFunctions.count(constEvalFun)) { + llvm::errs() << "Error: function " + << demangleSymbolName(constEvalFun->getName()); + llvm::errs() << " annotated as constant evaluable"; + llvm::errs() << " does not have a test driver" + << "\n"; + error = true; + } + } + assert(!error); + } +}; + +} // end anonymous namespace + +SILTransform *swift::createConstantEvaluableSubsetChecker() { + return new ConstantEvaluableSubsetChecker(); +} diff --git a/lib/SILOptimizer/UtilityPasses/ConstantEvaluatorTester.cpp b/lib/SILOptimizer/UtilityPasses/ConstantEvaluatorTester.cpp index c7370fa6bb0b9..25dc9534ba1e8 100644 --- a/lib/SILOptimizer/UtilityPasses/ConstantEvaluatorTester.cpp +++ b/lib/SILOptimizer/UtilityPasses/ConstantEvaluatorTester.cpp @@ -59,7 +59,8 @@ class ConstantEvaluatorTester : public SILFunctionTransform { llvm::errs() << "@" << fun->getName() << "\n"; SymbolicValueBumpAllocator allocator; - ConstExprStepEvaluator stepEvaluator(allocator, fun); + ConstExprStepEvaluator stepEvaluator(allocator, fun, + getOptions().AssertConfig); for (auto currI = fun->getEntryBlock()->begin();;) { auto *inst = &(*currI); diff --git a/lib/SILOptimizer/Utils/ConstExpr.cpp b/lib/SILOptimizer/Utils/ConstExpr.cpp index 0c5846835fda5..dd5d784e04818 100644 --- a/lib/SILOptimizer/Utils/ConstExpr.cpp +++ b/lib/SILOptimizer/Utils/ConstExpr.cpp @@ -30,8 +30,7 @@ using namespace swift; static llvm::Optional evaluateAndCacheCall(SILFunction &fn, SubstitutionMap substitutionMap, - ArrayRef arguments, - SmallVectorImpl &results, + ArrayRef arguments, SymbolicValue &result, unsigned &numInstEvaluated, ConstExprEvaluator &evaluator); // TODO: ConstantTracker in the performance inliner and the @@ -48,7 +47,9 @@ enum class WellKnownFunction { // static String.== infix(_: String) StringEquals, // String.percentEscapedString.getter - StringEscapePercent + StringEscapePercent, + // _assertionFailure(_: StaticString, _: StaticString, file: StaticString,...) + AssertionFailure }; static llvm::Optional classifyFunction(SILFunction *fn) { @@ -65,9 +66,17 @@ static llvm::Optional classifyFunction(SILFunction *fn) { return WellKnownFunction::StringEquals; if (fn->hasSemanticsAttr("string.escapePercent.get")) return WellKnownFunction::StringEscapePercent; + if (fn->hasSemanticsAttrThatStartsWith("programtermination_point")) + return WellKnownFunction::AssertionFailure; return None; } +/// Helper function for creating UnknownReason without a payload. +static SymbolicValue getUnknown(ConstExprEvaluator &evaluator, SILNode *node, + UnknownReason::UnknownKind kind) { + return evaluator.getUnknown(node, UnknownReason::create(kind)); +} + //===----------------------------------------------------------------------===// // ConstExprFunctionState implementation. //===----------------------------------------------------------------------===// @@ -109,6 +118,19 @@ class ConstExprFunctionState { : evaluator(evaluator), fn(fn), substitutionMap(substitutionMap), numInstEvaluated(numInstEvaluated) {} + /// Pretty print the state to stderr. + void dump() const { + llvm::errs() << "[ConstExprState: \n"; + llvm::errs() << " Caller: " << (fn ? fn->getName() : "null") << "\n"; + llvm::errs() << " evaluatedInstrCount: " << numInstEvaluated << "\n"; + llvm::errs() << " SubstMap: \n"; + substitutionMap.dump(llvm::errs(), SubstitutionMap::DumpStyle::Full, 6); + llvm::errs() << "\n calculatedValues: "; + for (auto kv : calculatedValues) { + llvm::errs() << " " << kv.first << " --> " << kv.second << "\n"; + } + } + void setValue(SILValue value, SymbolicValue symVal) { calculatedValues.insert({value, symVal}); } @@ -330,12 +352,10 @@ SymbolicValue ConstExprFunctionState::computeConstantValue(SILValue value) { auto confResult = substitutionMap.lookupConformance( wmi->getLookupType(), wmi->getConformance().getRequirement()); if (!confResult) - return evaluator.getUnknown( - value, UnknownReason::UnknownWitnessMethodConformance); + return getUnknown(evaluator, value, + UnknownReason::UnknownWitnessMethodConformance); auto conf = confResult.getValue(); auto &module = wmi->getModule(); - - // Look up the conformance's witness table and the member out of it. SILFunction *fn = module.lookUpFunctionInWitnessTable(conf, wmi->getMember()).first; // If we were able to resolve it, then we can proceed. @@ -344,8 +364,7 @@ SymbolicValue ConstExprFunctionState::computeConstantValue(SILValue value) { LLVM_DEBUG(llvm::dbgs() << "ConstExpr Unresolved witness: " << *value << "\n"); - return evaluator.getUnknown(value, - UnknownReason::UnresolvableWitnessMethod); + return getUnknown(evaluator, value, UnknownReason::NoWitnesTableEntry); } if (auto *builtin = dyn_cast(value)) @@ -417,17 +436,27 @@ SymbolicValue ConstExprFunctionState::computeConstantValue(SILValue value) { auto unknownReason = isa(value) ? UnknownReason::UnsupportedInstruction : UnknownReason::Default; - return evaluator.getUnknown(value, unknownReason); + return getUnknown(evaluator, value, unknownReason); } SymbolicValue ConstExprFunctionState::computeConstantValueBuiltin(BuiltinInst *inst) { const BuiltinInfo &builtin = inst->getBuiltinInfo(); + // Constant builtins. + if (inst->getNumOperands() == 0) { + switch (builtin.ID) { + default: + break; + case BuiltinValueKind::AssertConf: + return SymbolicValue::getInteger(evaluator.getAssertConfig(), 32); + } + } + // Handle various cases in groups. - auto unknownResult = [&]() -> SymbolicValue { - return evaluator.getUnknown(SILValue(inst), - UnknownReason::InvalidOperandValue); + auto invalidOperandValue = [&]() -> SymbolicValue { + return getUnknown(evaluator, SILValue(inst), + UnknownReason::InvalidOperandValue); }; // Unary operations. @@ -446,7 +475,7 @@ ConstExprFunctionState::computeConstantValueBuiltin(BuiltinInst *inst) { auto IntCheckedTruncFn = [&](bool srcSigned, bool dstSigned) -> SymbolicValue { if (operand.getKind() != SymbolicValue::Integer) - return unknownResult(); + return invalidOperandValue(); APInt operandVal = operand.getIntegerValue(); uint32_t srcBitWidth = operandVal.getBitWidth(); @@ -469,7 +498,7 @@ ConstExprFunctionState::computeConstantValueBuiltin(BuiltinInst *inst) { overflowed |= result.isSignBitSet(); if (overflowed) - return evaluator.getUnknown(SILValue(inst), UnknownReason::Overflow); + return getUnknown(evaluator, SILValue(inst), UnknownReason::Overflow); } auto &allocator = evaluator.getAllocator(); @@ -499,7 +528,7 @@ ConstExprFunctionState::computeConstantValueBuiltin(BuiltinInst *inst) { case BuiltinValueKind::SExt: case BuiltinValueKind::SExtOrBitCast: { if (operand.getKind() != SymbolicValue::Integer) - return unknownResult(); + return invalidOperandValue(); unsigned destBitWidth = inst->getType().castTo()->getGreatestWidth(); @@ -525,6 +554,18 @@ ConstExprFunctionState::computeConstantValueBuiltin(BuiltinInst *inst) { } return SymbolicValue::getInteger(result, evaluator.getAllocator()); } + // The two following builtins are supported only for string constants. This + // is because this builtin is used by StaticString which is used in + // preconditions and assertion failures. Supporting this enables the + // evaluator to handle assertion/precondition failures. + case BuiltinValueKind::PtrToInt: + case BuiltinValueKind::IntToPtr: { + if (operand.getKind() != SymbolicValue::String) { + return getUnknown(evaluator, SILValue(inst), + UnknownReason::UnsupportedInstruction); + } + return operand; + } } } @@ -542,7 +583,7 @@ ConstExprFunctionState::computeConstantValueBuiltin(BuiltinInst *inst) { -> SymbolicValue { if (operand0.getKind() != SymbolicValue::Integer || operand1.getKind() != SymbolicValue::Integer) - return unknownResult(); + return invalidOperandValue(); auto result = fn(operand0.getIntegerValue(), operand1.getIntegerValue()); return SymbolicValue::getInteger(APInt(1, result), @@ -552,7 +593,7 @@ ConstExprFunctionState::computeConstantValueBuiltin(BuiltinInst *inst) { #define REQUIRE_KIND(KIND) \ if (operand0.getKind() != SymbolicValue::KIND || \ operand1.getKind() != SymbolicValue::KIND) \ - return unknownResult(); + return invalidOperandValue(); switch (builtin.ID) { default: @@ -595,6 +636,9 @@ ConstExprFunctionState::computeConstantValueBuiltin(BuiltinInst *inst) { INT_COMPARE(ICMP_UGE, l.uge(r)); #undef INT_COMPARE #undef REQUIRE_KIND + + case BuiltinValueKind::Expect: + return operand0; } } @@ -618,7 +662,7 @@ ConstExprFunctionState::computeConstantValueBuiltin(BuiltinInst *inst) { if (operand0.getKind() != SymbolicValue::Integer || operand1.getKind() != SymbolicValue::Integer || operand2.getKind() != SymbolicValue::Integer) - return unknownResult(); + return invalidOperandValue(); auto l = operand0.getIntegerValue(), r = operand1.getIntegerValue(); bool overflowed = false; @@ -627,7 +671,7 @@ ConstExprFunctionState::computeConstantValueBuiltin(BuiltinInst *inst) { // Return a statically diagnosed overflow if the operation is supposed to // trap on overflow. if (overflowed && !operand2.getIntegerValue().isNullValue()) - return evaluator.getUnknown(SILValue(inst), UnknownReason::Overflow); + return getUnknown(evaluator, SILValue(inst), UnknownReason::Overflow); auto &allocator = evaluator.getAllocator(); // Build the Symbolic value result for our normal and overflow bit. @@ -660,8 +704,8 @@ ConstExprFunctionState::computeConstantValueBuiltin(BuiltinInst *inst) { LLVM_DEBUG(llvm::dbgs() << "ConstExpr Unknown Builtin: " << *inst << "\n"); // Otherwise, we don't know how to handle this builtin. - return evaluator.getUnknown(SILValue(inst), - UnknownReason::UnsupportedInstruction); + return getUnknown(evaluator, SILValue(inst), + UnknownReason::UnsupportedInstruction); } // Handle calls to opaque callees, either by handling them and returning None or @@ -670,8 +714,22 @@ llvm::Optional ConstExprFunctionState::computeOpaqueCallResult(ApplyInst *apply, SILFunction *callee) { LLVM_DEBUG(llvm::dbgs() << "ConstExpr Opaque Callee: " << *callee << "\n"); - return evaluator.getUnknown((SILInstruction *)apply, - UnknownReason::CalleeImplementationUnknown); + return evaluator.getUnknown( + (SILInstruction *)apply, + UnknownReason::createCalleeImplementationUnknown(callee)); +} + +/// Given a symbolic value representing an instance of StaticString, look into +/// the aggregate and extract the static string value stored inside it. +static Optional +extractStaticStringValue(SymbolicValue staticString) { + if (staticString.getKind() != SymbolicValue::Aggregate) + return None; + ArrayRef staticStringProps = staticString.getAggregateValue(); + if (staticStringProps.empty() || + staticStringProps[0].getKind() != SymbolicValue::String) + return None; + return staticStringProps[0].getStringValue(); } /// Given a call to a well known function, collect its arguments as constants, @@ -683,6 +741,34 @@ ConstExprFunctionState::computeWellKnownCallResult(ApplyInst *apply, WellKnownFunction callee) { auto conventions = apply->getSubstCalleeConv(); switch (callee) { + case WellKnownFunction::AssertionFailure: { + SmallString<4> message; + for (unsigned i = 0; i < apply->getNumArguments(); i++) { + SILValue argument = apply->getArgument(i); + SymbolicValue argValue = getConstantValue(argument); + Optional stringOpt = extractStaticStringValue(argValue); + + // The first argument is a prefix that specifies the kind of failure + // this is. + if (i == 0) { + if (stringOpt) { + message += stringOpt.getValue(); + } else { + // Use a generic prefix here, as the actual prefix is not a constant. + message += "assertion failed"; + } + continue; + } + + if (stringOpt) { + message += ": "; + message += stringOpt.getValue(); + } + } + return evaluator.getUnknown( + (SILInstruction *)apply, + UnknownReason::createTrap(message, evaluator.getAllocator())); + } case WellKnownFunction::StringInitEmpty: { // String.init() assert(conventions.getNumDirectSILResults() == 1 && conventions.getNumIndirectSILResults() == 0 && @@ -700,16 +786,16 @@ ConstExprFunctionState::computeWellKnownCallResult(ApplyInst *apply, conventions.getNumParameters() == 4 && "unexpected signature"); auto literal = getConstantValue(apply->getOperand(1)); if (literal.getKind() != SymbolicValue::String) { - return evaluator.getUnknown((SILInstruction *)apply, - UnknownReason::InvalidOperandValue); + return getUnknown(evaluator, (SILInstruction *)apply, + UnknownReason::InvalidOperandValue); } auto literalVal = literal.getStringValue(); auto byteCount = getConstantValue(apply->getOperand(2)); if (byteCount.getKind() != SymbolicValue::Integer || byteCount.getIntegerValue().getLimitedValue() != literalVal.size()) { - return evaluator.getUnknown((SILInstruction *)apply, - UnknownReason::InvalidOperandValue); + return getUnknown(evaluator, (SILInstruction *)apply, + UnknownReason::InvalidOperandValue); } setValue(apply, literal); return None; @@ -726,8 +812,8 @@ ConstExprFunctionState::computeWellKnownCallResult(ApplyInst *apply, return otherString; } if (otherString.getKind() != SymbolicValue::String) { - return evaluator.getUnknown((SILInstruction *)apply, - UnknownReason::InvalidOperandValue); + return getUnknown(evaluator, (SILInstruction *)apply, + UnknownReason::InvalidOperandValue); } auto inoutOperand = apply->getOperand(2); @@ -736,8 +822,8 @@ ConstExprFunctionState::computeWellKnownCallResult(ApplyInst *apply, return firstString; } if (firstString.getKind() != SymbolicValue::String) { - return evaluator.getUnknown((SILInstruction *)apply, - UnknownReason::InvalidOperandValue); + return getUnknown(evaluator, (SILInstruction *)apply, + UnknownReason::InvalidOperandValue); } auto result = SmallString<8>(firstString.getStringValue()); @@ -755,14 +841,14 @@ ConstExprFunctionState::computeWellKnownCallResult(ApplyInst *apply, auto firstString = getConstantValue(apply->getOperand(1)); if (firstString.getKind() != SymbolicValue::String) { - return evaluator.getUnknown((SILInstruction *)apply, - UnknownReason::InvalidOperandValue); + return getUnknown(evaluator, (SILInstruction *)apply, + UnknownReason::InvalidOperandValue); } auto otherString = getConstantValue(apply->getOperand(2)); if (otherString.getKind() != SymbolicValue::String) { - return evaluator.getUnknown((SILInstruction *)apply, - UnknownReason::InvalidOperandValue); + return getUnknown(evaluator, (SILInstruction *)apply, + UnknownReason::InvalidOperandValue); } // The result is a Swift.Bool which is a struct that wraps an Int1. @@ -787,8 +873,8 @@ ConstExprFunctionState::computeWellKnownCallResult(ApplyInst *apply, } if (stringArgument.getKind() != SymbolicValue::String) { - return evaluator.getUnknown((SILInstruction *)apply, - UnknownReason::InvalidOperandValue); + return getUnknown(evaluator, (SILInstruction *)apply, + UnknownReason::InvalidOperandValue); } // Replace all precent symbol (%) in the string with double percents (%%) @@ -816,15 +902,14 @@ ConstExprFunctionState::computeWellKnownCallResult(ApplyInst *apply, /// information about the error. llvm::Optional ConstExprFunctionState::computeCallResult(ApplyInst *apply) { - auto conventions = apply->getSubstCalleeConv(); - // Determine the callee. auto calleeFn = getConstantValue(apply->getOperand(0)); if (calleeFn.getKind() != SymbolicValue::Function) - return evaluator.getUnknown((SILInstruction *)apply, - UnknownReason::InvalidOperandValue); + return getUnknown(evaluator, (SILInstruction *)apply, + UnknownReason::InvalidOperandValue); SILFunction *callee = calleeFn.getFunctionValue(); + evaluator.recordCalledFunctionIfEnabled(callee); // If this is a well-known function, do not step into it. if (auto wellKnownFunction = classifyFunction(callee)) @@ -879,9 +964,8 @@ ConstExprFunctionState::computeCallResult(ApplyInst *apply) { auto conf = protoSelfToConcreteType.lookupConformance( protocol->getSelfInterfaceType()->getCanonicalType(), protocol); if (!conf.hasValue()) - return evaluator.getUnknown( - (SILInstruction *)apply, - UnknownReason::UnknownWitnessMethodConformance); + return getUnknown(evaluator, (SILInstruction *)apply, + UnknownReason::UnknownWitnessMethodConformance); callSubMap = getWitnessMethodSubstitutions( apply->getModule(), ApplySite(apply), callee, conf.getValue()); @@ -906,27 +990,15 @@ ConstExprFunctionState::computeCallResult(ApplyInst *apply) { // Now that we have successfully folded all of the parameters, we can evaluate // the call. evaluator.pushCallStack(apply->getLoc().getSourceLoc()); - SmallVector results; + SymbolicValue result; auto callResult = evaluateAndCacheCall(*callee, calleeSubMap, paramConstants, - results, numInstEvaluated, evaluator); + result, numInstEvaluated, evaluator); evaluator.popCallStack(); + + // Return the error value the callee evaluation failed. if (callResult.hasValue()) return callResult.getValue(); - - unsigned nextResult = 0; - - // If evaluation was successful, remember the results we captured in our - // current function's state. - if (unsigned numNormalResults = conventions.getNumDirectSILResults()) { - // TODO: unclear when this happens, is this for tuple result values? - assert(numNormalResults == 1 && "Multiple results aren't supported?"); - setValue(apply->getResults()[0], results[nextResult]); - ++nextResult; - } - - assert(nextResult == results.size() && "Unexpected number of results found"); - - // We have successfully folded this call! + setValue(apply, result); return None; } @@ -1036,8 +1108,8 @@ ConstExprFunctionState::initializeAddressFromSingleWriter(SILValue addr) { if (use->getOperandNumber() == 1) { // Forbid multiple assignment. if (getMemoryValue().getKind() != SymbolicValue::UninitMemory) - return error(evaluator.getUnknown( - addr, UnknownReason::MutipleTopLevelWriters)); + return error(getUnknown(evaluator, addr, + UnknownReason::MutipleTopLevelWriters)); auto result = getConstantValue(si->getOperand(0)); if (!result.isConstant()) @@ -1058,7 +1130,7 @@ ConstExprFunctionState::initializeAddressFromSingleWriter(SILValue addr) { // Forbid multiple assignment. if (getMemoryValue().getKind() != SymbolicValue::UninitMemory) return error( - evaluator.getUnknown(addr, UnknownReason::MutipleTopLevelWriters)); + getUnknown(evaluator, addr, UnknownReason::MutipleTopLevelWriters)); auto result = getConstAddrAndLoadResult(cai->getOperand(0)); if (!result.isConstant()) @@ -1083,7 +1155,7 @@ ConstExprFunctionState::initializeAddressFromSingleWriter(SILValue addr) { // Forbid multiple assignment. if (getMemoryValue().getKind() != SymbolicValue::UninitMemory) return error( - evaluator.getUnknown(addr, UnknownReason::MutipleTopLevelWriters)); + getUnknown(evaluator, addr, UnknownReason::MutipleTopLevelWriters)); // The callee needs to be a direct call to a constant expression. auto callResult = computeCallResult(apply); @@ -1106,7 +1178,7 @@ ConstExprFunctionState::initializeAddressFromSingleWriter(SILValue addr) { continue; } return error( - evaluator.getUnknown(addr, UnknownReason::NotTopLevelConstant)); + getUnknown(evaluator, addr, UnknownReason::NotTopLevelConstant)); } if (auto *teai = dyn_cast(user)) { @@ -1154,12 +1226,12 @@ ConstExprFunctionState::initializeAddressFromSingleWriter(SILValue addr) { // If this is some other user that we don't know about, then we should // treat it conservatively, because it could store into the address. return error( - evaluator.getUnknown(addr, UnknownReason::NotTopLevelConstant)); + getUnknown(evaluator, addr, UnknownReason::NotTopLevelConstant)); } if (mustCheckAggregateInitialized && !checkAggregateInitialized()) return error( - evaluator.getUnknown(addr, UnknownReason::NotTopLevelConstant)); + getUnknown(evaluator, addr, UnknownReason::NotTopLevelConstant)); return None; } @@ -1209,7 +1281,7 @@ ConstExprFunctionState::getSingleWriterAddressValue(SILValue addr) { assert(addr->getType().isAddress()); auto *addrInst = dyn_cast(addr); if (!addrInst) - return evaluator.getUnknown(addr, UnknownReason::NotTopLevelConstant); + return getUnknown(evaluator, addr, UnknownReason::NotTopLevelConstant); // Create a memory object to initialize, and point `addr` at it. auto memoryAddress = @@ -1223,7 +1295,7 @@ ConstExprFunctionState::getSingleWriterAddressValue(SILValue addr) { } if (!memoryObject->getValue().isConstant()) { auto unknown = - evaluator.getUnknown(addr, UnknownReason::NotTopLevelConstant); + getUnknown(evaluator, addr, UnknownReason::NotTopLevelConstant); memoryObject->setValue(unknown); return unknown; } @@ -1269,7 +1341,7 @@ SymbolicValue ConstExprFunctionState::loadAddrValue(SILValue addr, return objectVal; // Otherwise, return a generic failure. - return evaluator.getUnknown(addr, UnknownReason::InvalidOperandValue); + return getUnknown(evaluator, addr, UnknownReason::InvalidOperandValue); } /// Evaluate a flow sensitive store to the specified pointer address. @@ -1278,9 +1350,9 @@ ConstExprFunctionState::computeFSStore(SymbolicValue storedCst, SILValue dest) { // Only update existing memory locations that we're tracking. auto it = calculatedValues.find(dest); if (it == calculatedValues.end()) - return evaluator.getUnknown(dest, UnknownReason::UntrackedSILValue); + return getUnknown(evaluator, dest, UnknownReason::UntrackedSILValue); if (!it->second.isConstant()) - return evaluator.getUnknown(dest, UnknownReason::InvalidOperandValue); + return getUnknown(evaluator, dest, UnknownReason::InvalidOperandValue); SmallVector accessPath; auto *memoryObject = it->second.getAddressValue(accessPath); @@ -1309,6 +1381,16 @@ ConstExprFunctionState::evaluateFlowSensitive(SILInstruction *inst) { // If this is a special flow-sensitive instruction like a stack allocation, // store, copy_addr, etc, we handle it specially here. if (auto asi = dyn_cast(inst)) { + // If a struct with no stored properties is created, no initialization is + // needed. Hence, create a empty aggregate as the initial value. + StructDecl *structDecl = + asi->getElementType().getStructOrBoundGenericStruct(); + if (structDecl && structDecl->getStoredProperties().empty()) { + createMemoryObject(asi, + SymbolicValue::getAggregate(ArrayRef(), + evaluator.getAllocator())); + return None; + } createMemoryObject(asi, SymbolicValue::getUninitMemory()); return None; } @@ -1328,13 +1410,17 @@ ConstExprFunctionState::evaluateFlowSensitive(SILInstruction *inst) { if (isa(inst)) return None; - if (isa(inst)) { + if (CondFailInst *condFail = dyn_cast(inst)) { auto failed = getConstantValue(inst->getOperand(0)); if (failed.getKind() == SymbolicValue::Integer) { if (failed.getIntegerValue() == 0) return None; // Conditional fail actually failed. - return evaluator.getUnknown(inst, UnknownReason::Trap); + return evaluator.getUnknown( + (SILInstruction *)inst, + UnknownReason::createTrap( + (Twine("trap: ") + condFail->getMessage()).str(), + evaluator.getAllocator())); } } @@ -1394,7 +1480,7 @@ ConstExprFunctionState::evaluateFlowSensitive(SILInstruction *inst) { LLVM_DEBUG(llvm::dbgs() << "ConstExpr Unknown FS: " << *inst << "\n"); // If this is an unknown instruction with no results then bail out. - return evaluator.getUnknown(inst, UnknownReason::UnsupportedInstruction); + return getUnknown(evaluator, inst, UnknownReason::UnsupportedInstruction); } std::pair, Optional> @@ -1417,7 +1503,7 @@ ConstExprFunctionState::evaluateInstructionAndGetNext( // If we've already visited this block then fail - we have a loop. if (!visitedBlocks.insert(destBB).second) - return {None, evaluator.getUnknown(br, UnknownReason::Loop)}; + return {None, getUnknown(evaluator, br, UnknownReason::Loop)}; // Set up basic block arguments. for (unsigned i = 0, e = br->getNumArgs(); i != e; ++i) { @@ -1443,7 +1529,7 @@ ConstExprFunctionState::evaluateInstructionAndGetNext( // If we've already visited this block then fail - we have a loop. if (!visitedBlocks.insert(destBB).second) - return {None, evaluator.getUnknown(cbr, UnknownReason::Loop)}; + return {None, getUnknown(evaluator, cbr, UnknownReason::Loop)}; return {destBB->begin(), None}; } @@ -1463,8 +1549,17 @@ ConstExprFunctionState::evaluateInstructionAndGetNext( assert(value.getKind() == SymbolicValue::Enum || value.getKind() == SymbolicValue::EnumWithPayload); - auto *caseBB = switchInst->getCaseDestination(value.getEnumValue()); + SILBasicBlock *caseBB = + switchInst->getCaseDestination(value.getEnumValue()); + if (caseBB->getNumArguments() == 0) + return {caseBB->begin(), None}; + // Set up the arguments. + + // When there are multiple payload components, they form a single + // tuple-typed argument. + assert(caseBB->getNumArguments() == 1); + if (caseBB->getParent()->hasOwnership() && switchInst->getDefaultBBOrNull() == caseBB) { // If we are visiting the default block and we are in ossa, then we may @@ -1474,13 +1569,7 @@ ConstExprFunctionState::evaluateInstructionAndGetNext( return {caseBB->begin(), None}; } - if (caseBB->getNumArguments() == 0) - return {caseBB->begin(), None}; - assert(value.getKind() == SymbolicValue::EnumWithPayload); - // When there are multiple payload components, they form a single - // tuple-typed argument. - assert(caseBB->getNumArguments() == 1); auto argument = value.getEnumPayloadValue(); assert(argument.isConstant()); setValue(caseBB->getArgument(0), argument); @@ -1492,17 +1581,18 @@ ConstExprFunctionState::evaluateInstructionAndGetNext( << "\n"); return {None, - evaluator.getUnknown(inst, UnknownReason::UnsupportedInstruction)}; + getUnknown(evaluator, inst, UnknownReason::UnsupportedInstruction)}; } /// Evaluate a call to the specified function as if it were a constant /// expression, returning None and filling in `results` on success, or /// returning an 'Unknown' SymbolicValue on failure carrying the error. /// -static llvm::Optional evaluateAndCacheCall( - SILFunction &fn, SubstitutionMap substitutionMap, - ArrayRef arguments, SmallVectorImpl &results, - unsigned &numInstEvaluated, ConstExprEvaluator &evaluator) { +static llvm::Optional +evaluateAndCacheCall(SILFunction &fn, SubstitutionMap substitutionMap, + ArrayRef arguments, SymbolicValue &result, + unsigned &numInstEvaluated, + ConstExprEvaluator &evaluator) { assert(!fn.isExternalDeclaration() && "Can't analyze bodyless function"); ConstExprFunctionState state(evaluator, &fn, substitutionMap, numInstEvaluated); @@ -1510,8 +1600,6 @@ static llvm::Optional evaluateAndCacheCall( // TODO: implement caching. // TODO: reject code that is too complex. - // Set up all of the indirect results and argument values. - auto conventions = fn.getConventions(); unsigned nextBBArg = 0; const auto &argList = fn.front().getArguments(); @@ -1538,7 +1626,7 @@ static llvm::Optional evaluateAndCacheCall( // Make sure we haven't exceeded our interpreter iteration cap. if (++numInstEvaluated > ConstExprLimit) { - return evaluator.getUnknown(inst, UnknownReason::TooManyInstructions); + return getUnknown(evaluator, inst, UnknownReason::TooManyInstructions); } if (isa(inst)) { @@ -1548,14 +1636,7 @@ static llvm::Optional evaluateAndCacheCall( // If we got a constant value, then we're good. Set up the normal result // values as well as any indirect results. - auto numNormalResults = conventions.getNumDirectSILResults(); - if (numNormalResults == 1) { - results.push_back(val); - } else if (numNormalResults > 1) { - auto elts = val.getAggregateValue(); - assert(elts.size() == numNormalResults && "result list mismatch!"); - results.append(results.begin(), results.end()); - } + result = val; // TODO: Handle caching of results. @@ -1582,8 +1663,9 @@ static llvm::Optional evaluateAndCacheCall( // ConstExprEvaluator implementation. //===----------------------------------------------------------------------===// -ConstExprEvaluator::ConstExprEvaluator(SymbolicValueAllocator &alloc) - : allocator(alloc) {} +ConstExprEvaluator::ConstExprEvaluator(SymbolicValueAllocator &alloc, + unsigned assertConf, bool trackCallees) + : allocator(alloc), assertConfig(assertConf), trackCallees(trackCallees) {} ConstExprEvaluator::~ConstExprEvaluator() {} @@ -1599,14 +1681,10 @@ SymbolicValue ConstExprEvaluator::getUnknown(SILNode *node, getAllocator()); } -/// Analyze the specified values to determine if they are constant values. This -/// is done in code that is not necessarily itself a constexpr function. The +/// Analyze the specified values to determine if they are constant values. This +/// is done in code that is not necessarily itself a constexpr function. The /// results are added to the results list which is a parallel structure to the /// input values. -/// -/// TODO: Return information about which callees were found to be -/// constexprs, which would allow the caller to delete dead calls to them -/// that occur after folding them. void ConstExprEvaluator::computeConstantValues( ArrayRef values, SmallVectorImpl &results) { unsigned numInstEvaluated = 0; @@ -1626,9 +1704,12 @@ void ConstExprEvaluator::computeConstantValues( //===----------------------------------------------------------------------===// ConstExprStepEvaluator::ConstExprStepEvaluator(SymbolicValueAllocator &alloc, - SILFunction *fun) - : evaluator(alloc), internalState(new ConstExprFunctionState( - evaluator, fun, {}, stepsEvaluated)) { + SILFunction *fun, + unsigned assertConf, + bool trackCallees) + : evaluator(alloc, assertConf, trackCallees), + internalState( + new ConstExprFunctionState(evaluator, fun, {}, stepsEvaluated)) { assert(fun); } @@ -1691,8 +1772,9 @@ ConstExprStepEvaluator::skipByMakingEffectsNonConstant( SmallVector accessPath; auto *memoryObject = constVal.getAddressValue(accessPath); auto unknownValue = SymbolicValue::getUnknown( - inst, UnknownReason::MutatedByUnevaluatedInstruction, {}, - evaluator.getAllocator()); + inst, + UnknownReason::create(UnknownReason::MutatedByUnevaluatedInstruction), + {}, evaluator.getAllocator()); auto memoryContent = memoryObject->getValue(); if (memoryContent.getKind() == SymbolicValue::Aggregate) { @@ -1707,8 +1789,10 @@ ConstExprStepEvaluator::skipByMakingEffectsNonConstant( for (auto result : inst->getResults()) { internalState->setValue( result, SymbolicValue::getUnknown( - inst, UnknownReason::ReturnedByUnevaluatedInstruction, {}, - evaluator.getAllocator())); + inst, + UnknownReason::create( + UnknownReason::ReturnedByUnevaluatedInstruction), + {}, evaluator.getAllocator())); } // If we have a next instruction in the basic block return it. @@ -1724,9 +1808,8 @@ ConstExprStepEvaluator::skipByMakingEffectsNonConstant( bool ConstExprStepEvaluator::isFailStopError(SymbolicValue errorVal) { assert(errorVal.isUnknown()); - switch (errorVal.getUnknownReason()) { + switch (errorVal.getUnknownReason().getKind()) { case UnknownReason::TooManyInstructions: - case UnknownReason::Loop: case UnknownReason::Overflow: case UnknownReason::Trap: return true; @@ -1738,7 +1821,6 @@ bool ConstExprStepEvaluator::isFailStopError(SymbolicValue errorVal) { std::pair, Optional> ConstExprStepEvaluator::tryEvaluateOrElseMakeEffectsNonConstant( SILBasicBlock::iterator instI) { - auto evaluateResult = evaluate(instI); Optional nextI = evaluateResult.first; Optional errorVal = evaluateResult.second; @@ -1753,8 +1835,12 @@ ConstExprStepEvaluator::tryEvaluateOrElseMakeEffectsNonConstant( return evaluateResult; } - // Evaluation cannot fail on unconditional branches. - assert(!isa(&(*instI))); + // If evaluation fails on an unconditional branch, it implies there is a loop + // at the top level. + if (isa(&(*instI))) { + assert(errorVal->getUnknownReason().getKind() == UnknownReason::Loop); + return evaluateResult; + } // Since the evaluation has failed, make the effects of this instruction // unknown. @@ -1771,6 +1857,6 @@ ConstExprStepEvaluator::lookupConstValue(SILValue value) { return res; } -bool ConstExprStepEvaluator::isKnownFunction(SILFunction *fun) { +bool swift::isKnownConstantEvaluableFunction(SILFunction *fun) { return classifyFunction(fun).hasValue(); } diff --git a/lib/SILOptimizer/Utils/ConstantFolding.cpp b/lib/SILOptimizer/Utils/ConstantFolding.cpp index aca46e3e52e9c..0e101edc22d61 100644 --- a/lib/SILOptimizer/Utils/ConstantFolding.cpp +++ b/lib/SILOptimizer/Utils/ConstantFolding.cpp @@ -14,6 +14,7 @@ #include "swift/AST/DiagnosticsSIL.h" #include "swift/AST/Expr.h" +#include "swift/SIL/InstructionUtils.h" #include "swift/SIL/PatternMatch.h" #include "swift/SIL/SILBuilder.h" #include "swift/SILOptimizer/Utils/CastOptimizer.h" @@ -23,7 +24,7 @@ #include "llvm/ADT/Statistic.h" #include "llvm/Support/Debug.h" -#define DEBUG_TYPE "constant-folding" +#define DEBUG_TYPE "sil-constant-folding" using namespace swift; @@ -582,6 +583,20 @@ constantFoldAndCheckDivision(BuiltinInst *BI, BuiltinValueKind ID, return B.createIntegerLiteral(BI->getLoc(), BI->getType(), ResVal); } +static SILValue specializePolymorphicBuiltin(BuiltinInst *bi, + BuiltinValueKind id) { + // If we are not a polymorphic builtin, return an empty SILValue() + // so we keep on scanning. + if (!isPolymorphicBuiltin(id)) + return SILValue(); + + // Otherwise, try to perform the mapping. + if (auto newBuiltin = getStaticOverloadForSpecializedPolymorphicBuiltin(bi)) + return newBuiltin; + + return SILValue(); +} + /// Fold binary operations. /// /// The list of operations we constant fold might not be complete. Start with @@ -1201,9 +1216,8 @@ static SILValue constantFoldBuiltin(BuiltinInst *BI, #include "swift/AST/Builtins.def" return constantFoldBinaryWithOverflow(BI, Builtin.ID, ResultsInError); -#define BUILTIN(id, name, Attrs) -#define BUILTIN_BINARY_OPERATION(id, name, attrs, overload) \ -case BuiltinValueKind::id: +#define BUILTIN(id, name, attrs) +#define BUILTIN_BINARY_OPERATION(id, name, attrs) case BuiltinValueKind::id: #include "swift/AST/Builtins.def" return constantFoldBinary(BI, Builtin.ID, ResultsInError); @@ -1594,6 +1608,15 @@ void ConstantFolder::initializeWorklist(SILFunction &f) { continue; } + if (auto *bi = dyn_cast(inst)) { + if (auto kind = bi->getBuiltinKind()) { + if (isPolymorphicBuiltin(kind.getValue())) { + WorkList.insert(bi); + continue; + } + } + } + // If we have nominal type literals like struct, tuple, enum visit them // like we do in the worklist to see if we can fold any projection // manipulation operations. @@ -1805,6 +1828,21 @@ ConstantFolder::processWorkList() { continue; } + if (auto *bi = dyn_cast(I)) { + if (auto kind = bi->getBuiltinKind()) { + if (SILValue v = specializePolymorphicBuiltin(bi, kind.getValue())) { + // If bi had a result, RAUW. + if (bi->getResult(0)->getType() != + bi->getModule().Types.getEmptyTupleType()) + bi->replaceAllUsesWith(v); + // Then delete no matter what. + bi->eraseFromParent(); + InvalidateInstructions = true; + continue; + } + } + } + // Go through all users of the constant and try to fold them. FoldedUsers.clear(); for (auto Result : I->getResults()) { diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index b956ec2d814d5..d497efe6e7d65 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -1740,8 +1740,6 @@ namespace { return nullptr; } - tc.validateDecl(fn); - // Form a reference to the function. The bridging operations are generic, // so we need to form substitutions and compute the resulting type. auto genericSig = fn->getGenericSignature(); @@ -1920,14 +1918,13 @@ namespace { auto maxFloatTypeDecl = tc.Context.get_MaxBuiltinFloatTypeDecl(); if (!maxFloatTypeDecl || - !maxFloatTypeDecl->hasInterfaceType() || + !maxFloatTypeDecl->getInterfaceType() || !maxFloatTypeDecl->getDeclaredInterfaceType()->is()) { tc.diagnose(expr->getLoc(), diag::no_MaxBuiltinFloatType_found); return nullptr; } - tc.validateDecl(maxFloatTypeDecl); - auto maxType = maxFloatTypeDecl->getUnderlyingTypeLoc().getType(); + auto maxType = maxFloatTypeDecl->getUnderlyingType(); DeclName initName(tc.Context, DeclBaseName::createConstructor(), { tc.Context.Id_floatLiteral }); @@ -4154,7 +4151,6 @@ namespace { assert(method && "Didn't find a method?"); // The declaration we found must be exposed to Objective-C. - tc.validateDecl(method); if (!method->isObjC()) { // If the method declaration lies in a protocol and we're providing // a default implementation of the method through a protocol extension @@ -5422,10 +5418,11 @@ Expr *ExprRewriter::coerceCallArguments( auto params = funcType->getParams(); // Local function to produce a locator to refer to the given parameter. - auto getArgLocator = [&](unsigned argIdx, unsigned paramIdx) - -> ConstraintLocatorBuilder { + auto getArgLocator = + [&](unsigned argIdx, unsigned paramIdx, + ParameterTypeFlags flags) -> ConstraintLocatorBuilder { return locator.withPathElement( - LocatorPathElt::ApplyArgToParam(argIdx, paramIdx)); + LocatorPathElt::ApplyArgToParam(argIdx, paramIdx, flags)); }; bool matchCanFail = @@ -5537,8 +5534,9 @@ Expr *ExprRewriter::coerceCallArguments( } // Convert the argument. - auto convertedArg = coerceToType(arg, param.getPlainType(), - getArgLocator(argIdx, paramIdx)); + auto convertedArg = coerceToType( + arg, param.getPlainType(), + getArgLocator(argIdx, paramIdx, param.getParameterFlags())); if (!convertedArg) return nullptr; @@ -5658,8 +5656,9 @@ Expr *ExprRewriter::coerceCallArguments( convertedArg = cs.TC.buildAutoClosureExpr(dc, arg, closureType); cs.cacheExprTypes(convertedArg); } else { - convertedArg = - coerceToType(arg, paramType, getArgLocator(argIdx, paramIdx)); + convertedArg = coerceToType( + arg, paramType, + getArgLocator(argIdx, paramIdx, param.getParameterFlags())); } if (!convertedArg) diff --git a/lib/Sema/CSDiag.cpp b/lib/Sema/CSDiag.cpp index e737abaf6f3c8..6e417ceec39cd 100644 --- a/lib/Sema/CSDiag.cpp +++ b/lib/Sema/CSDiag.cpp @@ -74,202 +74,6 @@ static bool isUnresolvedOrTypeVarType(Type ty) { return ty->isTypeVariableOrMember() || ty->is(); } -/// Given a subpath of an old locator, compute its summary flags. -static unsigned recomputeSummaryFlags(ConstraintLocator *oldLocator, - ArrayRef path) { - if (oldLocator->getSummaryFlags() != 0) - return ConstraintLocator::getSummaryFlagsForPath(path); - return 0; -} - -ConstraintLocator * -constraints::simplifyLocator(ConstraintSystem &cs, ConstraintLocator *locator, - SourceRange &range) { - auto path = locator->getPath(); - auto anchor = locator->getAnchor(); - simplifyLocator(anchor, path, range); - - // If we didn't simplify anything, just return the input. - if (anchor == locator->getAnchor() && - path.size() == locator->getPath().size()) { - return locator; - } - - // Recompute the summary flags if we had any to begin with. This is - // necessary because we might remove e.g. tuple elements from the path. - unsigned summaryFlags = recomputeSummaryFlags(locator, path); - return cs.getConstraintLocator(anchor, path, summaryFlags); -} - -void constraints::simplifyLocator(Expr *&anchor, - ArrayRef &path, - SourceRange &range) { - range = SourceRange(); - - while (!path.empty()) { - switch (path[0].getKind()) { - case ConstraintLocator::ApplyArgument: { - // Extract application argument. - if (auto applyExpr = dyn_cast(anchor)) { - anchor = applyExpr->getArg(); - path = path.slice(1); - continue; - } - - if (auto subscriptExpr = dyn_cast(anchor)) { - anchor = subscriptExpr->getIndex(); - path = path.slice(1); - continue; - } - - if (auto objectLiteralExpr = dyn_cast(anchor)) { - anchor = objectLiteralExpr->getArg(); - path = path.slice(1); - continue; - } - - if (auto *UME = dyn_cast(anchor)) { - anchor = UME->getArgument(); - path = path.slice(1); - continue; - } - break; - } - - case ConstraintLocator::ApplyFunction: - // Extract application function. - if (auto applyExpr = dyn_cast(anchor)) { - anchor = applyExpr->getFn(); - path = path.slice(1); - continue; - } - - // The subscript itself is the function. - if (auto subscriptExpr = dyn_cast(anchor)) { - anchor = subscriptExpr; - path = path.slice(1); - continue; - } - - // The unresolved member itself is the function. - if (auto unresolvedMember = dyn_cast(anchor)) { - if (unresolvedMember->getArgument()) { - anchor = unresolvedMember; - path = path.slice(1); - continue; - } - } - - break; - - case ConstraintLocator::AutoclosureResult: - case ConstraintLocator::LValueConversion: - case ConstraintLocator::RValueAdjustment: - case ConstraintLocator::UnresolvedMember: - // Arguments in autoclosure positions, lvalue and rvalue adjustments, and - // scalar-to-tuple conversions, and unresolved members are - // implicit. - path = path.slice(1); - continue; - - case ConstraintLocator::NamedTupleElement: - case ConstraintLocator::TupleElement: { - // Extract tuple element. - auto elt = path[0].castTo(); - unsigned index = elt.getIndex(); - if (auto tupleExpr = dyn_cast(anchor)) { - if (index < tupleExpr->getNumElements()) { - anchor = tupleExpr->getElement(index); - path = path.slice(1); - continue; - } - } - - if (auto *CE = dyn_cast(anchor)) { - if (index < CE->getNumElements()) { - anchor = CE->getElement(index); - path = path.slice(1); - continue; - } - } - break; - } - - case ConstraintLocator::ApplyArgToParam: { - auto elt = path[0].castTo(); - // Extract tuple element. - if (auto tupleExpr = dyn_cast(anchor)) { - unsigned index = elt.getArgIdx(); - if (index < tupleExpr->getNumElements()) { - anchor = tupleExpr->getElement(index); - path = path.slice(1); - continue; - } - } - - // Extract subexpression in parentheses. - if (auto parenExpr = dyn_cast(anchor)) { - assert(elt.getArgIdx() == 0); - - anchor = parenExpr->getSubExpr(); - path = path.slice(1); - continue; - } - break; - } - case ConstraintLocator::ConstructorMember: - if (auto typeExpr = dyn_cast(anchor)) { - // This is really an implicit 'init' MemberRef, so point at the base, - // i.e. the TypeExpr. - range = SourceRange(); - anchor = typeExpr; - path = path.slice(1); - continue; - } - LLVM_FALLTHROUGH; - - case ConstraintLocator::Member: - case ConstraintLocator::MemberRefBase: - if (auto UDE = dyn_cast(anchor)) { - range = UDE->getNameLoc().getSourceRange(); - anchor = UDE->getBase(); - path = path.slice(1); - continue; - } - break; - - case ConstraintLocator::SubscriptMember: - if (isa(anchor)) { - path = path.slice(1); - continue; - } - break; - - case ConstraintLocator::ClosureResult: - if (auto CE = dyn_cast(anchor)) { - if (CE->hasSingleExpressionBody()) { - anchor = CE->getSingleExpressionBody(); - path = path.slice(1); - continue; - } - } - break; - - case ConstraintLocator::ContextualType: - // This was just for identifying purposes, strip it off. - path = path.slice(1); - continue; - - default: - // FIXME: Lots of other cases to handle. - break; - } - - // If we get here, we couldn't simplify the path further. - break; - } -} - /// Flags that can be used to control name lookup. enum TCCFlags { /// Allow the result of the subexpression to be an lvalue. If this is not @@ -1528,7 +1332,7 @@ DeclContext *FailureDiagnosis::findDeclContext(Expr *subExpr) const { // variables would be accessible to name lookup of the subexpression and // may thus leak in. Reset them to UnresolvedTypes for safe measures. assert(llvm::all_of(*closure->getParameters(), [](const ParamDecl *PD) { - if (PD->hasValidSignature()) { + if (PD->hasInterfaceType()) { auto paramTy = PD->getType(); return !(paramTy->hasTypeVariable() || paramTy->hasError()); } @@ -3660,11 +3464,16 @@ bool FailureDiagnosis::visitApplyExpr(ApplyExpr *callExpr) { // case (let (_, _, _)) + 1: break // } if (callExpr->isImplicit() && overloadName == "~=") { - auto *locator = - CS.getConstraintLocator(callExpr, - {ConstraintLocator::ApplyArgument, - LocatorPathElt::ApplyArgToParam(0, 0)}, - /*summaryFlags=*/0); + auto flags = ParameterTypeFlags(); + if (calleeInfo.candidates.size() == 1) + if (auto fnType = calleeInfo.candidates[0].getFunctionType()) + flags = fnType->getParams()[0].getParameterFlags(); + + auto *locator = CS.getConstraintLocator( + callExpr, + {ConstraintLocator::ApplyArgument, + LocatorPathElt::ApplyArgToParam(0, 0, flags)}, + /*summaryFlags=*/0); ArgumentMismatchFailure failure(expr, CS, lhsType, rhsType, locator); return failure.diagnosePatternMatchingMismatch(); @@ -4094,10 +3903,8 @@ bool FailureDiagnosis::diagnoseClosureExpr( return true; } - MissingArgumentsFailure failure( - expr, CS, fnType, inferredArgCount - actualArgCount, - CS.getConstraintLocator(CE, LocatorPathElt::ContextualType())); - return failure.diagnoseAsError(); + // Missing arguments are already diagnosed via new diagnostic framework. + return false; } // Coerce parameter types here only if there are no unresolved @@ -4501,8 +4308,6 @@ static bool diagnoseKeyPathComponents(ConstraintSystem &CS, KeyPathExpr *KPE, // Handle property references. if (auto var = dyn_cast(found)) { - TC.validateDecl(var); - // Resolve this component to the variable we found. auto varRef = ConcreteDeclRef(var); auto resolved = @@ -5558,7 +5363,7 @@ diagnoseAmbiguousMultiStatementClosure(ClosureExpr *closure) { if (auto DRE = dyn_cast(childExpr)) { if (auto param = dyn_cast(DRE->getDecl())) { auto paramType = - param->hasValidSignature() ? param->getType() : Type(); + param->hasInterfaceType() ? param->getType() : Type(); if (!paramType || paramType->hasTypeVariable()) { hasUnresolvedParams = true; return nullptr; diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index 3694b156d5f88..ae75692c66324 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -28,6 +28,7 @@ #include "swift/AST/Pattern.h" #include "swift/AST/ProtocolConformance.h" #include "swift/AST/ProtocolConformanceRef.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/Stmt.h" #include "swift/AST/Types.h" #include "swift/Basic/SourceLoc.h" @@ -594,16 +595,18 @@ bool MissingConformanceFailure::diagnoseAsError() { } } - if (nonConformingType->isExistentialType()) { - auto diagnostic = diag::protocol_does_not_conform_objc; - if (nonConformingType->isObjCExistentialType()) - diagnostic = diag::protocol_does_not_conform_static; - - emitDiagnostic(anchor->getLoc(), diagnostic, nonConformingType, - protocolType); + if (nonConformingType->isObjCExistentialType()) { + emitDiagnostic(anchor->getLoc(), diag::protocol_does_not_conform_static, + nonConformingType, protocolType); return true; } + if (diagnoseTypeCannotConform((atParameterPos ? + getArgumentAt(Apply, *atParameterPos) : anchor), + nonConformingType, protocolType)) { + return true; + } + if (atParameterPos) { // Requirement comes from one of the parameter types, // let's try to point diagnostic to the argument expression. @@ -619,6 +622,58 @@ bool MissingConformanceFailure::diagnoseAsError() { return RequirementFailure::diagnoseAsError(); } +bool MissingConformanceFailure::diagnoseTypeCannotConform(Expr *anchor, + Type nonConformingType, Type protocolType) const { + if (!(nonConformingType->is() || + nonConformingType->is() || + nonConformingType->isExistentialType() || + nonConformingType->is())) { + return false; + } + + emitDiagnostic(anchor->getLoc(), diag::type_cannot_conform, + nonConformingType->isExistentialType(), nonConformingType, + protocolType); + + if (auto *OTD = dyn_cast(AffectedDecl)) { + auto *namingDecl = OTD->getNamingDecl(); + if (auto *repr = namingDecl->getOpaqueResultTypeRepr()) { + emitDiagnostic(repr->getLoc(), diag::required_by_opaque_return, + namingDecl->getDescriptiveKind(), namingDecl->getFullName()) + .highlight(repr->getSourceRange()); + } + return true; + } + + auto &req = getRequirement(); + auto *reqDC = getRequirementDC(); + auto *genericCtx = getGenericContext(); + auto noteLocation = reqDC->getAsDecl()->getLoc(); + + if (!noteLocation.isValid()) + noteLocation = anchor->getLoc(); + + if (isConditional()) { + emitDiagnostic(noteLocation, diag::requirement_implied_by_conditional_conformance, + resolveType(Conformance->getType()), + Conformance->getProtocol()->getDeclaredInterfaceType()); + } else if (genericCtx != reqDC && (genericCtx->isChildContextOf(reqDC) || + isStaticOrInstanceMember(AffectedDecl))) { + emitDiagnostic(noteLocation, diag::required_by_decl_ref, + AffectedDecl->getDescriptiveKind(), + AffectedDecl->getFullName(), + reqDC->getSelfNominalTypeDecl()->getDeclaredType(), + req.getFirstType(), nonConformingType); + } else { + emitDiagnostic(noteLocation, diag::required_by_decl, + AffectedDecl->getDescriptiveKind(), + AffectedDecl->getFullName(), req.getFirstType(), + nonConformingType); + } + + return true; +} + bool MissingConformanceFailure::diagnoseAsAmbiguousOperatorRef() { auto *anchor = getRawAnchor(); auto *ODRE = dyn_cast(anchor); @@ -694,6 +749,8 @@ Optional> GenericArgumentsMismatchFailure::getDiagnosticFor( return diag::cannot_convert_coerce; case CTP_SubscriptAssignSource: return diag::cannot_convert_subscript_assign; + case CTP_Condition: + return diag::cannot_convert_condition_value; case CTP_ThrowStmt: case CTP_Unused: @@ -1294,6 +1351,13 @@ bool RValueTreatedAsLValueFailure::diagnoseAsError() { Expr *diagExpr = getRawAnchor(); SourceLoc loc = diagExpr->getLoc(); + auto &cs = getConstraintSystem(); + // Assignment is not allowed inside of a condition, + // so let's not diagnose immutability, because + // most likely the problem is related to use of `=` itself. + if (cs.getContextualTypePurpose() == CTP_Condition) + return false; + if (auto assignExpr = dyn_cast(diagExpr)) { diagExpr = assignExpr->getDest(); } @@ -1411,7 +1475,7 @@ bool TrailingClosureAmbiguityFailure::diagnoseAsNote() { const ParamDecl *param = paramList->getArray().back(); // Sanity-check that the trailing closure corresponds to this parameter. - if (!param->hasValidSignature() || + if (!param->hasInterfaceType() || !param->getInterfaceType()->is()) return false; @@ -1956,6 +2020,8 @@ getContextualNilDiagnostic(ContextualTypePurpose CTP) { return diag::cannot_convert_assign_nil; case CTP_SubscriptAssignSource: return diag::cannot_convert_subscript_assign_nil; + case CTP_Condition: + return diag::cannot_convert_condition_value_nil; } llvm_unreachable("Unhandled ContextualTypePurpose in switch"); } @@ -2020,8 +2086,10 @@ bool ContextualFailure::diagnoseConversionToNil() const { } // `nil` is passed as an argument to a parameter which doesn't - // expect it e.g. `foo(a: nil)` or `s[x: nil]`. - if (isa(enclosingExpr) || isa(enclosingExpr)) + // expect it e.g. `foo(a: nil)`, `s[x: nil]` or `\S.[x: nil]`. + // FIXME: Find a more robust way of checking this. + if (isa(enclosingExpr) || isa(enclosingExpr) || + isa(enclosingExpr)) CTP = CTP_CallArgument; } else if (auto *CE = dyn_cast(parentExpr)) { // `nil` is passed as a left-hand side of the coercion @@ -2691,6 +2759,8 @@ ContextualFailure::getDiagnosticFor(ContextualTypePurpose context, case CTP_SubscriptAssignSource: return forProtocol ? diag::cannot_convert_subscript_assign_protocol : diag::cannot_convert_subscript_assign; + case CTP_Condition: + return diag::cannot_convert_condition_value; case CTP_ThrowStmt: case CTP_Unused: @@ -3506,14 +3576,31 @@ bool MissingArgumentsFailure::diagnoseAsError() { path.back().getKind() == ConstraintLocator::ContextualType)) return false; - if (auto *closure = dyn_cast(getAnchor())) - return diagnoseTrailingClosure(closure); + auto *anchor = getAnchor(); + if (auto *captureList = dyn_cast(anchor)) + anchor = captureList->getClosureBody(); + + if (auto *closure = dyn_cast(anchor)) + return diagnoseClosure(closure); return false; } -bool MissingArgumentsFailure::diagnoseTrailingClosure(ClosureExpr *closure) { - auto diff = Fn->getNumParams() - NumSynthesized; +bool MissingArgumentsFailure::diagnoseClosure(ClosureExpr *closure) { + auto &cs = getConstraintSystem(); + FunctionType *funcType = nullptr; + + auto *locator = getLocator(); + if (locator->isForContextualType()) { + funcType = cs.getContextualType()->getAs(); + } else if (auto info = getFunctionArgApplyInfo(locator)) { + funcType = info->getParamType()->getAs(); + } + + if (!funcType) + return false; + + auto diff = funcType->getNumParams() - NumSynthesized; // If the closure didn't specify any arguments and it is in a context that // needs some, produce a fixit to turn "{...}" into "{ _,_ in ...}". @@ -3523,10 +3610,10 @@ bool MissingArgumentsFailure::diagnoseTrailingClosure(ClosureExpr *closure) { diag::closure_argument_list_missing, NumSynthesized); std::string fixText; // Let's provide fixits for up to 10 args. - if (Fn->getNumParams() <= 10) { + if (funcType->getNumParams() <= 10) { fixText += " "; interleave( - Fn->getParams(), + funcType->getParams(), [&fixText](const AnyFunctionType::Param ¶m) { fixText += '_'; }, [&fixText] { fixText += ','; }); fixText += " in "; @@ -3552,9 +3639,9 @@ bool MissingArgumentsFailure::diagnoseTrailingClosure(ClosureExpr *closure) { std::all_of(params->begin(), params->end(), [](ParamDecl *param) { return !param->hasName(); }); - auto diag = - emitDiagnostic(params->getStartLoc(), diag::closure_argument_list_tuple, - resolveType(Fn), Fn->getNumParams(), diff, diff == 1); + auto diag = emitDiagnostic( + params->getStartLoc(), diag::closure_argument_list_tuple, + resolveType(funcType), funcType->getNumParams(), diff, diff == 1); // If the number of parameters is less than number of inferred // let's try to suggest a fix-it with the rest of the missing parameters. @@ -4593,9 +4680,11 @@ bool ArgumentMismatchFailure::diagnoseUseOfReferenceEqualityOperator() const { // one would cover both arguments. if (getAnchor() == rhs && rhsType->is()) { auto &cs = getConstraintSystem(); - if (cs.hasFixFor(cs.getConstraintLocator( - binaryOp, {ConstraintLocator::ApplyArgument, - LocatorPathElt::ApplyArgToParam(0, 0)}))) + auto info = getFunctionArgApplyInfo(locator); + if (info && cs.hasFixFor(cs.getConstraintLocator( + binaryOp, {ConstraintLocator::ApplyArgument, + LocatorPathElt::ApplyArgToParam( + 0, 0, info->getParameterFlagsAtIndex(0))}))) return true; } @@ -4745,3 +4834,44 @@ bool ArgumentMismatchFailure::diagnoseArchetypeMismatch() const { return true; } + +void ExpandArrayIntoVarargsFailure::tryDropArrayBracketsFixIt( + Expr *anchor) const { + // If this is an array literal, offer to remove the brackets and pass the + // elements directly as variadic arguments. + if (auto *arrayExpr = dyn_cast(anchor)) { + auto diag = emitDiagnostic(arrayExpr->getLoc(), + diag::suggest_pass_elements_directly); + diag.fixItRemove(arrayExpr->getLBracketLoc()) + .fixItRemove(arrayExpr->getRBracketLoc()); + // Handle the case where the array literal has a trailing comma. + if (arrayExpr->getNumCommas() == arrayExpr->getNumElements()) + diag.fixItRemove(arrayExpr->getCommaLocs().back()); + } +} + +bool ExpandArrayIntoVarargsFailure::diagnoseAsError() { + if (auto anchor = getAnchor()) { + emitDiagnostic(anchor->getLoc(), diag::cannot_convert_array_to_variadic, + getFromType(), getToType()); + tryDropArrayBracketsFixIt(anchor); + // TODO: Array splat fix-it once that's supported. + return true; + } + return false; +} + +bool ExpandArrayIntoVarargsFailure::diagnoseAsNote() { + auto overload = getChoiceFor(getLocator()); + auto anchor = getAnchor(); + if (!overload || !anchor) + return false; + + if (auto chosenDecl = overload->choice.getDeclOrNull()) { + emitDiagnostic(chosenDecl, diag::candidate_would_match_array_to_variadic, + getToType()); + tryDropArrayBracketsFixIt(anchor); + return true; + } + return false; +} diff --git a/lib/Sema/CSDiagnostics.h b/lib/Sema/CSDiagnostics.h index 264f2020ca790..a0a4fdc180786 100644 --- a/lib/Sema/CSDiagnostics.h +++ b/lib/Sema/CSDiagnostics.h @@ -290,6 +290,10 @@ class RequirementFailure : public FailureDiagnostic { isa(apply); } + /// Determine whether given declaration represents a static + /// or instance property/method, excluding operators. + static bool isStaticOrInstanceMember(const ValueDecl *decl); + private: /// Retrieve declaration associated with failing generic requirement. ValueDecl *getDeclRef() const; @@ -299,10 +303,6 @@ class RequirementFailure : public FailureDiagnostic { void emitRequirementNote(const Decl *anchor, Type lhs, Type rhs) const; - /// Determine whether given declaration represents a static - /// or instance property/method, excluding operators. - static bool isStaticOrInstanceMember(const ValueDecl *decl); - /// If this is a failure in conditional requirement, retrieve /// conformance information. ProtocolConformance * @@ -346,6 +346,10 @@ class MissingConformanceFailure final : public RequirementFailure { DiagAsNote getDiagnosticAsNote() const override { return diag::candidate_types_conformance_requirement; } + +private: + bool diagnoseTypeCannotConform(Expr *anchor, Type nonConformingType, + Type protocolType) const; }; /// Diagnose failures related to same-type generic requirements, e.g. @@ -1182,23 +1186,19 @@ class ImplicitInitOnNonConstMetatypeFailure final class MissingArgumentsFailure final : public FailureDiagnostic { using Param = AnyFunctionType::Param; - FunctionType *Fn; unsigned NumSynthesized; public: MissingArgumentsFailure(Expr *root, ConstraintSystem &cs, - FunctionType *funcType, - unsigned numSynthesized, - ConstraintLocator *locator) - : FailureDiagnostic(root, cs, locator), Fn(funcType), - NumSynthesized(numSynthesized) {} + unsigned numSynthesized, ConstraintLocator *locator) + : FailureDiagnostic(root, cs, locator), NumSynthesized(numSynthesized) {} bool diagnoseAsError() override; private: - /// If missing arguments come from trailing closure, + /// If missing arguments come from a closure, /// let's produce tailored diagnostics. - bool diagnoseTrailingClosure(ClosureExpr *closure); + bool diagnoseClosure(ClosureExpr *closure); }; class OutOfOrderArgumentFailure final : public FailureDiagnostic { @@ -1586,8 +1586,25 @@ class InvalidTupleSplatWithSingleParameterFailure final Type paramTy, ConstraintLocator *locator) : FailureDiagnostic(root, cs, locator), ParamType(paramTy) {} + bool diagnoseAsError() override; +}; + +/// Diagnose situation when an array is passed instead of varargs. +/// +/// ```swift +/// func foo(_ x: Int...) {} +/// foo([1,2,3]]) // foo expects varags like foo(1,2,3) instead. +/// ``` +class ExpandArrayIntoVarargsFailure final : public ContextualFailure { +public: + ExpandArrayIntoVarargsFailure(Expr *root, ConstraintSystem &cs, Type lhs, + Type rhs, ConstraintLocator *locator) + : ContextualFailure(root, cs, lhs, rhs, locator) {} bool diagnoseAsError() override; + bool diagnoseAsNote() override; + + void tryDropArrayBracketsFixIt(Expr *anchor) const; }; /// Diagnose a situation there is a mismatch between argument and parameter @@ -1719,6 +1736,10 @@ class FunctionArgApplyInfo { ParameterTypeFlags getParameterFlags() const { return FnType->getParams()[ParamIdx].getParameterFlags(); } + + ParameterTypeFlags getParameterFlagsAtIndex(unsigned idx) const { + return FnType->getParams()[idx].getParameterFlags(); + } }; } // end namespace constraints diff --git a/lib/Sema/CSFix.cpp b/lib/Sema/CSFix.cpp index c351ce41b2035..625f4b9a79ff7 100644 --- a/lib/Sema/CSFix.cpp +++ b/lib/Sema/CSFix.cpp @@ -477,18 +477,18 @@ AllowClosureParamDestructuring::create(ConstraintSystem &cs, } bool AddMissingArguments::diagnose(Expr *root, bool asNote) const { - MissingArgumentsFailure failure(root, getConstraintSystem(), Fn, - NumSynthesized, getLocator()); + auto &cs = getConstraintSystem(); + MissingArgumentsFailure failure(root, cs, NumSynthesized, getLocator()); return failure.diagnose(asNote); } AddMissingArguments * -AddMissingArguments::create(ConstraintSystem &cs, FunctionType *funcType, +AddMissingArguments::create(ConstraintSystem &cs, llvm::ArrayRef synthesizedArgs, ConstraintLocator *locator) { unsigned size = totalSizeToAlloc(synthesizedArgs.size()); void *mem = cs.getAllocator().Allocate(size, alignof(AddMissingArguments)); - return new (mem) AddMissingArguments(cs, funcType, synthesizedArgs, locator); + return new (mem) AddMissingArguments(cs, synthesizedArgs, locator); } bool MoveOutOfOrderArgument::diagnose(Expr *root, bool asNote) const { @@ -759,6 +759,26 @@ IgnoreContextualType *IgnoreContextualType::create(ConstraintSystem &cs, IgnoreContextualType(cs, resultTy, specifiedTy, locator); } +bool IgnoreAssignmentDestinationType::diagnose(Expr *root, bool asNote) const { + auto &cs = getConstraintSystem(); + auto *AE = cast(getAnchor()); + auto CTP = isa(AE->getDest()) ? CTP_SubscriptAssignSource + : CTP_AssignSource; + + ContextualFailure failure( + root, cs, CTP, getFromType(), getToType(), + cs.getConstraintLocator(AE->getSrc(), LocatorPathElt::ContextualType())); + return failure.diagnose(asNote); +} + +IgnoreAssignmentDestinationType * +IgnoreAssignmentDestinationType::create(ConstraintSystem &cs, Type sourceTy, + Type destTy, + ConstraintLocator *locator) { + return new (cs.getAllocator()) + IgnoreAssignmentDestinationType(cs, sourceTy, destTy, locator); +} + bool AllowInOutConversion::diagnose(Expr *root, bool asNote) const { auto &cs = getConstraintSystem(); InOutConversionFailure failure(root, cs, getFromType(), getToType(), @@ -795,6 +815,36 @@ static bool isValueOfRawRepresentable(ConstraintSystem &cs, return false; } +ExpandArrayIntoVarargs * +ExpandArrayIntoVarargs::attempt(ConstraintSystem &cs, Type argType, + Type paramType, + ConstraintLocatorBuilder locator) { + auto constraintLocator = cs.getConstraintLocator(locator); + auto elementType = cs.isArrayType(argType); + if (elementType && + constraintLocator->getLastElementAs() + ->getParameterFlags() + .isVariadic()) { + auto options = ConstraintSystem::TypeMatchOptions( + ConstraintSystem::TypeMatchFlags::TMF_ApplyingFix | + ConstraintSystem::TypeMatchFlags::TMF_GenerateConstraints); + auto result = + cs.matchTypes(*elementType, paramType, + ConstraintKind::ArgumentConversion, options, locator); + if (result.isSuccess()) + return new (cs.getAllocator()) + ExpandArrayIntoVarargs(cs, argType, paramType, constraintLocator); + } + + return nullptr; +} + +bool ExpandArrayIntoVarargs::diagnose(Expr *root, bool asNote) const { + ExpandArrayIntoVarargsFailure failure( + root, getConstraintSystem(), getFromType(), getToType(), getLocator()); + return failure.diagnose(asNote); +} + ExplicitlyConstructRawRepresentable * ExplicitlyConstructRawRepresentable::attempt(ConstraintSystem &cs, Type argType, Type paramType, diff --git a/lib/Sema/CSFix.h b/lib/Sema/CSFix.h index bb86cac4d713b..28867744468ea 100644 --- a/lib/Sema/CSFix.h +++ b/lib/Sema/CSFix.h @@ -204,6 +204,9 @@ enum class FixKind : uint8_t { /// Use raw value type associated with raw representative accessible /// using `.rawValue` member. UseValueTypeOfRawRepresentative, + /// If an array was passed to a variadic argument, give a specific diagnostic + /// and offer to drop the brackets if it's a literal. + ExpandArrayIntoVarargs, }; class ConstraintFix { @@ -1001,13 +1004,12 @@ class AddMissingArguments final using Param = AnyFunctionType::Param; - FunctionType *Fn; unsigned NumSynthesized; - AddMissingArguments(ConstraintSystem &cs, FunctionType *funcType, - llvm::ArrayRef synthesizedArgs, + AddMissingArguments(ConstraintSystem &cs, + llvm::ArrayRef synthesizedArgs, ConstraintLocator *locator) - : ConstraintFix(cs, FixKind::AddMissingArguments, locator), Fn(funcType), + : ConstraintFix(cs, FixKind::AddMissingArguments, locator), NumSynthesized(synthesizedArgs.size()) { std::uninitialized_copy(synthesizedArgs.begin(), synthesizedArgs.end(), getSynthesizedArgumentsBuf().begin()); @@ -1022,7 +1024,7 @@ class AddMissingArguments final bool diagnose(Expr *root, bool asNote = false) const override; - static AddMissingArguments *create(ConstraintSystem &cs, FunctionType *fnType, + static AddMissingArguments *create(ConstraintSystem &cs, llvm::ArrayRef synthesizedArgs, ConstraintLocator *locator); @@ -1300,6 +1302,23 @@ class IgnoreContextualType : public ContextualMismatch { ConstraintLocator *locator); }; +class IgnoreAssignmentDestinationType final : public ContextualMismatch { + IgnoreAssignmentDestinationType(ConstraintSystem &cs, Type sourceTy, + Type destTy, ConstraintLocator *locator) + : ContextualMismatch(cs, sourceTy, destTy, locator) {} + +public: + std::string getName() const override { + return "ignore type of the assignment destination"; + } + + bool diagnose(Expr *root, bool asNote = false) const override; + + static IgnoreAssignmentDestinationType *create(ConstraintSystem &cs, + Type sourceTy, Type destTy, + ConstraintLocator *locator); +}; + /// If this is an argument-to-parameter conversion which is associated with /// `inout` parameter, subtyping is not permitted, types have to /// be identical. @@ -1343,6 +1362,25 @@ class AllowArgumentMismatch : public ContextualMismatch { ConstraintLocator *locator); }; +class ExpandArrayIntoVarargs final : public AllowArgumentMismatch { + + ExpandArrayIntoVarargs(ConstraintSystem &cs, Type argType, Type paramType, + ConstraintLocator *locator) + : AllowArgumentMismatch(cs, FixKind::ExpandArrayIntoVarargs, argType, + paramType, locator) {} + +public: + std::string getName() const override { + return "cannot pass Array elements as variadic arguments"; + } + + bool diagnose(Expr *root, bool asNote = false) const override; + + static ExpandArrayIntoVarargs *attempt(ConstraintSystem &cs, Type argType, + Type paramType, + ConstraintLocatorBuilder locator); +}; + class ExplicitlyConstructRawRepresentable final : public AllowArgumentMismatch { ExplicitlyConstructRawRepresentable(ConstraintSystem &cs, Type argType, Type paramType, diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index e9cb845b282b9..05ea0770b5ee4 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -962,7 +962,8 @@ namespace { if (!decl) return nullptr; - CS.getTypeChecker().validateDecl(decl); + // FIXME(InterfaceTypeRequest): isInvalid() should be based on the interface type. + (void)decl->getInterfaceType(); if (decl->isInvalid()) return nullptr; @@ -1327,9 +1328,9 @@ namespace { // FIXME: If the decl is in error, we get no information from this. // We may, alternatively, want to use a type variable in that case, // and possibly infer the type of the variable that way. - CS.getTypeChecker().validateDecl(E->getDecl()); + auto oldInterfaceTy = E->getDecl()->getInterfaceType(); if (E->getDecl()->isInvalid()) { - CS.setType(E, E->getDecl()->getInterfaceType()); + CS.setType(E, oldInterfaceTy); return nullptr; } @@ -1442,7 +1443,8 @@ namespace { // If the result is invalid, skip it. // FIXME: Note this as invalid, in case we don't find a solution, // so we don't let errors cascade further. - CS.getTypeChecker().validateDecl(decls[i]); + // FIXME(InterfaceTypeRequest): isInvalid() should be based on the interface type. + (void)decls[i]->getInterfaceType(); if (decls[i]->isInvalid()) continue; @@ -2000,7 +2002,6 @@ namespace { if (dictionaryKeyTy->isTypeVariableOrMember() && tc.Context.getAnyHashableDecl()) { auto anyHashable = tc.Context.getAnyHashableDecl(); - tc.validateDecl(anyHashable); CS.addConstraint(ConstraintKind::Defaultable, dictionaryKeyTy, anyHashable->getDeclaredInterfaceType(), locator); } diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index f86a428311668..e3ca52c605ee8 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -913,8 +913,8 @@ ConstraintSystem::TypeMatchResult constraints::matchCallArguments( // Compare each of the bound arguments for this parameter. for (auto argIdx : parameterBindings[paramIdx]) { - auto loc = locator.withPathElement( - LocatorPathElt::ApplyArgToParam(argIdx, paramIdx)); + auto loc = locator.withPathElement(LocatorPathElt::ApplyArgToParam( + argIdx, paramIdx, param.getParameterFlags())); auto argTy = argsWithLabels[argIdx].getOldType(); bool matchingAutoClosureResult = param.isAutoClosure(); @@ -1167,9 +1167,8 @@ static ConstraintFix *fixRequirementFailure(ConstraintSystem &cs, Type type1, /// Attempt to fix missing arguments by introducing type variables /// and inferring their types from parameters. static bool fixMissingArguments(ConstraintSystem &cs, Expr *anchor, - FunctionType *funcType, SmallVectorImpl &args, - SmallVectorImpl ¶ms, + ArrayRef params, unsigned numMissing, ConstraintLocatorBuilder locator) { assert(args.size() < params.size()); @@ -1180,16 +1179,26 @@ static bool fixMissingArguments(ConstraintSystem &cs, Expr *anchor, // tuple e.g. `$0.0`. Optional argumentTuple; if (isa(anchor) && isSingleTupleParam(ctx, args)) { - auto isParam = [](const Expr *expr) { - if (auto *DRE = dyn_cast(expr)) { - if (auto *decl = DRE->getDecl()) - return isa(decl); + auto argType = args.back().getPlainType(); + // Let's unpack argument tuple into N arguments, this corresponds + // to something like `foo { (bar: (Int, Int)) in }` where `foo` + // has a single parameter of type `(Int, Int) -> Void`. + if (auto *tuple = argType->getAs()) { + args.pop_back(); + for (const auto &elt : tuple->getElements()) { + args.push_back(AnyFunctionType::Param(elt.getType(), elt.getName(), + elt.getParameterFlags())); } - return false; - }; + } else if (auto *typeVar = argType->getAs()) { + auto isParam = [](const Expr *expr) { + if (auto *DRE = dyn_cast(expr)) { + if (auto *decl = DRE->getDecl()) + return isa(decl); + } + return false; + }; - const auto &arg = args.back(); - if (auto *argTy = arg.getPlainType()->getAs()) { + // Something like `foo { x in }` or `foo { $0 }` anchor->forEachChildExpr([&](Expr *expr) -> Expr * { if (auto *UDE = dyn_cast(expr)) { if (!isParam(UDE->getBase())) @@ -1201,7 +1210,7 @@ static bool fixMissingArguments(ConstraintSystem &cs, Expr *anchor, llvm::any_of(params, [&](const AnyFunctionType::Param ¶m) { return param.getLabel() == name; })) { - argumentTuple.emplace(argTy); + argumentTuple.emplace(typeVar); args.pop_back(); return nullptr; } @@ -1219,9 +1228,8 @@ static bool fixMissingArguments(ConstraintSystem &cs, Expr *anchor, } ArrayRef argsRef(args); - auto *fix = - AddMissingArguments::create(cs, funcType, argsRef.take_back(numMissing), - cs.getConstraintLocator(locator)); + auto *fix = AddMissingArguments::create(cs, argsRef.take_back(numMissing), + cs.getConstraintLocator(locator)); if (cs.recordFix(fix)) return true; @@ -1459,7 +1467,7 @@ ConstraintSystem::matchFunctionTypes(FunctionType *func1, FunctionType *func2, // If there are missing arguments, let's add them // using parameter as a template. if (diff < 0) { - if (fixMissingArguments(*this, anchor, func2, func1Params, func2Params, + if (fixMissingArguments(*this, anchor, func1Params, func2Params, abs(diff), locator)) return getTypeMatchFailure(argumentLocator); } else { @@ -2136,7 +2144,7 @@ static ConstraintFix *fixPropertyWrapperFailure( }; auto applyFix = [&](Fix fix, VarDecl *decl, Type type) -> ConstraintFix * { - if (!decl->hasValidSignature() || !type) + if (!decl->hasInterfaceType() || !type) return nullptr; if (baseTy->isEqual(type)) @@ -2345,6 +2353,15 @@ bool ConstraintSystem::repairFailures( return false; }; + auto hasConversionOrRestriction = [&](ConversionRestrictionKind kind) { + return llvm::any_of(conversionsOrFixes, + [kind](const RestrictionOrFix correction) { + if (auto restriction = correction.getRestriction()) + return restriction == kind; + return false; + }); + }; + if (path.empty()) { if (!anchor) return false; @@ -2383,20 +2400,39 @@ bool ConstraintSystem::repairFailures( if (repairViaBridgingCast(*this, lhs, rhs, conversionsOrFixes, locator)) return true; + + // If we are trying to assign e.g. `Array` to `Array` let's + // give solver a chance to determine which generic parameters are + // mismatched and produce a fix for that. + if (hasConversionOrRestriction(ConversionRestrictionKind::DeepEquality)) + return false; + + // If the situation has to do with protocol composition types and + // destination doesn't have one of the conformances e.g. source is + // `X & Y` but destination is only `Y` or vice versa, there is a + // tailored "missing conformance" fix for that. + if (hasConversionOrRestriction(ConversionRestrictionKind::Existential)) + return false; + + // If this is an attempt to assign something to a value of optional type + // there is a possiblity that the problem is related to escapiness, so + // fix has to be delayed. + if (hasConversionOrRestriction( + ConversionRestrictionKind::ValueToOptional)) + return false; + + // If the destination of an assignment is l-value type + // it leaves only possible reason for failure - a type mismatch. + if (getType(AE->getDest())->is()) { + conversionsOrFixes.push_back(IgnoreAssignmentDestinationType::create( + *this, lhs, rhs, getConstraintLocator(locator))); + return true; + } } return false; } - auto hasConversionOrRestriction = [&](ConversionRestrictionKind kind) { - return llvm::any_of(conversionsOrFixes, - [kind](const RestrictionOrFix correction) { - if (auto restriction = correction.getRestriction()) - return restriction == kind; - return false; - }); - }; - auto elt = path.back(); switch (elt.getKind()) { case ConstraintLocator::LValueConversion: { @@ -2590,6 +2626,11 @@ bool ConstraintSystem::repairFailures( elt.castTo().getParamIdx() == 1) break; + if (auto *fix = ExpandArrayIntoVarargs::attempt(*this, lhs, rhs, locator)) { + conversionsOrFixes.push_back(fix); + break; + } + if (auto *fix = ExplicitlyConstructRawRepresentable::attempt( *this, lhs, rhs, locator)) { conversionsOrFixes.push_back(fix); @@ -2662,11 +2703,9 @@ bool ConstraintSystem::repairFailures( // But if `T.Element` didn't get resolved to `Void` we'd like // to diagnose this as a missing argument which can't be ignored. if (arg != getTypeVariables().end()) { - auto fnType = FunctionType::get({FunctionType::Param(lhs)}, - getASTContext().TheEmptyTupleType); - conversionsOrFixes.push_back(AddMissingArguments::create( - *this, fnType, {FunctionType::Param(*arg)}, - getConstraintLocator(anchor, path))); + conversionsOrFixes.push_back( + AddMissingArguments::create(*this, {FunctionType::Param(*arg)}, + getConstraintLocator(anchor, path))); } if ((lhs->is() && !rhs->is()) || @@ -4662,7 +4701,8 @@ performMemberLookup(ConstraintKind constraintKind, DeclName memberName, auto decl = candidate.getDecl(); // If the result is invalid, skip it. - TC.validateDecl(decl); + // FIXME(InterfaceTypeRequest): isInvalid() should be based on the interface type. + (void)decl->getInterfaceType(); if (decl->isInvalid()) { result.markErrorAlreadyDiagnosed(); return; @@ -5036,7 +5076,8 @@ performMemberLookup(ConstraintKind constraintKind, DeclName memberName, auto *cand = entry.getValueDecl(); // If the result is invalid, skip it. - TC.validateDecl(cand); + // FIXME(InterfaceTypeRequest): isInvalid() should be based on the interface type. + (void)cand->getInterfaceType(); if (cand->isInvalid()) { result.markErrorAlreadyDiagnosed(); return result; @@ -7020,7 +7061,8 @@ ConstraintSystem::simplifyDynamicCallableApplicableFnConstraint( // Record the 'dynamicallyCall` method overload set. SmallVector choices; for (auto candidate : candidates) { - TC.validateDecl(candidate); + // FIXME(InterfaceTypeRequest): isInvalid() should be based on the interface type. + (void)candidate->getInterfaceType(); if (candidate->isInvalid()) continue; choices.push_back( OverloadChoice(type2, candidate, FunctionRefKind::SingleApply)); @@ -7658,6 +7700,7 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint( case FixKind::SkipUnhandledConstructInFunctionBuilder: case FixKind::UsePropertyWrapper: case FixKind::UseWrappedValue: + case FixKind::ExpandArrayIntoVarargs: case FixKind::UseValueTypeOfRawRepresentative: case FixKind::ExplicitlyConstructRawRepresentable: { return recordFix(fix) ? SolutionKind::Error : SolutionKind::Solved; diff --git a/lib/Sema/CalleeCandidateInfo.cpp b/lib/Sema/CalleeCandidateInfo.cpp index 7cccb629d1adf..9f3add305c261 100644 --- a/lib/Sema/CalleeCandidateInfo.cpp +++ b/lib/Sema/CalleeCandidateInfo.cpp @@ -61,7 +61,7 @@ OverloadCandidate::OverloadCandidate(ValueDecl *decl, bool skipCurriedSelf) : declOrExpr(decl), skipCurriedSelf(skipCurriedSelf), substituted(false) { if (auto *PD = dyn_cast(decl)) { - if (PD->hasValidSignature()) + if (PD->hasInterfaceType()) entityType = PD->getType(); else entityType = PD->getASTContext().TheUnresolvedType; @@ -593,9 +593,7 @@ void CalleeCandidateInfo::collectCalleeCandidates(Expr *fn, auto ctors = TypeChecker::lookupConstructors( CS.DC, instanceType, NameLookupFlags::IgnoreAccessControl); for (auto ctor : ctors) { - if (!ctor.getValueDecl()->hasInterfaceType()) - CS.getTypeChecker().validateDeclForNameLookup(ctor.getValueDecl()); - if (ctor.getValueDecl()->hasInterfaceType()) + if (ctor.getValueDecl()->getInterfaceType()) candidates.push_back({ ctor.getValueDecl(), 1 }); } } diff --git a/lib/Sema/CodeSynthesis.cpp b/lib/Sema/CodeSynthesis.cpp index 66169ecf4ef8b..bf45390cd59dd 100644 --- a/lib/Sema/CodeSynthesis.cpp +++ b/lib/Sema/CodeSynthesis.cpp @@ -29,6 +29,7 @@ #include "swift/AST/ParameterList.h" #include "swift/AST/PrettyStackTrace.h" #include "swift/AST/ProtocolConformance.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/TypeCheckRequests.h" #include "swift/Basic/Defer.h" #include "swift/ClangImporter/ClangModule.h" @@ -212,7 +213,6 @@ static ConstructorDecl *createImplicitConstructor(NominalTypeDecl *decl, accessLevel = std::min(accessLevel, var->getFormalAccess()); - ctx.getLazyResolver()->resolveDeclSignature(var); auto varInterfaceType = var->getValueInterfaceType(); if (var->getAttrs().hasAttribute()) { @@ -545,9 +545,6 @@ synthesizeDesignatedInitOverride(AbstractFunctionDecl *fn, void *context) { auto *superclassCtor = (ConstructorDecl *) context; - if (!superclassCtor->hasValidSignature()) - ctx.getLazyResolver()->resolveDeclSignature(superclassCtor); - // Reference to super.init. auto *selfDecl = ctor->getImplicitSelfDecl(); auto *superRef = buildSelfReference(selfDecl, SelfAccessorKind::Super, @@ -861,9 +858,7 @@ static void addImplicitConstructorsToStruct(StructDecl *decl, ASTContext &ctx) { if (!var->isMemberwiseInitialized(/*preferDeclaredProperties=*/true)) continue; - if (!var->hasValidSignature()) - ctx.getLazyResolver()->resolveDeclSignature(var); - if (!var->hasValidSignature()) + if (!var->getInterfaceType()) return; } } @@ -928,9 +923,7 @@ static void addImplicitConstructorsToClass(ClassDecl *decl, ASTContext &ctx) { if (!decl->hasClangNode()) { for (auto member : decl->getMembers()) { if (auto ctor = dyn_cast(member)) { - if (!ctor->hasValidSignature()) - ctx.getLazyResolver()->resolveDeclSignature(ctor); - if (!ctor->hasValidSignature()) + if (!ctor->getInterfaceType()) return; } } @@ -1084,11 +1077,6 @@ static void addImplicitConstructorsToClass(ClassDecl *decl, ASTContext &ctx) { ? DesignatedInitKind::Chaining : DesignatedInitKind::Stub; - // We have a designated initializer. Create an override of it. - // FIXME: Validation makes sure we get a generic signature here. - if (!decl->hasValidSignature()) - ctx.getLazyResolver()->resolveDeclSignature(decl); - if (auto ctor = createDesignatedInitOverride( decl, superclassCtor, kind, ctx)) { decl->addMember(ctor); diff --git a/lib/Sema/ConstraintLocator.h b/lib/Sema/ConstraintLocator.h index 34619cf370f26..663312bb27414 100644 --- a/lib/Sema/ConstraintLocator.h +++ b/lib/Sema/ConstraintLocator.h @@ -184,8 +184,10 @@ class ConstraintLocator : public llvm::FoldingSetNode { case TypeParameterRequirement: case ConditionalRequirement: - case ApplyArgToParam: return 2; + + case ApplyArgToParam: + return 3; } llvm_unreachable("Unhandled PathElementKind in switch."); @@ -282,12 +284,12 @@ class ConstraintLocator : public llvm::FoldingSetNode { uint64_t storedKind : 3; /// Encode a path element kind and a value into the storage format. - static uint64_t encodeStorage(PathElementKind kind, unsigned value) { - return ((uint64_t)value << 8) | kind; + static uint64_t encodeStorage(PathElementKind kind, uint64_t value) { + return (value << 8) | kind; } /// Decode a storage value into path element kind and value. - static std::pair + static std::pair decodeStorage(uint64_t storage) { return { (PathElementKind)((unsigned)storage & 0xFF), storage >> 8 }; } @@ -323,6 +325,17 @@ class ConstraintLocator : public llvm::FoldingSetNode { assert(value1 == getValue(1) && "value1 truncated"); } + PathElement(PathElementKind kind, uint64_t value0, uint64_t value1, + uint64_t value2) + : storage(encodeStorage(kind, value0 << 32 | value1 << 16 | value2)), + storedKind(StoredKindAndValue) { + assert(numNumericValuesInPathElement(kind) == 3 && + "Path element kind does not require 3 values"); + assert(value0 == getValue(0) && "value0 truncated"); + assert(value1 == getValue(1) && "value1 truncated"); + assert(value2 == getValue(2) && "value2 truncated"); + } + /// Store a path element with an associated pointer, accessible using /// \c getStoredPointer. template @@ -695,11 +708,15 @@ dyn_cast(const LocatorPathElt &) = delete; // Use LocatorPathElt::getAs instead. class LocatorPathElt::ApplyArgToParam final : public LocatorPathElt { public: - ApplyArgToParam(unsigned argIdx, unsigned paramIdx) - : LocatorPathElt(ConstraintLocator::ApplyArgToParam, argIdx, paramIdx) {} + ApplyArgToParam(unsigned argIdx, unsigned paramIdx, ParameterTypeFlags flags) + : LocatorPathElt(ConstraintLocator::ApplyArgToParam, argIdx, paramIdx, + flags.toRaw()) {} unsigned getArgIdx() const { return getValue(0); } unsigned getParamIdx() const { return getValue(1); } + ParameterTypeFlags getParameterFlags() const { + return ParameterTypeFlags::fromRaw(getValue(2)); + } static bool classof(const LocatorPathElt *elt) { return elt->getKind() == ConstraintLocator::ApplyArgToParam; diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index 0ceb6de576c31..f1e05239155e4 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -498,14 +498,6 @@ Type ConstraintSystem::openUnboundGenericType(UnboundGenericType *unbound, ConstraintLocatorBuilder locator, OpenedTypeMap &replacements) { auto unboundDecl = unbound->getDecl(); - - // If the unbound decl hasn't been validated yet, we have a circular - // dependency that isn't being diagnosed properly. - if (!unboundDecl->getGenericSignature()) { - TC.diagnose(unboundDecl, diag::circular_reference); - return Type(); - } - auto parentTy = unbound->getParent(); if (parentTy) { parentTy = openUnboundGenericType(parentTy, locator); @@ -827,7 +819,7 @@ Type ConstraintSystem::getUnopenedTypeOfReference(VarDecl *value, Type baseType, if (auto *param = dyn_cast(var)) return getType(param); - if (!var->hasValidSignature()) { + if (!var->hasInterfaceType()) { if (!var->isInvalid()) { TC.diagnose(var->getLoc(), diag::recursive_decl_reference, var->getDescriptiveKind(), var->getName()); @@ -1474,7 +1466,6 @@ Type ConstraintSystem::getEffectiveOverloadType(const OverloadChoice &overload, // Retrieve the interface type. auto type = decl->getInterfaceType(); if (!type) { - decl->getASTContext().getLazyResolver()->resolveDeclSignature(decl); type = decl->getInterfaceType(); if (!type) { return Type(); @@ -2818,6 +2809,216 @@ bool ConstraintSystem::diagnoseAmbiguity(Expr *expr, return false; } +ConstraintLocator * +constraints::simplifyLocator(ConstraintSystem &cs, ConstraintLocator *locator, + SourceRange &range) { + auto path = locator->getPath(); + auto anchor = locator->getAnchor(); + simplifyLocator(anchor, path, range); + + // If we didn't simplify anything, just return the input. + if (anchor == locator->getAnchor() && + path.size() == locator->getPath().size()) { + return locator; + } + + // If the old locator didn't have any summary flags, neither will the + // simplified version, as it must contain a subset of the path elements. + if (locator->getSummaryFlags() == 0) + return cs.getConstraintLocator(anchor, path, /*summaryFlags*/ 0); + + return cs.getConstraintLocator(anchor, path); +} + +void constraints::simplifyLocator(Expr *&anchor, + ArrayRef &path, + SourceRange &range) { + range = SourceRange(); + + while (!path.empty()) { + switch (path[0].getKind()) { + case ConstraintLocator::ApplyArgument: { + // Extract application argument. + if (auto applyExpr = dyn_cast(anchor)) { + anchor = applyExpr->getArg(); + path = path.slice(1); + continue; + } + + if (auto subscriptExpr = dyn_cast(anchor)) { + anchor = subscriptExpr->getIndex(); + path = path.slice(1); + continue; + } + + if (auto objectLiteralExpr = dyn_cast(anchor)) { + anchor = objectLiteralExpr->getArg(); + path = path.slice(1); + continue; + } + + if (auto *UME = dyn_cast(anchor)) { + anchor = UME->getArgument(); + path = path.slice(1); + continue; + } + break; + } + + case ConstraintLocator::ApplyFunction: + // Extract application function. + if (auto applyExpr = dyn_cast(anchor)) { + anchor = applyExpr->getFn(); + path = path.slice(1); + continue; + } + + // The subscript itself is the function. + if (auto subscriptExpr = dyn_cast(anchor)) { + anchor = subscriptExpr; + path = path.slice(1); + continue; + } + + // The unresolved member itself is the function. + if (auto unresolvedMember = dyn_cast(anchor)) { + if (unresolvedMember->getArgument()) { + anchor = unresolvedMember; + path = path.slice(1); + continue; + } + } + + break; + + case ConstraintLocator::AutoclosureResult: + case ConstraintLocator::LValueConversion: + case ConstraintLocator::RValueAdjustment: + case ConstraintLocator::UnresolvedMember: + // Arguments in autoclosure positions, lvalue and rvalue adjustments, and + // scalar-to-tuple conversions, and unresolved members are + // implicit. + path = path.slice(1); + continue; + + case ConstraintLocator::NamedTupleElement: + case ConstraintLocator::TupleElement: { + // Extract tuple element. + auto elt = path[0].castTo(); + unsigned index = elt.getIndex(); + if (auto tupleExpr = dyn_cast(anchor)) { + if (index < tupleExpr->getNumElements()) { + anchor = tupleExpr->getElement(index); + path = path.slice(1); + continue; + } + } + + if (auto *CE = dyn_cast(anchor)) { + if (index < CE->getNumElements()) { + anchor = CE->getElement(index); + path = path.slice(1); + continue; + } + } + break; + } + + case ConstraintLocator::ApplyArgToParam: { + auto elt = path[0].castTo(); + // Extract tuple element. + if (auto tupleExpr = dyn_cast(anchor)) { + unsigned index = elt.getArgIdx(); + if (index < tupleExpr->getNumElements()) { + anchor = tupleExpr->getElement(index); + path = path.slice(1); + continue; + } + } + + // Extract subexpression in parentheses. + if (auto parenExpr = dyn_cast(anchor)) { + assert(elt.getArgIdx() == 0); + + anchor = parenExpr->getSubExpr(); + path = path.slice(1); + continue; + } + break; + } + case ConstraintLocator::ConstructorMember: + if (auto typeExpr = dyn_cast(anchor)) { + // This is really an implicit 'init' MemberRef, so point at the base, + // i.e. the TypeExpr. + range = SourceRange(); + anchor = typeExpr; + path = path.slice(1); + continue; + } + LLVM_FALLTHROUGH; + + case ConstraintLocator::Member: + case ConstraintLocator::MemberRefBase: + if (auto UDE = dyn_cast(anchor)) { + range = UDE->getNameLoc().getSourceRange(); + anchor = UDE->getBase(); + path = path.slice(1); + continue; + } + break; + + case ConstraintLocator::SubscriptMember: + if (isa(anchor)) { + path = path.slice(1); + continue; + } + break; + + case ConstraintLocator::ClosureResult: + if (auto CE = dyn_cast(anchor)) { + if (CE->hasSingleExpressionBody()) { + anchor = CE->getSingleExpressionBody(); + path = path.slice(1); + continue; + } + } + break; + + case ConstraintLocator::ContextualType: + // This was just for identifying purposes, strip it off. + path = path.slice(1); + continue; + + case ConstraintLocator::KeyPathComponent: { + auto elt = path[0].castTo(); + + // If the next element is an ApplyArgument, we can simplify by looking + // into the index expression. + if (path.size() < 2 || + path[1].getKind() != ConstraintLocator::ApplyArgument) + break; + + if (auto *kpe = dyn_cast(anchor)) { + auto component = kpe->getComponents()[elt.getIndex()]; + auto indexExpr = component.getIndexExpr(); + assert(indexExpr && "Trying to apply a component without an index?"); + anchor = indexExpr; + path = path.slice(2); + continue; + } + break; + } + + default: + // FIXME: Lots of other cases to handle. + break; + } + + // If we get here, we couldn't simplify the path further. + break; + } +} + Expr *constraints::simplifyLocatorToAnchor(ConstraintLocator *locator) { if (!locator) return nullptr; diff --git a/lib/Sema/DebuggerTestingTransform.cpp b/lib/Sema/DebuggerTestingTransform.cpp index 70e1713c21e6b..cb85e9998a4e3 100644 --- a/lib/Sema/DebuggerTestingTransform.cpp +++ b/lib/Sema/DebuggerTestingTransform.cpp @@ -23,6 +23,7 @@ #include "swift/AST/Expr.h" #include "swift/AST/Module.h" #include "swift/AST/ParameterList.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/Stmt.h" #include "swift/Subsystems.h" diff --git a/lib/Sema/DerivedConformanceCodable.cpp b/lib/Sema/DerivedConformanceCodable.cpp index 1e1e75ae58c5d..3ebcc03c99220 100644 --- a/lib/Sema/DerivedConformanceCodable.cpp +++ b/lib/Sema/DerivedConformanceCodable.cpp @@ -118,13 +118,9 @@ static CodableConformanceType varConformsToCodable(TypeChecker &tc, // // hasn't yet been evaluated // } // - // Validate the decl eagerly. - if (!varDecl->hasInterfaceType()) - tc.validateDecl(varDecl); - // If the var decl didn't validate, it may still not have a type; confirm it // has a type before ensuring the type conforms to Codable. - if (!varDecl->hasInterfaceType()) + if (!varDecl->getInterfaceType()) return TypeNotValidated; bool isIUO = varDecl->isImplicitlyUnwrappedOptional(); @@ -272,9 +268,6 @@ static CodingKeysValidity hasValidCodingKeysEnum(DerivedConformance &derived) { return CodingKeysValidity(/*hasType=*/true, /*isValid=*/false); } - // If the decl hasn't been validated yet, do so. - tc.validateDecl(codingKeysTypeDecl); - // CodingKeys may be a typealias. If so, follow the alias to its canonical // type. auto codingKeysType = codingKeysTypeDecl->getDeclaredInterfaceType(); diff --git a/lib/Sema/DerivedConformanceCodingKey.cpp b/lib/Sema/DerivedConformanceCodingKey.cpp index a09d4e1603b40..595e0552a7bc6 100644 --- a/lib/Sema/DerivedConformanceCodingKey.cpp +++ b/lib/Sema/DerivedConformanceCodingKey.cpp @@ -333,8 +333,7 @@ deriveBodyCodingKey_init_stringValue(AbstractFunctionDecl *initDecl, void *) { static bool canSynthesizeCodingKey(DerivedConformance &derived) { auto enumDecl = cast(derived.Nominal); // Validate the enum and its raw type. - derived.TC.validateDecl(enumDecl); - + // If the enum has a raw type (optional), it must be String or Int. Type rawType = enumDecl->getRawType(); if (rawType) { diff --git a/lib/Sema/DerivedConformanceDifferentiable.cpp b/lib/Sema/DerivedConformanceDifferentiable.cpp index 62fbedade2265..c93fcce99b692 100644 --- a/lib/Sema/DerivedConformanceDifferentiable.cpp +++ b/lib/Sema/DerivedConformanceDifferentiable.cpp @@ -707,6 +707,7 @@ static void addAssociatedTypeAliasDecl(Identifier name, cast(sourceDC->getAsDecl())->addMember(aliasDecl); aliasDecl->copyFormalAccessFrom(nominal, /*sourceIsParentContext*/ true); aliasDecl->setValidationToChecked(); + aliasDecl->computeType(); TC.validateDecl(aliasDecl); C.addSynthesizedDecl(aliasDecl); }; @@ -853,6 +854,7 @@ deriveDifferentiable_TangentVectorStruct(DerivedConformance &derived) { aliasDecl->setImplicit(); aliasDecl->copyFormalAccessFrom(nominal, /*sourceIsParentContext*/ true); aliasDecl->setValidationToChecked(); + aliasDecl->computeType(); TC.validateDecl(aliasDecl); derived.addMembersToConformanceContext({aliasDecl}); C.addSynthesizedDecl(aliasDecl); diff --git a/lib/Sema/DerivedConformanceEquatableHashable.cpp b/lib/Sema/DerivedConformanceEquatableHashable.cpp index 65b7fa86011f7..566ca9e48dd77 100644 --- a/lib/Sema/DerivedConformanceEquatableHashable.cpp +++ b/lib/Sema/DerivedConformanceEquatableHashable.cpp @@ -45,12 +45,11 @@ enum NonconformingMemberKind { static SmallVector associatedValuesNotConformingToProtocol(DeclContext *DC, EnumDecl *theEnum, ProtocolDecl *protocol) { - auto lazyResolver = DC->getASTContext().getLazyResolver(); SmallVector nonconformingAssociatedValues; for (auto elt : theEnum->getAllElements()) { - if (!elt->hasInterfaceType()) - lazyResolver->resolveDeclSignature(elt); - + if (!elt->getInterfaceType()) + continue; + auto PL = elt->getParameterList(); if (!PL) continue; @@ -85,19 +84,15 @@ static bool allAssociatedValuesConformToProtocol(DeclContext *DC, static SmallVector storedPropertiesNotConformingToProtocol(DeclContext *DC, StructDecl *theStruct, ProtocolDecl *protocol) { - auto lazyResolver = DC->getASTContext().getLazyResolver(); auto storedProperties = theStruct->getStoredProperties(); SmallVector nonconformingProperties; for (auto propertyDecl : storedProperties) { if (!propertyDecl->isUserAccessible()) continue; - if (!propertyDecl->hasInterfaceType()) - lazyResolver->resolveDeclSignature(propertyDecl); - if (!propertyDecl->hasInterfaceType()) - nonconformingProperties.push_back(propertyDecl); - auto type = propertyDecl->getValueInterfaceType(); + if (!type) + nonconformingProperties.push_back(propertyDecl); if (!TypeChecker::conformsToProtocol(DC->mapTypeIntoContext(type), protocol, DC, None)) { @@ -1169,9 +1164,6 @@ deriveBodyHashable_hashValue(AbstractFunctionDecl *hashValueDecl, void *) { // _hashValue(for:) auto *hashFunc = C.getHashValueForDecl(); - if (!hashFunc->hasInterfaceType()) - static_cast(C.getLazyResolver())->validateDecl(hashFunc); - auto substitutions = SubstitutionMap::get( hashFunc->getGenericSignature(), [&](SubstitutableType *dependentType) { diff --git a/lib/Sema/DerivedConformanceRawRepresentable.cpp b/lib/Sema/DerivedConformanceRawRepresentable.cpp index 4ad71c81cc166..88ec16718d8dc 100644 --- a/lib/Sema/DerivedConformanceRawRepresentable.cpp +++ b/lib/Sema/DerivedConformanceRawRepresentable.cpp @@ -465,10 +465,6 @@ static bool canSynthesizeRawRepresentable(DerivedConformance &derived) { auto enumDecl = cast(derived.Nominal); auto &tc = derived.TC; - // Validate the enum and its raw type. - tc.validateDecl(enumDecl); - - // It must have a valid raw type. Type rawType = enumDecl->getRawType(); if (!rawType) return false; @@ -504,7 +500,8 @@ static bool canSynthesizeRawRepresentable(DerivedConformance &derived) { if (elt->hasAssociatedValues()) return false; - tc.validateDecl(elt); + // FIXME(InterfaceTypeRequest): isInvalid() should be based on the interface type. + (void)elt->getInterfaceType(); if (elt->isInvalid()) { return false; } diff --git a/lib/Sema/IDETypeCheckingRequests.cpp b/lib/Sema/IDETypeCheckingRequests.cpp index 2cd7c318a31f6..efa924be57178 100644 --- a/lib/Sema/IDETypeCheckingRequests.cpp +++ b/lib/Sema/IDETypeCheckingRequests.cpp @@ -56,9 +56,7 @@ static bool isExtensionAppliedInternal(const DeclContext *DC, Type BaseTy, if (!ED->isConstrainedExtension()) return true; - TypeChecker *TC = &TypeChecker::createForContext((DC->getASTContext())); - TC->validateExtension(const_cast(ED)); - + (void)TypeChecker::createForContext(DC->getASTContext()); GenericSignature *genericSig = ED->getGenericSignature(); SubstitutionMap substMap = BaseTy->getContextSubstitutionMap( DC->getParentModule(), ED->getExtendedNominal()); diff --git a/lib/Sema/InstrumenterSupport.cpp b/lib/Sema/InstrumenterSupport.cpp index 79dabab5810b6..cf09f836343ba 100644 --- a/lib/Sema/InstrumenterSupport.cpp +++ b/lib/Sema/InstrumenterSupport.cpp @@ -17,6 +17,7 @@ #include "InstrumenterSupport.h" #include "swift/AST/DiagnosticSuppression.h" +#include "swift/AST/SourceFile.h" #include "swift/Demangling/Punycode.h" #include "llvm/Support/Path.h" diff --git a/lib/Sema/LookupVisibleDecls.cpp b/lib/Sema/LookupVisibleDecls.cpp index 1713f14f50fa8..d8f5ae5d2c465 100644 --- a/lib/Sema/LookupVisibleDecls.cpp +++ b/lib/Sema/LookupVisibleDecls.cpp @@ -24,6 +24,7 @@ #include "swift/AST/ModuleNameLookup.h" #include "swift/AST/NameLookup.h" #include "swift/AST/ProtocolConformance.h" +#include "swift/AST/SourceFile.h" #include "swift/Basic/SourceManager.h" #include "swift/Basic/STLExtras.h" #include "swift/Sema/IDETypeCheckingRequests.h" @@ -124,11 +125,7 @@ static bool isDeclVisibleInLookupMode(ValueDecl *Member, LookupState LS, // Accessors are never visible directly in the source language. if (isa(Member)) return false; - - if (!Member->hasInterfaceType()) { - Member->getASTContext().getLazyResolver()->resolveDeclSignature(Member); - } - + // Check access when relevant. if (!Member->getDeclContext()->isLocalContext() && !isa(Member) && !isa(Member)) { @@ -283,10 +280,7 @@ static void doDynamicLookup(VisibleDeclConsumer &Consumer, return; // Ensure that the declaration has a type. - if (!D->hasInterfaceType()) { - D->getASTContext().getLazyResolver()->resolveDeclSignature(D); - if (!D->hasInterfaceType()) return; - } + if (!D->getInterfaceType()) return; switch (D->getKind()) { #define DECL(ID, SUPER) \ @@ -433,8 +427,9 @@ static void lookupDeclsFromProtocolsBeingConformedTo( continue; } if (auto *VD = dyn_cast(Member)) { + // FIXME(InterfaceTypeRequest): Remove this. + (void)VD->getInterfaceType(); if (auto *TypeResolver = VD->getASTContext().getLazyResolver()) { - TypeResolver->resolveDeclSignature(VD); if (!NormalConformance->hasWitness(VD) && (Conformance->getDeclContext()->getParentSourceFile() != FromContext->getParentSourceFile())) @@ -745,10 +740,8 @@ class OverrideFilteringConsumer : public VisibleDeclConsumer { return; } - if (!VD->hasInterfaceType()) { - VD->getASTContext().getLazyResolver()->resolveDeclSignature(VD); - if (!VD->hasInterfaceType()) - return; + if (!VD->getInterfaceType()) { + return; } if (VD->isInvalid()) { diff --git a/lib/Sema/MiscDiagnostics.cpp b/lib/Sema/MiscDiagnostics.cpp index e5ca10964e986..a98cc8aa61db2 100644 --- a/lib/Sema/MiscDiagnostics.cpp +++ b/lib/Sema/MiscDiagnostics.cpp @@ -1478,9 +1478,13 @@ bool TypeChecker::getDefaultGenericArgumentsString( genericParamText << contextTy; }; - interleave(typeDecl->getInnermostGenericParamTypes(), - printGenericParamSummary, [&]{ genericParamText << ", "; }); - + // FIXME: We can potentially be in the middle of creating a generic signature + // if we get here. Break this cycle. + if (typeDecl->hasComputedGenericSignature()) { + interleave(typeDecl->getInnermostGenericParamTypes(), + printGenericParamSummary, [&]{ genericParamText << ", "; }); + } + genericParamText << ">"; return true; } @@ -4170,10 +4174,7 @@ static OmissionTypeName getTypeNameForOmission(Type type) { Optional TypeChecker::omitNeedlessWords(AbstractFunctionDecl *afd) { auto &Context = afd->getASTContext(); - if (!afd->hasInterfaceType()) - validateDecl(afd); - - if (afd->isInvalid() || isa(afd)) + if (!afd->getInterfaceType() || afd->isInvalid() || isa(afd)) return None; DeclName name = afd->getFullName(); @@ -4253,10 +4254,7 @@ Optional TypeChecker::omitNeedlessWords(AbstractFunctionDecl *afd) { Optional TypeChecker::omitNeedlessWords(VarDecl *var) { auto &Context = var->getASTContext(); - if (!var->hasInterfaceType()) - validateDecl(var); - - if (var->isInvalid() || !var->hasInterfaceType()) + if (!var->getInterfaceType() || var->isInvalid()) return None; if (var->getName().empty()) diff --git a/lib/Sema/NameBinding.cpp b/lib/Sema/NameBinding.cpp index 0d532c8713f06..4d17b4eefc760 100644 --- a/lib/Sema/NameBinding.cpp +++ b/lib/Sema/NameBinding.cpp @@ -19,6 +19,7 @@ #include "swift/AST/ModuleLoader.h" #include "swift/AST/ModuleNameLookup.h" #include "swift/AST/NameLookup.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/SubstitutionMap.h" #include "swift/Basic/Statistic.h" #include "swift/ClangImporter/ClangModule.h" @@ -333,7 +334,7 @@ void NameBinder::addImport( diag::imported_decl_is_wrong_kind_typealias, typealias->getDescriptiveKind(), TypeAliasType::get(typealias, Type(), SubstitutionMap(), - typealias->getUnderlyingTypeLoc().getType()), + typealias->getUnderlyingType()), getImportKindString(ID->getImportKind()))); } else { emittedDiag.emplace(diagnose(ID, diag::imported_decl_is_wrong_kind, diff --git a/lib/Sema/PCMacro.cpp b/lib/Sema/PCMacro.cpp index 656fa70bbaedf..a2f52b7371dcd 100644 --- a/lib/Sema/PCMacro.cpp +++ b/lib/Sema/PCMacro.cpp @@ -25,6 +25,7 @@ #include "swift/AST/ParameterList.h" #include "swift/AST/Module.h" #include "swift/AST/Pattern.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/Stmt.h" using namespace swift; diff --git a/lib/Sema/PlaygroundTransform.cpp b/lib/Sema/PlaygroundTransform.cpp index 3805491d24c5e..e722d7df42fe2 100644 --- a/lib/Sema/PlaygroundTransform.cpp +++ b/lib/Sema/PlaygroundTransform.cpp @@ -22,6 +22,7 @@ #include "swift/AST/DeclContext.h" #include "swift/AST/Module.h" #include "swift/AST/Pattern.h" +#include "swift/AST/SourceFile.h" #include #include diff --git a/lib/Sema/ResilienceDiagnostics.cpp b/lib/Sema/ResilienceDiagnostics.cpp index 5afac83616be2..b77ac07675e34 100644 --- a/lib/Sema/ResilienceDiagnostics.cpp +++ b/lib/Sema/ResilienceDiagnostics.cpp @@ -21,6 +21,7 @@ #include "swift/AST/DeclContext.h" #include "swift/AST/Initializer.h" #include "swift/AST/ProtocolConformance.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/TypeDeclFinder.h" using namespace swift; diff --git a/lib/Sema/SourceLoader.cpp b/lib/Sema/SourceLoader.cpp index 9abce488f8a2f..3026605d6faf5 100644 --- a/lib/Sema/SourceLoader.cpp +++ b/lib/Sema/SourceLoader.cpp @@ -20,6 +20,7 @@ #include "swift/AST/ASTContext.h" #include "swift/AST/DiagnosticsSema.h" #include "swift/AST/Module.h" +#include "swift/AST/SourceFile.h" #include "swift/Parse/PersistentParserState.h" #include "swift/Basic/SourceManager.h" #include "llvm/ADT/SmallString.h" diff --git a/lib/Sema/TypeAccessScopeChecker.h b/lib/Sema/TypeAccessScopeChecker.h index 767b5022afad7..2e8b8990204bf 100644 --- a/lib/Sema/TypeAccessScopeChecker.h +++ b/lib/Sema/TypeAccessScopeChecker.h @@ -15,6 +15,7 @@ #include "swift/AST/Decl.h" #include "swift/AST/DeclContext.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/Type.h" #include "swift/AST/TypeDeclFinder.h" #include "swift/AST/TypeRepr.h" diff --git a/lib/Sema/TypeCheckAccess.cpp b/lib/Sema/TypeCheckAccess.cpp index 57322cce77a19..5d9f6360567c5 100644 --- a/lib/Sema/TypeCheckAccess.cpp +++ b/lib/Sema/TypeCheckAccess.cpp @@ -572,7 +572,8 @@ class AccessControlChecker : public AccessControlCheckerBase, void visitTypeAliasDecl(TypeAliasDecl *TAD) { checkGenericParamAccess(TAD->getGenericParams(), TAD); - checkTypeAccess(TAD->getUnderlyingTypeLoc(), TAD, /*mayBeInferred*/false, + checkTypeAccess(TAD->getUnderlyingType(), + TAD->getUnderlyingTypeRepr(), TAD, /*mayBeInferred*/false, [&](AccessScope typeAccessScope, const TypeRepr *complainRepr, DowngradeToWarning downgradeToWarning) { @@ -1194,7 +1195,8 @@ class UsableFromInlineChecker : public AccessControlCheckerBase, void visitTypeAliasDecl(TypeAliasDecl *TAD) { checkGenericParamAccess(TAD->getGenericParams(), TAD); - checkTypeAccess(TAD->getUnderlyingTypeLoc(), TAD, /*mayBeInferred*/false, + checkTypeAccess(TAD->getUnderlyingType(), + TAD->getUnderlyingTypeRepr(), TAD, /*mayBeInferred*/false, [&](AccessScope typeAccessScope, const TypeRepr *complainRepr, DowngradeToWarning downgradeToWarning) { @@ -1832,7 +1834,8 @@ class ExportabilityChecker : public DeclVisitor { void visitTypeAliasDecl(TypeAliasDecl *TAD) { checkGenericParams(TAD->getGenericParams(), TAD); - checkType(TAD->getUnderlyingTypeLoc(), TAD, getDiagnoseCallback(TAD), + checkType(TAD->getUnderlyingType(), + TAD->getUnderlyingTypeRepr(), TAD, getDiagnoseCallback(TAD), getDiagnoseCallback(TAD)); } diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp index a1b82c8d9d723..072313046021a 100644 --- a/lib/Sema/TypeCheckAttr.cpp +++ b/lib/Sema/TypeCheckAttr.cpp @@ -28,6 +28,7 @@ #include "swift/AST/NameLookupRequests.h" #include "swift/AST/ParameterList.h" #include "swift/AST/PropertyWrappers.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/TypeCheckRequests.h" #include "swift/AST/Types.h" #include "swift/Parse/Lexer.h" @@ -1092,7 +1093,8 @@ bool swift::isValidDynamicCallableMethod(FuncDecl *decl, DeclContext *DC, // `ExpressibleByStringLiteral`. // `D.Value` and the return type can be arbitrary. - TC.validateDeclForNameLookup(decl); + // FIXME(InterfaceTypeRequest): Remove this. + (void)decl->getInterfaceType(); auto paramList = decl->getParameters(); if (paramList->size() != 1 || paramList->get(0)->isVariadic()) return false; auto argType = paramList->get(0)->getType(); @@ -1172,7 +1174,7 @@ static bool hasSingleNonVariadicParam(SubscriptDecl *decl, return false; auto *index = indices->get(0); - if (index->isVariadic() || !index->hasValidSignature()) + if (index->isVariadic() || !index->hasInterfaceType()) return false; if (ignoreLabel) { @@ -1263,7 +1265,8 @@ visitDynamicMemberLookupAttr(DynamicMemberLookupAttr *attr) { auto oneCandidate = candidates.front().getValueDecl(); candidates.filter([&](LookupResultEntry entry, bool isOuter) -> bool { auto cand = cast(entry.getValueDecl()); - TC.validateDeclForNameLookup(cand); + // FIXME(InterfaceTypeRequest): Remove this. + (void)cand->getInterfaceType(); return isValidDynamicMemberLookupSubscript(cand, decl, TC); }); @@ -1286,7 +1289,8 @@ visitDynamicMemberLookupAttr(DynamicMemberLookupAttr *attr) { // Validate the candidates while ignoring the label. newCandidates.filter([&](const LookupResultEntry entry, bool isOuter) { auto cand = cast(entry.getValueDecl()); - TC.validateDeclForNameLookup(cand); + // FIXME(InterfaceTypeRequest): Remove this. + (void)cand->getInterfaceType(); return isValidDynamicMemberLookupSubscript(cand, decl, TC, /*ignoreLabel*/ true); }); @@ -2154,7 +2158,6 @@ static FuncDecl *findReplacedAccessor(DeclName replacedVarName, // Filter out any accessors that won't work. if (!results.empty()) { auto replacementStorage = replacement->getStorage(); - TC.validateDecl(replacementStorage); Type replacementStorageType = getDynamicComparisonType(replacementStorage); results.erase(std::remove_if(results.begin(), results.end(), [&](ValueDecl *result) { @@ -2166,7 +2169,6 @@ static FuncDecl *findReplacedAccessor(DeclName replacedVarName, return true; // Check for type mismatch. - TC.validateDecl(result); auto resultType = getDynamicComparisonType(result); if (!resultType->isEqual(replacementStorageType) && !resultType->matches( @@ -2200,7 +2202,9 @@ static FuncDecl *findReplacedAccessor(DeclName replacedVarName, } assert(!isa(results[0])); - TC.validateDecl(results[0]); + + // FIXME(InterfaceTypeRequest): Remove this. + (void)results[0]->getInterfaceType(); auto *origStorage = cast(results[0]); if (!origStorage->isDynamic()) { TC.diagnose(attr->getLocation(), @@ -2216,8 +2220,8 @@ static FuncDecl *findReplacedAccessor(DeclName replacedVarName, if (!origAccessor) return nullptr; - TC.validateDecl(origAccessor); - + // FIXME(InterfaceTypeRequest): Remove this. + (void)origAccessor->getInterfaceType(); if (origAccessor->isImplicit() && !(origStorage->getReadImpl() == ReadImplKind::Stored && origStorage->getWriteImpl() == WriteImplKind::Stored)) { @@ -2249,9 +2253,7 @@ findReplacedFunction(DeclName replacedFunctionName, // Check for static/instance mismatch. if (result->isStatic() != replacement->isStatic()) continue; - - if (TC) - TC->validateDecl(result); + TypeMatchOptions matchMode = TypeMatchFlags::AllowABICompatible; matchMode |= TypeMatchFlags::AllowCompatibleOpaqueTypeArchetypes; if (result->getInterfaceType()->getCanonicalType()->matches( @@ -2372,7 +2374,8 @@ void AttributeChecker::visitDynamicReplacementAttr(DynamicReplacementAttr *attr) if (attr->isInvalid()) return; - TC.validateDecl(accessor); + // FIXME(InterfaceTypeRequest): Remove this. + (void)accessor->getInterfaceType(); auto *orig = findReplacedAccessor(attr->getReplacedFunctionName(), accessor, attr, TC); if (!orig) @@ -3468,7 +3471,7 @@ void AttributeChecker::visitDifferentiableAttr(DifferentiableAttr *attr) { lookupConformance, whereClauseGenSig, /*makeSelfParamFirst*/ true); auto isValidJVP = [&](FuncDecl *jvpCandidate) { - TC.validateDeclForNameLookup(jvpCandidate); + TC.validateDecl(jvpCandidate); return checkFunctionSignature( cast(expectedJVPFnTy->getCanonicalType()), jvpCandidate->getInterfaceType()->getCanonicalType()); @@ -3494,7 +3497,7 @@ void AttributeChecker::visitDifferentiableAttr(DifferentiableAttr *attr) { lookupConformance, whereClauseGenSig, /*makeSelfParamFirst*/ true); auto isValidVJP = [&](FuncDecl *vjpCandidate) { - TC.validateDeclForNameLookup(vjpCandidate); + TC.validateDecl(vjpCandidate); return checkFunctionSignature( cast(expectedVJPFnTy->getCanonicalType()), vjpCandidate->getInterfaceType()->getCanonicalType()); @@ -3638,7 +3641,7 @@ void AttributeChecker::visitDifferentiatingAttr(DifferentiatingAttr *attr) { }; auto isValidOriginal = [&](FuncDecl *originalCandidate) { - TC.validateDeclForNameLookup(originalCandidate); + TC.validateDecl(originalCandidate); return checkFunctionSignature( cast(originalFnType->getCanonicalType()), originalCandidate->getInterfaceType()->getCanonicalType(), @@ -3991,7 +3994,7 @@ void AttributeChecker::visitTransposingAttr(TransposingAttr *attr) { }; auto isValidOriginal = [&](FuncDecl *originalCandidate) { - TC.validateDeclForNameLookup(originalCandidate); + TC.validateDecl(originalCandidate); return checkFunctionSignature( cast(expectedOriginalFnType->getCanonicalType()), originalCandidate->getInterfaceType()->getCanonicalType(), diff --git a/lib/Sema/TypeCheckAvailability.cpp b/lib/Sema/TypeCheckAvailability.cpp index bdfd2d6925e0c..2b48f3e8b470a 100644 --- a/lib/Sema/TypeCheckAvailability.cpp +++ b/lib/Sema/TypeCheckAvailability.cpp @@ -22,6 +22,7 @@ #include "swift/AST/Initializer.h" #include "swift/AST/NameLookup.h" #include "swift/AST/Pattern.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/TypeRefinementContext.h" #include "swift/Basic/Defer.h" #include "swift/Basic/SourceManager.h" diff --git a/lib/Sema/TypeCheckCaptures.cpp b/lib/Sema/TypeCheckCaptures.cpp index c376ec6c91a8d..048bff537ff1d 100644 --- a/lib/Sema/TypeCheckCaptures.cpp +++ b/lib/Sema/TypeCheckCaptures.cpp @@ -42,39 +42,33 @@ class FindCapturedVars : public ASTWalker { OpaqueValueExpr *OpaqueValue = nullptr; SourceLoc CaptureLoc; DeclContext *CurDC; - bool NoEscape, ObjC; + bool NoEscape, ObjC, IsGenericFunction; public: FindCapturedVars(ASTContext &Context, SourceLoc CaptureLoc, DeclContext *CurDC, bool NoEscape, - bool ObjC) + bool ObjC, + bool IsGenericFunction) : Context(Context), CaptureLoc(CaptureLoc), CurDC(CurDC), - NoEscape(NoEscape), ObjC(ObjC) {} + NoEscape(NoEscape), ObjC(ObjC), IsGenericFunction(IsGenericFunction) {} CaptureInfo getCaptureInfo() const { - CaptureInfo result; - - // Anything can capture an opaque value placeholder. - if (OpaqueValue) - result.setOpaqueValue(OpaqueValue); + DynamicSelfType *dynamicSelfToRecord = nullptr; + bool hasGenericParamCaptures = IsGenericFunction; // Only local functions capture dynamic 'Self'. if (CurDC->getParent()->isLocalContext()) { if (GenericParamCaptureLoc.isValid()) - result.setGenericParamCaptures(true); + hasGenericParamCaptures = true; if (DynamicSelfCaptureLoc.isValid()) - result.setDynamicSelfType(DynamicSelf); + dynamicSelfToRecord = DynamicSelf; } - if (Captures.empty()) - result.setCaptures(None); - else - result.setCaptures(Context.AllocateCopy(Captures)); - - return result; + return CaptureInfo(Context, Captures, dynamicSelfToRecord, OpaqueValue, + hasGenericParamCaptures); } SourceLoc getGenericParamCaptureLoc() const { @@ -325,11 +319,8 @@ class FindCapturedVars : public ASTWalker { return { false, DRE }; } - void propagateCaptures(AnyFunctionRef innerClosure, SourceLoc captureLoc) { - TypeChecker::computeCaptures(innerClosure); - - auto &captureInfo = innerClosure.getCaptureInfo(); - + void propagateCaptures(const CaptureInfo &captureInfo, + SourceLoc loc) { for (auto capture : captureInfo.getCaptures()) { // If the decl was captured from us, it isn't captured *by* us. if (capture.getDecl()->getDeclContext() == CurDC) @@ -347,18 +338,19 @@ class FindCapturedVars : public ASTWalker { if (!NoEscape) Flags &= ~CapturedValue::IsNoEscape; - addCapture(CapturedValue(capture.getDecl(), Flags, captureLoc)); + addCapture(CapturedValue(capture.getDecl(), Flags, capture.getLoc())); } if (GenericParamCaptureLoc.isInvalid()) if (captureInfo.hasGenericParamCaptures()) - GenericParamCaptureLoc = innerClosure.getLoc(); + GenericParamCaptureLoc = loc; - if (DynamicSelfCaptureLoc.isInvalid()) + if (DynamicSelfCaptureLoc.isInvalid()) { if (captureInfo.hasDynamicSelfCapture()) { - DynamicSelfCaptureLoc = innerClosure.getLoc(); + DynamicSelfCaptureLoc = loc; DynamicSelf = captureInfo.getDynamicSelfType(); } + } if (!OpaqueValue) { if (captureInfo.hasOpaqueValueCapture()) @@ -368,14 +360,8 @@ class FindCapturedVars : public ASTWalker { bool walkToDeclPre(Decl *D) override { if (auto *AFD = dyn_cast(D)) { - propagateCaptures(AFD, AFD->getLoc()); - - // Can default parameter initializers capture state? That seems like - // a really bad idea. - for (auto *param : *AFD->getParameters()) - if (auto E = param->getDefaultValue()) - E->walk(*this); - + TypeChecker::computeCaptures(AFD); + propagateCaptures(AFD->getCaptureInfo(), AFD->getLoc()); return false; } @@ -569,7 +555,8 @@ class FindCapturedVars : public ASTWalker { // list computed; we just propagate it, filtering out stuff that they // capture from us. if (auto *SubCE = dyn_cast(E)) { - propagateCaptures(SubCE, SubCE->getStartLoc()); + TypeChecker::computeCaptures(SubCE); + propagateCaptures(SubCE->getCaptureInfo(), SubCE->getLoc()); return { false, E }; } @@ -597,29 +584,50 @@ void TypeChecker::computeCaptures(AnyFunctionRef AFR) { PrettyStackTraceAnyFunctionRef trace("computing captures for", AFR); + // A generic function always captures outer generic parameters. + bool isGeneric = false; + auto *AFD = AFR.getAbstractFunctionDecl(); + if (AFD) + isGeneric = (AFD->getGenericParams() != nullptr); + auto &Context = AFR.getAsDeclContext()->getASTContext(); FindCapturedVars finder(Context, AFR.getLoc(), AFR.getAsDeclContext(), AFR.isKnownNoEscape(), - AFR.isObjC()); + AFR.isObjC(), + isGeneric); AFR.getBody()->walk(finder); if (AFR.hasType() && !AFR.isObjC()) { finder.checkType(AFR.getType(), AFR.getLoc()); } - auto captures = finder.getCaptureInfo(); + AFR.setCaptureInfo(finder.getCaptureInfo()); + + // Compute captures for default argument expressions. + if (auto *AFD = AFR.getAbstractFunctionDecl()) { + for (auto *P : *AFD->getParameters()) { + if (auto E = P->getDefaultValue()) { + FindCapturedVars finder(Context, + E->getLoc(), + AFD, + /*isNoEscape=*/false, + /*isObjC=*/false, + /*IsGeneric*/isGeneric); + E->walk(finder); + + if (!AFD->getDeclContext()->isLocalContext() && + finder.getDynamicSelfCaptureLoc().isValid()) { + Context.Diags.diagnose(finder.getDynamicSelfCaptureLoc(), + diag::dynamic_self_default_arg); + } - // A generic function always captures outer generic parameters. - auto *AFD = AFR.getAbstractFunctionDecl(); - if (AFD) { - if (AFD->getGenericParams()) - captures.setGenericParamCaptures(true); + P->setDefaultArgumentCaptureInfo(finder.getCaptureInfo()); + } + } } - AFR.setCaptureInfo(captures); - // Extensions of generic ObjC functions can't use generic parameters from // their context. if (AFD && finder.getGenericParamCaptureLoc().isValid()) { @@ -672,7 +680,8 @@ void TypeChecker::checkPatternBindingCaptures(NominalTypeDecl *typeDecl) { init->getLoc(), PBD->getInitContext(i), /*NoEscape=*/false, - /*ObjC=*/false); + /*ObjC=*/false, + /*IsGenericFunction*/false); init->walk(finder); if (finder.getDynamicSelfCaptureLoc().isValid() && !isLazy(PBD)) { diff --git a/lib/Sema/TypeCheckCircularity.cpp b/lib/Sema/TypeCheckCircularity.cpp index 69adbfb619bb3..bd491e15b8435 100644 --- a/lib/Sema/TypeCheckCircularity.cpp +++ b/lib/Sema/TypeCheckCircularity.cpp @@ -249,11 +249,8 @@ bool CircularityChecker::expandStruct(CanType type, StructDecl *S, S->getModuleContext(), S); for (auto field: S->getStoredProperties()) { - if (!field->hasInterfaceType()) { - TC.validateDecl(field); - if (!field->hasInterfaceType()) - continue; - } + if (!field->getInterfaceType()) + continue; auto fieldType =field->getInterfaceType().subst(subMap); if (addMember(type, field, fieldType, depth)) @@ -286,11 +283,8 @@ bool CircularityChecker::expandEnum(CanType type, EnumDecl *E, if (!elt->hasAssociatedValues()) continue; - if (!elt->hasInterfaceType()) { - TC.validateDecl(elt); - if (!elt->hasInterfaceType()) - continue; - } + if (!elt->getInterfaceType()) + continue; auto eltType = elt->getArgumentInterfaceType().subst(subMap); if (addMember(type, elt, eltType, depth)) @@ -620,11 +614,8 @@ void CircularityChecker::diagnoseNonWellFoundedEnum(EnumDecl *E) { return false; for (auto elt: elts) { - if (!elt->hasInterfaceType()) { - TC.validateDecl(elt); - if (!elt->hasInterfaceType()) - return false; - } + if (!elt->getInterfaceType()) + return false; if (!elt->isIndirect() && !E->isIndirect()) return false; diff --git a/lib/Sema/TypeCheckConstraints.cpp b/lib/Sema/TypeCheckConstraints.cpp index 74d1e7c880e82..7e5cfa7b2ae85 100644 --- a/lib/Sema/TypeCheckConstraints.cpp +++ b/lib/Sema/TypeCheckConstraints.cpp @@ -440,11 +440,8 @@ static bool findNonMembers(TypeChecker &TC, if (!isValid(D)) return false; - if (!D->hasInterfaceType()) - TC.validateDecl(D); - // FIXME: Circularity hack. - if (!D->hasInterfaceType()) { + if (!D->getInterfaceType()) { AllDeclRefs = false; continue; } @@ -2633,7 +2630,7 @@ bool TypeChecker::typeCheckBinding(Pattern *&pattern, Expr *&initializer, emptyLocator); return propertyType; } - + // Otherwise, compute the wrapped value type directly. return computeWrappedValueType(wrappedVar, initType); } @@ -2654,10 +2651,10 @@ bool TypeChecker::typeCheckBinding(Pattern *&pattern, Expr *&initializer, // is the initialization of the property wrapper instance. initType = cs.getType(expr); - // Add a conversion constraint between the pattern type and the + // Add an equal constraint between the pattern type and the // property wrapper's "value" type. - cs.addConstraint(ConstraintKind::Conversion, patternType, - getPatternInitType(&cs), Locator, /*isFavored*/true); + cs.addConstraint(ConstraintKind::Equal, patternType, + getPatternInitType(&cs), Locator, /*isFavored*/ true); } else { // The initializer type is the type of the pattern. initType = patternType; @@ -3009,31 +3006,13 @@ bool TypeChecker::typeCheckCondition(Expr *&expr, DeclContext *dc) { return !resultTy; } - /// Expression type checking listener for conditions. - class ConditionListener : public ExprTypeCheckListener { - Expr *OrigExpr = nullptr; - - public: - // Add the appropriate Boolean constraint. - bool builtConstraints(ConstraintSystem &cs, Expr *expr) override { - // Save the original expression. - OrigExpr = expr; - - // Otherwise, the result must be convertible to Bool. - auto boolDecl = cs.getASTContext().getBoolDecl(); - if (!boolDecl) - return true; - - // Condition must convert to Bool. - cs.addConstraint(ConstraintKind::Conversion, cs.getType(expr), - boolDecl->getDeclaredType(), - cs.getConstraintLocator(expr)); - return false; - } - }; + auto *boolDecl = Context.getBoolDecl(); + if (!boolDecl) + return true; - ConditionListener listener; - auto resultTy = typeCheckExpression(expr, dc, &listener); + auto resultTy = typeCheckExpression( + expr, dc, TypeLoc::withoutLoc(boolDecl->getDeclaredType()), + CTP_Condition); return !resultTy; } @@ -3165,9 +3144,32 @@ bool TypeChecker::typeCheckExprPattern(ExprPattern *EP, DeclContext *DC, Expr *matchCall = new (Context) BinaryExpr(matchOp, matchArgs, /*Implicit=*/true); - + // Check the expression as a condition. - bool hadError = typeCheckCondition(matchCall, DC); + // + // TODO: Type-check of `~=` operator can't (yet) use `typeCheckCondition` + // because that utilizes contextual type which interferes with diagnostics. + // We don't yet have a full access to pattern-matching context in + // constraint system, which is required to enable these situations + // to be properly diagnosed. + struct ConditionListener : public ExprTypeCheckListener { + // Add the appropriate Boolean constraint. + bool builtConstraints(ConstraintSystem &cs, Expr *expr) override { + // Otherwise, the result must be convertible to Bool. + auto boolDecl = cs.getASTContext().getBoolDecl(); + if (!boolDecl) + return true; + + // Condition must convert to Bool. + cs.addConstraint(ConstraintKind::Conversion, cs.getType(expr), + boolDecl->getDeclaredType(), + cs.getConstraintLocator(expr)); + return false; + } + }; + + ConditionListener listener; + bool hadError = !typeCheckExpression(matchCall, DC, &listener); // Save the type-checked expression in the pattern. EP->setMatchExpr(matchCall); // Set the type on the pattern. @@ -4425,11 +4427,6 @@ CheckedCastKind TypeChecker::typeCheckCheckedCast(Type fromType, ConformanceCheckFlags::InExpression)) { auto nsError = Context.getNSErrorDecl(); if (nsError) { - if (!nsError->hasInterfaceType()) { - auto resolver = Context.getLazyResolver(); - assert(resolver); - resolver->resolveDeclSignature(nsError); - } Type NSErrorTy = nsError->getDeclaredInterfaceType(); if (isSubtypeOf(fromType, NSErrorTy, dc) // Don't mask "always true" warnings if NSError is cast to diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index e25a0a86f0ee0..a276d617cf2ab 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -39,6 +39,7 @@ #include "swift/AST/PropertyWrappers.h" #include "swift/AST/ProtocolConformance.h" #include "swift/AST/ReferencedNameTracker.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/TypeWalker.h" #include "swift/Basic/Statistic.h" #include "swift/Parse/Lexer.h" @@ -696,9 +697,10 @@ static void checkRedeclaration(TypeChecker &tc, ValueDecl *current) { // Validate the declaration but only if it came from a different context. if (other->getDeclContext() != current->getDeclContext()) - tc.validateDecl(other); + (void)other->getInterfaceType(); // Skip invalid or not yet seen declarations. + // FIXME(InterfaceTypeRequest): Delete this. if (other->isInvalid() || !other->hasInterfaceType()) continue; @@ -1122,10 +1124,7 @@ ExistentialTypeSupportedRequest::evaluate(Evaluator &evaluator, // For value members, look at their type signatures. if (auto valueMember = dyn_cast(member)) { - if (!valueMember->hasInterfaceType()) - if (auto *resolver = decl->getASTContext().getLazyResolver()) - resolver->resolveDeclSignature(valueMember); - + (void)valueMember->getInterfaceType(); if (!decl->isAvailableInExistential(valueMember)) return false; } @@ -1494,8 +1493,8 @@ static void checkEnumRawValues(TypeChecker &TC, EnumDecl *ED) { continue; // Make sure the element is checked out before we poke at it. - TC.validateDecl(elt); - + // FIXME: Make isInvalid work with interface types + (void)elt->getInterfaceType(); if (elt->isInvalid()) continue; @@ -1953,17 +1952,10 @@ void TypeChecker::validateDecl(OperatorDecl *OD) { } } -bool swift::doesContextHaveValueSemantics(DeclContext *dc) { - if (Type contextTy = dc->getDeclaredInterfaceType()) - return !contextTy->hasReferenceSemantics(); - return false; -} - llvm::Expected SelfAccessKindRequest::evaluate(Evaluator &evaluator, FuncDecl *FD) const { if (FD->getAttrs().getAttribute(true)) { - if (!FD->isInstanceMember() || - !doesContextHaveValueSemantics(FD->getDeclContext())) { + if (!FD->isInstanceMember() || !FD->getDeclContext()->hasValueSemantics()) { return SelfAccessKind::NonMutating; } return SelfAccessKind::Mutating; @@ -1985,8 +1977,7 @@ SelfAccessKindRequest::evaluate(Evaluator &evaluator, FuncDecl *FD) const { case AccessorKind::MutableAddress: case AccessorKind::Set: case AccessorKind::Modify: - if (AD->isInstanceMember() && - doesContextHaveValueSemantics(AD->getDeclContext())) + if (AD->isInstanceMember() && AD->getDeclContext()->hasValueSemantics()) return SelfAccessKind::Mutating; break; @@ -2414,8 +2405,10 @@ class DeclChecker : public DeclVisitor { } void visitSubscriptDecl(SubscriptDecl *SD) { - TC.validateDecl(SD); + (void)SD->getInterfaceType(); + // Force creation of the generic signature. + (void)SD->getGenericSignature(); if (!SD->isInvalid()) { TC.checkReferencedGenericParams(SD); checkGenericParams(SD->getGenericParams(), SD, TC); @@ -2462,22 +2455,31 @@ class DeclChecker : public DeclVisitor { } void visitTypeAliasDecl(TypeAliasDecl *TAD) { + (void)TAD->getInterfaceType(); - TC.validateDecl(TAD); TC.checkDeclAttributes(TAD); + // Force the generic signature to be computed in case it emits diagnostics. + (void)TAD->getGenericSignature(); + // Force computing the underlying type in case it emits diagnostics. + (void)TAD->getUnderlyingType(); + checkAccessControl(TC, TAD); + } void visitOpaqueTypeDecl(OpaqueTypeDecl *OTD) { - TC.validateDecl(OTD); + (void)OTD->getInterfaceType(); TC.checkDeclAttributes(OTD); + // Force the generic signature to be computed in case it emits diagnostics. + (void)OTD->getGenericSignature(); + checkAccessControl(TC, OTD); } void visitAssociatedTypeDecl(AssociatedTypeDecl *AT) { - TC.validateDecl(AT); + (void)AT->getInterfaceType(); TC.checkDeclAttributes(AT); checkInheritanceClause(AT); @@ -2526,6 +2528,7 @@ class DeclChecker : public DeclVisitor { TC.diagnose(NTD->getLoc(), diag::unsupported_nested_protocol, NTD->getName()); + NTD->setInvalid(); return; } @@ -2564,7 +2567,7 @@ class DeclChecker : public DeclVisitor { void visitEnumDecl(EnumDecl *ED) { checkUnsupportedNestedType(ED); - TC.validateDecl(ED); + (void)ED->getInterfaceType(); checkGenericParams(ED->getGenericParams(), ED, TC); { @@ -2599,7 +2602,7 @@ class DeclChecker : public DeclVisitor { void visitStructDecl(StructDecl *SD) { checkUnsupportedNestedType(SD); - TC.validateDecl(SD); + (void)SD->getInterfaceType(); checkGenericParams(SD->getGenericParams(), SD, TC); // Force lowering of stored properties. @@ -2720,7 +2723,9 @@ class DeclChecker : public DeclVisitor { void visitClassDecl(ClassDecl *CD) { checkUnsupportedNestedType(CD); - TC.validateDecl(CD); + (void)CD->getInterfaceType(); + // Force creation of the generic signature. + (void)CD->getGenericSignature(); checkGenericParams(CD->getGenericParams(), CD, TC); { @@ -2873,8 +2878,8 @@ class DeclChecker : public DeclVisitor { void visitProtocolDecl(ProtocolDecl *PD) { checkUnsupportedNestedType(PD); - TC.validateDecl(PD); - if (!PD->hasValidSignature()) + // FIXME: Circularity? + if (!PD->getInterfaceType()) return; auto *SF = PD->getParentSourceFile(); @@ -2988,7 +2993,7 @@ class DeclChecker : public DeclVisitor { } void visitFuncDecl(FuncDecl *FD) { - TC.validateDecl(FD); + (void)FD->getInterfaceType(); if (!FD->isInvalid()) { checkGenericParams(FD->getGenericParams(), FD, TC); @@ -3037,7 +3042,7 @@ class DeclChecker : public DeclVisitor { } void visitEnumElementDecl(EnumElementDecl *EED) { - TC.validateDecl(EED); + (void)EED->getInterfaceType(); TC.checkDeclAttributes(EED); @@ -3079,9 +3084,14 @@ class DeclChecker : public DeclVisitor { return; } - TC.validateExtension(ED); + // Validate the nominal type declaration being extended. + (void)nominal->getInterfaceType(); + // Don't bother computing the generic signature if the extended nominal + // type didn't pass validation so we don't crash. + if (!nominal->isInvalid()) + (void)ED->getGenericSignature(); + ED->setValidationToChecked(); - extType = ED->getExtendedType(); if (extType && !extType->hasError()) { // The first condition catches syntactic forms like // protocol A & B { ... } // may be protocols or typealiases @@ -3169,7 +3179,7 @@ class DeclChecker : public DeclVisitor { } void visitConstructorDecl(ConstructorDecl *CD) { - TC.validateDecl(CD); + (void)CD->getInterfaceType(); // Compute these requests in case they emit diagnostics. (void) CD->getInitKind(); @@ -3292,7 +3302,7 @@ class DeclChecker : public DeclVisitor { } void visitDestructorDecl(DestructorDecl *DD) { - TC.validateDecl(DD); + (void)DD->getInterfaceType(); TC.checkDeclAttributes(DD); @@ -3458,37 +3468,36 @@ IsImplicitlyUnwrappedOptionalRequest::evaluate(Evaluator &evaluator, } /// Validate the underlying type of the given typealias. -static void validateTypealiasType(TypeChecker &tc, TypeAliasDecl *typeAlias) { - TypeResolutionOptions options( - (typeAlias->getGenericParams() ? - TypeResolverContext::GenericTypeAliasDecl : - TypeResolverContext::TypeAliasDecl)); +llvm::Expected +UnderlyingTypeRequest::evaluate(Evaluator &evaluator, + TypeAliasDecl *typeAlias) const { + TypeResolutionOptions options((typeAlias->getGenericParams() + ? TypeResolverContext::GenericTypeAliasDecl + : TypeResolverContext::TypeAliasDecl)); if (!typeAlias->getDeclContext()->isCascadingContextForLookup( - /*functionsAreNonCascading*/true)) { - options |= TypeResolutionFlags::KnownNonCascadingDependency; + /*functionsAreNonCascading*/ true)) { + options |= TypeResolutionFlags::KnownNonCascadingDependency; } // This can happen when code completion is attempted inside // of typealias underlying type e.g. `typealias F = () -> Int#^TOK^#` - auto underlyingType = typeAlias->getUnderlyingTypeLoc(); - if (underlyingType.isNull()) { - typeAlias->getUnderlyingTypeLoc().setInvalidType(tc.Context); - typeAlias->setInterfaceType(ErrorType::get(tc.Context)); - return; + auto *underlyingRepr = typeAlias->getUnderlyingTypeRepr(); + if (!underlyingRepr) { + typeAlias->setInvalid(); + return ErrorType::get(typeAlias->getASTContext()); } - if (TypeChecker::validateType(tc.Context, typeAlias->getUnderlyingTypeLoc(), - TypeResolution::forInterface(typeAlias, &tc), + auto underlyingLoc = TypeLoc(typeAlias->getUnderlyingTypeRepr()); + if (TypeChecker::validateType(typeAlias->getASTContext(), underlyingLoc, + TypeResolution::forInterface(typeAlias), options)) { typeAlias->setInvalid(); - typeAlias->getUnderlyingTypeLoc().setInvalidType(tc.Context); + return ErrorType::get(typeAlias->getASTContext()); } - - typeAlias->setUnderlyingType(typeAlias->getUnderlyingTypeLoc().getType()); + return underlyingLoc.getType(); } - /// Bind the given function declaration, which declares an operator, to the corresponding operator declaration. llvm::Expected FunctionOperatorRequest::evaluate(Evaluator &evaluator, FuncDecl *FD) const { @@ -3693,18 +3702,39 @@ static Type buildAddressorResultType(TypeChecker &TC, return pointerType; } + +static void validateResultType(TypeChecker &TC, + ValueDecl *decl, ParameterList *params, + TypeLoc &resultTyLoc, + TypeResolution resolution) { + // Nothing to do if there's no result type loc to set into. + if (resultTyLoc.isNull()) + return; + + // Check the result type. It is allowed to be opaque. + if (auto opaqueTy = + dyn_cast_or_null(resultTyLoc.getTypeRepr())) { + // Create the decl and type for it. + resultTyLoc.setType( + TC.getOrCreateOpaqueResultType(resolution, decl, opaqueTy)); + } else { + TypeChecker::validateType(TC.Context, resultTyLoc, resolution, + TypeResolverContext::FunctionResult); + } +} + void TypeChecker::validateDecl(ValueDecl *D) { // Generic parameters are validated as part of their context. if (isa(D)) return; // Handling validation failure due to re-entrancy is left - // up to the caller, who must call hasValidSignature() to + // up to the caller, who must call hasInterfaceType() to // check that validateDecl() returned a fully-formed decl. if (D->hasValidationStarted()) { // If this isn't reentrant (i.e. D has already been validated), the // signature better be valid. - assert(D->isBeingValidated() || D->hasValidSignature()); + assert(D->isBeingValidated() || D->hasInterfaceType()); return; } @@ -3726,19 +3756,32 @@ void TypeChecker::validateDecl(ValueDecl *D) { // Validate the context. auto dc = D->getDeclContext(); if (auto nominal = dyn_cast(dc)) { - validateDecl(nominal); - if (!nominal->hasValidSignature()) + if (!nominal->getInterfaceType()) return; } else if (auto ext = dyn_cast(dc)) { - validateExtension(ext); - if (!ext->hasValidSignature()) + // If we're currently validating, or have already validated this extension, + // there's nothing more to do now. + if (!ext->hasValidationStarted()) { + DeclValidationRAII IBV(ext); + + if (auto *nominal = ext->getExtendedNominal()) { + // Validate the nominal type declaration being extended. + // FIXME(InterfaceTypeRequest): isInvalid() should be based on the interface type. + (void)nominal->getInterfaceType(); + + // Eagerly validate the generic signature of the extension. + if (!nominal->isInvalid()) + (void)ext->getGenericSignature(); + } + } + if (ext->getValidationState() == Decl::ValidationState::Checking) return; } // Validating the parent may have triggered validation of this declaration, // so just return if that was the case. if (D->hasValidationStarted()) { - assert(D->hasValidSignature()); + assert(D->hasInterfaceType()); return; } @@ -3780,18 +3823,19 @@ void TypeChecker::validateDecl(ValueDecl *D) { case DeclKind::TypeAlias: { auto typeAlias = cast(D); - // Check generic parameters, if needed. + DeclValidationRAII IBV(typeAlias); - validateGenericTypeSignature(typeAlias); - validateTypealiasType(*this, typeAlias); + // Finally, set the interface type. + if (!typeAlias->hasInterfaceType()) + typeAlias->computeType(); + break; } case DeclKind::OpaqueType: { auto opaque = cast(D); - DeclValidationRAII IBV(opaque); - validateGenericTypeSignature(opaque); + opaque->setValidationToChecked(); break; } @@ -3800,11 +3844,7 @@ void TypeChecker::validateDecl(ValueDecl *D) { case DeclKind::Class: { auto nominal = cast(D); nominal->computeType(); - - // Check generic parameters, if needed. - DeclValidationRAII IBV(nominal); - validateGenericTypeSignature(nominal); - nominal->setSignatureIsValidated(); + nominal->setValidationToChecked(); if (auto *ED = dyn_cast(nominal)) { // @objc enums use their raw values as the value representation, so we @@ -3820,40 +3860,7 @@ void TypeChecker::validateDecl(ValueDecl *D) { auto proto = cast(D); if (!proto->hasInterfaceType()) proto->computeType(); - - // Validate the generic type signature, which is just . - DeclValidationRAII IBV(proto); - validateGenericTypeSignature(proto); - proto->setSignatureIsValidated(); - - // See the comment in validateDeclForNameLookup(); we may have validated - // the alias before we built the protocol's generic environment. - // - // FIXME: Hopefully this can all go away with the ITC. - for (auto member : proto->getMembers()) { - if (auto *aliasDecl = dyn_cast(member)) { - if (!aliasDecl->isGeneric()) { - // FIXME: Force creation of the protocol's generic environment now. - (void) proto->getGenericEnvironment(); - aliasDecl->setGenericSignature(proto->getGenericSignature()); - - // The generic environment didn't exist until now, we may have - // unresolved types we will need to deal with, and need to record the - // appropriate substitutions for that environment. Wipe out the types - // and validate them again. - aliasDecl->getUnderlyingTypeLoc().setType(Type()); - aliasDecl->setInterfaceType(Type()); - - // Check generic parameters, if needed. - if (aliasDecl->hasValidationStarted()) { - validateTypealiasType(*this, aliasDecl); - } else { - DeclValidationRAII IBV(aliasDecl); - validateTypealiasType(*this, aliasDecl); - } - } - } - } + proto->setValidationToChecked(); break; } @@ -3930,8 +3937,7 @@ void TypeChecker::validateDecl(ValueDecl *D) { // Bail out if we're in a recursive validation situation. if (auto accessor = dyn_cast(FD)) { auto *storage = accessor->getStorage(); - validateDecl(storage); - if (!storage->hasValidSignature()) + if (!storage->getInterfaceType()) return; } @@ -4026,12 +4032,17 @@ void TypeChecker::validateDecl(ValueDecl *D) { break; } } - - validateGenericFuncOrSubscriptSignature(FD, FD, FD); // We want the function to be available for name lookup as soon // as it has a valid interface type. - FD->setSignatureIsValidated(); + auto resolution = TypeResolution::forInterface(FD, + FD->getGenericSignature()); + typeCheckParameterList(FD->getParameters(), resolution, + TypeResolverContext::AbstractFunctionDecl); + validateResultType(*this, FD, FD->getParameters(), + FD->getBodyResultTypeLoc(), resolution); + // FIXME: Roll all of this interface type computation into a request. + FD->computeType(); // TODO(TF-789): Figure out the proper way to typecheck these. checkDeclDifferentiableAttributes(FD); @@ -4075,12 +4086,10 @@ void TypeChecker::validateDecl(ValueDecl *D) { DeclValidationRAII IBV(CD); - validateGenericFuncOrSubscriptSignature(CD, CD, CD); - - // We want the constructor to be available for name lookup as soon - // as it has a valid interface type. - CD->setSignatureIsValidated(); - + auto res = TypeResolution::forInterface(CD, CD->getGenericSignature()); + typeCheckParameterList(CD->getParameters(), res, + TypeResolverContext::AbstractFunctionDecl); + CD->computeType(); break; } @@ -4089,9 +4098,10 @@ void TypeChecker::validateDecl(ValueDecl *D) { DeclValidationRAII IBV(DD); - validateGenericFuncOrSubscriptSignature(DD, DD, DD); - - DD->setSignatureIsValidated(); + auto res = TypeResolution::forInterface(DD, DD->getGenericSignature()); + typeCheckParameterList(DD->getParameters(), res, + TypeResolverContext::AbstractFunctionDecl); + DD->computeType(); break; } @@ -4100,9 +4110,12 @@ void TypeChecker::validateDecl(ValueDecl *D) { DeclValidationRAII IBV(SD); - validateGenericFuncOrSubscriptSignature(SD, SD, SD); - - SD->setSignatureIsValidated(); + auto res = TypeResolution::forInterface(SD, SD->getGenericSignature()); + typeCheckParameterList(SD->getIndices(), res, + TypeResolverContext::SubscriptDecl); + validateResultType(*this, SD, SD->getIndices(), + SD->getElementTypeLoc(), res); + SD->computeType(); if (SD->getOpaqueResultTypeDecl()) { if (auto SF = SD->getInnermostDeclContext()->getParentSourceFile()) { @@ -4147,8 +4160,6 @@ void TypeChecker::validateDecl(ValueDecl *D) { // type. EED->computeType(); - EED->setSignatureIsValidated(); - if (auto argTy = EED->getArgumentInterfaceType()) { assert(argTy->isMaterializable()); (void) argTy; @@ -4158,91 +4169,7 @@ void TypeChecker::validateDecl(ValueDecl *D) { } } - assert(D->hasValidSignature()); -} - -void TypeChecker::validateDeclForNameLookup(ValueDecl *D) { - // Validate the context. - auto dc = D->getDeclContext(); - if (auto nominal = dyn_cast(dc)) { - validateDeclForNameLookup(nominal); - if (!nominal->hasInterfaceType()) - return; - } else if (auto ext = dyn_cast(dc)) { - validateExtension(ext); - if (!ext->hasValidSignature()) - return; - } - - switch (D->getKind()) { - case DeclKind::Protocol: { - auto proto = cast(D); - if (proto->hasInterfaceType()) - return; - proto->computeType(); - - break; - } - case DeclKind::AssociatedType: { - auto assocType = cast(D); - if (assocType->hasInterfaceType()) - return; - assocType->computeType(); - break; - } - case DeclKind::TypeAlias: { - auto typealias = cast(D); - if (typealias->getUnderlyingTypeLoc().getType()) - return; - - // Perform earlier validation of typealiases in protocols. - if (isa(dc)) { - if (!typealias->getGenericParams()) { - if (typealias->isBeingValidated()) return; - - auto helper = [&] { - TypeResolutionOptions options( - (typealias->getGenericParams() ? - TypeResolverContext::GenericTypeAliasDecl : - TypeResolverContext::TypeAliasDecl)); - auto &underlyingTL = typealias->getUnderlyingTypeLoc(); - if (underlyingTL.isNull() || - TypeChecker::validateType(Context, - underlyingTL, - TypeResolution::forStructural(typealias), - options)) { - typealias->setInvalid(); - underlyingTL.setInvalidType(Context); - } - - typealias->setUnderlyingType(underlyingTL.getType()); - - // Note that this doesn't set the generic environment of the alias yet, - // because we haven't built one for the protocol. - // - // See how validateDecl() sets the generic environment on alias members - // explicitly. - // - // FIXME: Hopefully this can all go away with the ITC. - }; - - if (typealias->hasValidationStarted()) { - helper(); - } else { - DeclValidationRAII IBV(typealias); - helper(); - } - - return; - } - } - LLVM_FALLTHROUGH; - } - - default: - validateDecl(D); - break; - } + assert(D->hasInterfaceType()); } llvm::Expected @@ -4285,29 +4212,11 @@ EmittedMembersRequest::evaluate(Evaluator &evaluator, return CD->getMembers(); } -/// Determine whether this is a "pass-through" typealias, which has the -/// same type parameters as the nominal type it references and specializes -/// the underlying nominal type with exactly those type parameters. -/// For example, the following typealias \c GX is a pass-through typealias: -/// -/// \code -/// struct X { } -/// typealias GX = X -/// \endcode -/// -/// whereas \c GX2 and \c GX3 are not pass-through because \c GX2 has -/// different type parameters and \c GX3 doesn't pass its type parameters -/// directly through. -/// -/// \code -/// typealias GX2 = X -/// typealias GX3 = X -/// \endcode -static bool isPassThroughTypealias(TypeAliasDecl *typealias) { +bool TypeChecker::isPassThroughTypealias(TypeAliasDecl *typealias, + Type underlyingType, + NominalTypeDecl *nominal) { // Pass-through only makes sense when the typealias refers to a nominal // type. - Type underlyingType = typealias->getUnderlyingTypeLoc().getType(); - auto nominal = underlyingType->getAnyNominal(); if (!nominal) return false; // Check that the nominal type and the typealias are either both generic @@ -4356,135 +4265,6 @@ static bool isPassThroughTypealias(TypeAliasDecl *typealias) { }); } -/// Form the interface type of an extension from the raw type and the -/// extension's list of generic parameters. -static Type formExtensionInterfaceType( - TypeChecker &tc, ExtensionDecl *ext, - Type type, - GenericParamList *genericParams, - SmallVectorImpl &sameTypeReqs, - bool &mustInferRequirements) { - if (type->is()) - return type; - - // Find the nominal type declaration and its parent type. - if (type->is()) - type = type->getCanonicalType(); - - Type parentType = type->getNominalParent(); - GenericTypeDecl *genericDecl = type->getAnyGeneric(); - - // Reconstruct the parent, if there is one. - if (parentType) { - // Build the nested extension type. - auto parentGenericParams = genericDecl->getGenericParams() - ? genericParams->getOuterParameters() - : genericParams; - parentType = - formExtensionInterfaceType(tc, ext, parentType, parentGenericParams, - sameTypeReqs, mustInferRequirements); - } - - // Find the nominal type. - auto nominal = dyn_cast(genericDecl); - auto typealias = dyn_cast(genericDecl); - if (!nominal) { - Type underlyingType = typealias->getUnderlyingTypeLoc().getType(); - nominal = underlyingType->getNominalOrBoundGenericNominal(); - } - - // Form the result. - Type resultType; - SmallVector genericArgs; - if (!nominal->isGeneric() || isa(nominal)) { - resultType = NominalType::get(nominal, parentType, - nominal->getASTContext()); - } else { - auto currentBoundType = type->getAs(); - - // Form the bound generic type with the type parameters provided. - unsigned gpIndex = 0; - for (auto gp : *genericParams) { - SWIFT_DEFER { ++gpIndex; }; - - auto gpType = gp->getDeclaredInterfaceType(); - genericArgs.push_back(gpType); - - if (currentBoundType) { - sameTypeReqs.emplace_back(RequirementKind::SameType, gpType, - currentBoundType->getGenericArgs()[gpIndex]); - } - } - - resultType = BoundGenericType::get(nominal, parentType, genericArgs); - } - - // If we have a typealias, try to form type sugar. - if (typealias && isPassThroughTypealias(typealias)) { - auto typealiasSig = typealias->getGenericSignature(); - SubstitutionMap subMap; - if (typealiasSig) { - subMap = typealiasSig->getIdentitySubstitutionMap(); - - mustInferRequirements = true; - } - - resultType = TypeAliasType::get(typealias, parentType, subMap, - resultType); - } - - return resultType; -} - -/// Retrieve the generic parameter depth of the extended type. -static unsigned getExtendedTypeGenericDepth(ExtensionDecl *ext) { - auto nominal = ext->getSelfNominalTypeDecl(); - if (!nominal) return static_cast(-1); - - auto sig = nominal->getGenericSignatureOfContext(); - if (!sig) return static_cast(-1); - - return sig->getGenericParams().back()->getDepth(); -} - -/// Check the generic parameters of an extension, recursively handling all of -/// the parameter lists within the extension. -static GenericSignature * -checkExtensionGenericParams(TypeChecker &tc, ExtensionDecl *ext, - GenericParamList *genericParams) { - assert(!ext->getGenericEnvironment()); - - // Form the interface type of the extension. - bool mustInferRequirements = false; - SmallVector sameTypeReqs; - Type extInterfaceType = - formExtensionInterfaceType(tc, ext, ext->getExtendedType(), - genericParams, sameTypeReqs, - mustInferRequirements); - - assert(genericParams && "Missing generic parameters?"); - - auto cannotReuseNominalSignature = [&]() -> bool { - const auto finalDepth = genericParams->getParams().back()->getDepth(); - return mustInferRequirements - || !sameTypeReqs.empty() - || ext->getTrailingWhereClause() - || (getExtendedTypeGenericDepth(ext) != finalDepth); - }; - - // Re-use the signature of the type being extended by default. - if (cannotReuseNominalSignature()) { - return TypeChecker::checkGenericSignature( - genericParams, ext, - /*parent signature*/ nullptr, - /*allowConcreteGenericParams=*/true, - sameTypeReqs, - {TypeLoc{nullptr, extInterfaceType}}); - } - - return ext->getSelfNominalTypeDecl()->getGenericSignatureOfContext(); -} - static bool isNonGenericTypeAliasType(Type type) { // A non-generic typealias can extend a specialized type. if (auto *aliasType = dyn_cast(type.getPointer())) @@ -4517,11 +4297,24 @@ ExtendedTypeRequest::evaluate(Evaluator &eval, ExtensionDecl *ext) const { // Hack to allow extending a generic typealias. if (auto *unboundGeneric = extendedType->getAs()) { if (auto *aliasDecl = dyn_cast(unboundGeneric->getDecl())) { - auto extendedNominal = aliasDecl->getDeclaredInterfaceType()->getAnyNominal(); - if (extendedNominal) - return isPassThroughTypealias(aliasDecl) - ? extendedType - : extendedNominal->getDeclaredType(); + // Nested Hack to break cycles if this is called before validation has + // finished. + if (aliasDecl->hasInterfaceType()) { + auto extendedNominal = + aliasDecl->getDeclaredInterfaceType()->getAnyNominal(); + if (extendedNominal) + return TypeChecker::isPassThroughTypealias( + aliasDecl, aliasDecl->getUnderlyingType(), extendedNominal) + ? extendedType + : extendedNominal->getDeclaredType(); + } else { + if (auto ty = aliasDecl->getStructuralType() + ->getAs()) + return TypeChecker::isPassThroughTypealias(aliasDecl, ty, + ty->getDecl()) + ? extendedType + : ty->getDecl()->getDeclaredType(); + } } } @@ -4554,25 +4347,6 @@ ExtendedTypeRequest::evaluate(Evaluator &eval, ExtensionDecl *ext) const { return extendedType; } -void TypeChecker::validateExtension(ExtensionDecl *ext) { - // If we're currently validating, or have already validated this extension, - // there's nothing more to do now. - if (ext->hasValidationStarted()) - return; - - DeclValidationRAII IBV(ext); - - if (auto *nominal = ext->getExtendedNominal()) { - // Validate the nominal type declaration being extended. - validateDecl(nominal); - - if (auto *genericParams = ext->getGenericParams()) { - auto *sig = checkExtensionGenericParams(*this, ext, genericParams); - ext->setGenericSignature(sig); - } - } -} - /// Build a default initializer string for the given pattern. /// /// This string is suitable for display in diagnostics. diff --git a/lib/Sema/TypeCheckDecl.h b/lib/Sema/TypeCheckDecl.h index f546f78762fe9..d6eaeaf17b828 100644 --- a/lib/Sema/TypeCheckDecl.h +++ b/lib/Sema/TypeCheckDecl.h @@ -25,8 +25,6 @@ class DeclContext; class ValueDecl; class Pattern; -bool doesContextHaveValueSemantics(DeclContext *dc); - /// Walks up the override chain for \p CD until it finds an initializer that is /// required and non-implicit. If no such initializer exists, returns the /// declaration where \c required was introduced (i.e. closest to the root diff --git a/lib/Sema/TypeCheckDeclObjC.cpp b/lib/Sema/TypeCheckDeclObjC.cpp index 66cc11d8ea4bc..c5e28afa2514c 100644 --- a/lib/Sema/TypeCheckDeclObjC.cpp +++ b/lib/Sema/TypeCheckDeclObjC.cpp @@ -23,6 +23,7 @@ #include "swift/AST/ForeignErrorConvention.h" #include "swift/AST/ImportCache.h" #include "swift/AST/ParameterList.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/TypeCheckRequests.h" #include "swift/Basic/StringExtras.h" using namespace swift; @@ -240,12 +241,6 @@ static bool isParamListRepresentableInObjC(const AbstractFunctionDecl *AFD, // If you change this function, you must add or modify a test in PrintAsObjC. ASTContext &ctx = AFD->getASTContext(); auto &diags = ctx.Diags; - - if (!AFD->hasInterfaceType()) { - ctx.getLazyResolver()->resolveDeclSignature( - const_cast(AFD)); - } - bool Diagnose = shouldDiagnoseObjCReason(Reason, ctx); bool IsObjC = true; unsigned NumParams = PL->size(); @@ -493,6 +488,8 @@ bool swift::isRepresentableInObjC( // If you change this function, you must add or modify a test in PrintAsObjC. ASTContext &ctx = AFD->getASTContext(); + // FIXME(InterfaceTypeRequest): Remove this. + (void)AFD->getInterfaceType(); bool Diagnose = shouldDiagnoseObjCReason(Reason, ctx); if (checkObjCInForeignClassContext(AFD, Reason)) @@ -688,11 +685,6 @@ bool swift::isRepresentableInObjC( auto nsError = ctx.getNSErrorDecl(); Type errorParameterType; if (nsError) { - if (!nsError->hasInterfaceType()) { - auto resolver = ctx.getLazyResolver(); - assert(resolver); - resolver->resolveDeclSignature(nsError); - } errorParameterType = nsError->getDeclaredInterfaceType(); errorParameterType = OptionalType::get(errorParameterType); errorParameterType @@ -821,19 +813,15 @@ bool swift::isRepresentableInObjC( bool swift::isRepresentableInObjC(const VarDecl *VD, ObjCReason Reason) { // If you change this function, you must add or modify a test in PrintAsObjC. - if (VD->isInvalid()) + if (!VD->getInterfaceType()) { + VD->diagnose(diag::recursive_decl_reference, VD->getDescriptiveKind(), + VD->getName()); return false; - - if (!VD->hasInterfaceType()) { - VD->getASTContext().getLazyResolver()->resolveDeclSignature( - const_cast(VD)); - if (!VD->hasInterfaceType()) { - VD->diagnose(diag::recursive_decl_reference, VD->getDescriptiveKind(), - VD->getName()); - return false; - } } + if (VD->isInvalid()) + return false; + Type T = VD->getDeclContext()->mapTypeIntoContext(VD->getInterfaceType()); if (auto *RST = T->getAs()) { // In-memory layout of @weak and @unowned does not correspond to anything @@ -889,11 +877,6 @@ bool swift::isRepresentableInObjC(const SubscriptDecl *SD, ObjCReason Reason) { return true; } - if (!SD->hasInterfaceType()) { - SD->getASTContext().getLazyResolver()->resolveDeclSignature( - const_cast(SD)); - } - // Figure out the type of the indices. auto SubscriptType = SD->getInterfaceType()->getAs(); if (!SubscriptType) @@ -1026,11 +1009,8 @@ static void checkObjCBridgingFunctions(ModuleDecl *mod, NLKind::QualifiedLookup, results); for (auto D : results) { - if (!D->hasInterfaceType()) { - auto resolver = ctx.getLazyResolver(); - assert(resolver); - resolver->resolveDeclSignature(D); - } + // FIXME(InterfaceTypeRequest): Remove this. + (void)D->getInterfaceType(); } } @@ -1343,13 +1323,8 @@ static bool isCIntegerType(Type type) { foundDecls); for (auto found : foundDecls) { auto foundType = dyn_cast(found); - if (!foundType) continue; - - if (!foundType->hasInterfaceType()) { - auto resolver = ctx.getLazyResolver(); - assert(resolver); - resolver->resolveDeclSignature(foundType); - } + if (!foundType) + continue; if (foundType->getDeclaredInterfaceType()->isEqual(type)) return true; diff --git a/lib/Sema/TypeCheckDeclOverride.cpp b/lib/Sema/TypeCheckDeclOverride.cpp index be726e2105955..36f007050dddf 100644 --- a/lib/Sema/TypeCheckDeclOverride.cpp +++ b/lib/Sema/TypeCheckDeclOverride.cpp @@ -76,20 +76,8 @@ Type swift::getMemberTypeForComparison(ASTContext &ctx, ValueDecl *member, assert((method || abstractStorage) && "Not a method or abstractStorage?"); SubscriptDecl *subscript = dyn_cast_or_null(abstractStorage); - if (!member->hasInterfaceType()) { - auto lazyResolver = ctx.getLazyResolver(); - assert(lazyResolver && "Need to resolve interface type"); - lazyResolver->resolveDeclSignature(member); - } - auto memberType = member->getInterfaceType(); if (derivedDecl) { - if (!derivedDecl->hasInterfaceType()) { - auto lazyResolver = ctx.getLazyResolver(); - assert(lazyResolver && "Need to resolve interface type"); - lazyResolver->resolveDeclSignature(derivedDecl); - } - auto *dc = derivedDecl->getDeclContext(); auto owningType = dc->getDeclaredInterfaceType(); assert(owningType); diff --git a/lib/Sema/TypeCheckExpr.cpp b/lib/Sema/TypeCheckExpr.cpp index c09e8e2e7ce80..620ec1c159f8f 100644 --- a/lib/Sema/TypeCheckExpr.cpp +++ b/lib/Sema/TypeCheckExpr.cpp @@ -20,6 +20,7 @@ #include "swift/AST/Decl.h" #include "swift/AST/Initializer.h" #include "swift/AST/ParameterList.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/TypeCheckRequests.h" #include "swift/Parse/Lexer.h" using namespace swift; @@ -649,8 +650,10 @@ static Type lookupDefaultLiteralType(TypeChecker &TC, const DeclContext *dc, TypeDecl *TD = lookup.getSingleTypeResult(); if (!TD) return Type(); - TC.validateDecl(TD); - + + // FIXME: Make isInvalid ask for the interface type. + (void)TD->getInterfaceType(); + if (TD->isInvalid()) return Type(); diff --git a/lib/Sema/TypeCheckExprObjC.cpp b/lib/Sema/TypeCheckExprObjC.cpp index c85dc0173ed5f..74710b189877d 100644 --- a/lib/Sema/TypeCheckExprObjC.cpp +++ b/lib/Sema/TypeCheckExprObjC.cpp @@ -318,8 +318,6 @@ Optional TypeChecker::checkObjCKeyPathExpr(DeclContext *dc, // Handle property references. if (auto var = dyn_cast(found)) { - validateDecl(var); - // Resolve this component to the variable we found. auto varRef = ConcreteDeclRef(var); auto resolved = diff --git a/lib/Sema/TypeCheckGeneric.cpp b/lib/Sema/TypeCheckGeneric.cpp index c4f53ef1e9b8f..0a65d7db6870f 100644 --- a/lib/Sema/TypeCheckGeneric.cpp +++ b/lib/Sema/TypeCheckGeneric.cpp @@ -443,144 +443,6 @@ void TypeChecker::checkReferencedGenericParams(GenericContext *dc) { } } -void TypeChecker::validateGenericFuncOrSubscriptSignature( - PointerUnion - funcOrSubscript, - ValueDecl *decl, GenericContext *genCtx) { - auto func = funcOrSubscript.dyn_cast(); - auto subscr = funcOrSubscript.dyn_cast(); - - auto gpList = genCtx->getGenericParams(); - if (gpList) { - // Do some initial configuration of the generic parameter lists that's - // required in all cases. - gpList->setDepth(genCtx->getGenericContextDepth()); - } else { - // Inherit the signature of the surrounding environment. - genCtx->setGenericSignature( - decl->getDeclContext()->getGenericSignatureOfContext()); - } - - // Accessors can always use the generic context of their storage - // declarations. This is a compile-time optimization since it lets us - // avoid the requirements-gathering phase, but it also simplifies that - // work for accessors which don't mention the value type in their formal - // signatures (like the read and modify coroutines, since yield types - // aren't tracked in the AST type yet). - if (auto accessor = dyn_cast(decl)) { - auto subscr = dyn_cast(accessor->getStorage()); - if (gpList && subscr) { - genCtx->setGenericSignature(subscr->getGenericSignature()); - } - // We've inherited all of the type information already. - accessor->computeType(); - return; - } - - // Use the generic signature of the surrounding context by default. - GenericSignature *sig = - decl->getDeclContext()->getGenericSignatureOfContext(); - - auto params = func ? func->getParameters() : subscr->getIndices(); - TypeLoc emptyLoc; - TypeLoc &resultTyLoc = [&]() -> TypeLoc& { - if (subscr) - return subscr->getElementTypeLoc(); - if (auto fn = dyn_cast(func)) - return fn->getBodyResultTypeLoc(); - return emptyLoc; - }(); - - if (gpList) { - // Gather requirements from the parameter list. - auto resolution = TypeResolution::forStructural(genCtx); - - TypeResolutionOptions options = - (func - ? TypeResolverContext::AbstractFunctionDecl - : TypeResolverContext::SubscriptDecl); - - SmallVector inferenceSources; - for (auto param : *params) { - auto *typeRepr = param->getTypeLoc().getTypeRepr(); - if (typeRepr == nullptr) - continue; - - auto paramOptions = options; - paramOptions.setContext(param->isVariadic() ? - TypeResolverContext::VariadicFunctionInput : - TypeResolverContext::FunctionInput); - paramOptions |= TypeResolutionFlags::Direct; - - auto type = resolution.resolveType(typeRepr, paramOptions); - - if (auto *specifier = dyn_cast_or_null(typeRepr)) - typeRepr = specifier->getBase(); - - inferenceSources.emplace_back(typeRepr, type); - } - - // Gather requirements from the result type. - auto *resultTypeRepr = resultTyLoc.getTypeRepr(); - if (resultTypeRepr && !isa(resultTypeRepr)) { - TypeResolutionOptions resultOptions = TypeResolverContext::FunctionResult; - - auto resultType = resolution.resolveType(resultTypeRepr, resultOptions); - - inferenceSources.emplace_back(resultTypeRepr, resultType); - } - - // The signature is complete and well-formed. Determine - // the type of the generic function or subscript. - auto request = InferredGenericSignatureRequest{ - genCtx->getParentModule(), - decl->getDeclContext() - ->getGenericSignatureOfContext(), - {gpList}, {}, inferenceSources, - /*allowConcreteGenericParams=*/false}; - sig = evaluateOrDefault(Context.evaluator, request, nullptr); - - // Debugging of the generic signature. - if (Context.LangOpts.DebugGenericSignatures) { - decl->dumpRef(llvm::errs()); - llvm::errs() << "\n"; - llvm::errs() << "Generic signature: "; - sig->print(llvm::errs()); - llvm::errs() << "\n"; - llvm::errs() << "Canonical generic signature: "; - sig->getCanonicalSignature()->print(llvm::errs()); - llvm::errs() << "\n"; - } - - genCtx->setGenericSignature(sig); - } - - auto resolution = TypeResolution::forInterface(genCtx, sig); - // Check parameter patterns. - typeCheckParameterList(params, resolution, func - ? TypeResolverContext::AbstractFunctionDecl - : TypeResolverContext::SubscriptDecl); - - if (!resultTyLoc.isNull()) { - // Check the result type. It is allowed to be opaque. - if (auto opaqueTy = dyn_cast_or_null( - resultTyLoc.getTypeRepr())) { - // Create the decl and type for it. - resultTyLoc.setType( - getOrCreateOpaqueResultType(resolution, decl, opaqueTy)); - } else { - validateType(Context, resultTyLoc, resolution, - TypeResolverContext::FunctionResult); - } - } - - func ? func->computeType() : subscr->computeType(); - - // Make sure that there are no unresolved dependent types in the - // generic signature. - assert(!decl->getInterfaceType()->findUnresolvedDependentMemberType()); -} - /// /// Generic types /// @@ -614,7 +476,11 @@ GenericSignature *TypeChecker::checkGenericSignature( // Debugging of the generic signature builder and generic signature // generation. if (dc->getASTContext().LangOpts.DebugGenericSignatures) { - dc->printContext(llvm::errs()); + if (auto *VD = dyn_cast_or_null(dc->getAsDecl())) { + VD->dumpRef(llvm::errs()); + } else { + dc->printContext(llvm::errs()); + } llvm::errs() << "\n"; llvm::errs() << "Generic signature: "; sig->print(llvm::errs()); @@ -627,8 +493,108 @@ GenericSignature *TypeChecker::checkGenericSignature( return sig; } -void TypeChecker::validateGenericTypeSignature(GenericTypeDecl *typeDecl) { - if (auto *proto = dyn_cast(typeDecl)) { +/// Form the interface type of an extension from the raw type and the +/// extension's list of generic parameters. +static Type formExtensionInterfaceType( + ExtensionDecl *ext, Type type, + GenericParamList *genericParams, + SmallVectorImpl &sameTypeReqs, + bool &mustInferRequirements) { + if (type->is()) + return type; + + // Find the nominal type declaration and its parent type. + if (type->is()) + type = type->getCanonicalType(); + + Type parentType = type->getNominalParent(); + GenericTypeDecl *genericDecl = type->getAnyGeneric(); + + // Reconstruct the parent, if there is one. + if (parentType) { + // Build the nested extension type. + auto parentGenericParams = genericDecl->getGenericParams() + ? genericParams->getOuterParameters() + : genericParams; + parentType = + formExtensionInterfaceType(ext, parentType, parentGenericParams, + sameTypeReqs, mustInferRequirements); + } + + // Find the nominal type. + auto nominal = dyn_cast(genericDecl); + auto typealias = dyn_cast(genericDecl); + if (!nominal) { + Type underlyingType = typealias->getUnderlyingType(); + nominal = underlyingType->getNominalOrBoundGenericNominal(); + } + + // Form the result. + Type resultType; + SmallVector genericArgs; + if (!nominal->isGeneric() || isa(nominal)) { + resultType = NominalType::get(nominal, parentType, + nominal->getASTContext()); + } else { + auto currentBoundType = type->getAs(); + + // Form the bound generic type with the type parameters provided. + unsigned gpIndex = 0; + for (auto gp : *genericParams) { + SWIFT_DEFER { ++gpIndex; }; + + auto gpType = gp->getDeclaredInterfaceType(); + genericArgs.push_back(gpType); + + if (currentBoundType) { + sameTypeReqs.emplace_back(RequirementKind::SameType, gpType, + currentBoundType->getGenericArgs()[gpIndex]); + } + } + + resultType = BoundGenericType::get(nominal, parentType, genericArgs); + } + + // If we have a typealias, try to form type sugar. + if (typealias && TypeChecker::isPassThroughTypealias( + typealias, typealias->getUnderlyingType(), nominal)) { + auto typealiasSig = typealias->getGenericSignature(); + SubstitutionMap subMap; + if (typealiasSig) { + subMap = typealiasSig->getIdentitySubstitutionMap(); + + mustInferRequirements = true; + } + + resultType = TypeAliasType::get(typealias, parentType, subMap, resultType); + } + + + return resultType; +} + +/// Retrieve the generic parameter depth of the extended type. +static unsigned getExtendedTypeGenericDepth(ExtensionDecl *ext) { + auto nominal = ext->getSelfNominalTypeDecl(); + if (!nominal) return static_cast(-1); + + auto sig = nominal->getGenericSignatureOfContext(); + if (!sig) return static_cast(-1); + + return sig->getGenericParams().back()->getDepth(); +} + +llvm::Expected +GenericSignatureRequest::evaluate(Evaluator &evaluator, + GenericContext *GC) const { + // The signature of a Protocol is trivial (Self: TheProtocol) so let's compute + // it. + if (auto PD = dyn_cast(GC)) { + auto self = PD->getSelfInterfaceType()->castTo(); + auto req = + Requirement(RequirementKind::Conformance, self, PD->getDeclaredType()); + auto *sig = GenericSignature::get({self}, {req}); + // The requirement signature is created lazily by // ProtocolDecl::getRequirementSignature(). // The generic signature and environment is created lazily by @@ -637,10 +603,8 @@ void TypeChecker::validateGenericTypeSignature(GenericTypeDecl *typeDecl) { // Debugging of the generic signature builder and generic signature // generation. - if (Context.LangOpts.DebugGenericSignatures) { - auto *sig = proto->getGenericSignature(); - - proto->printContext(llvm::errs()); + if (GC->getASTContext().LangOpts.DebugGenericSignatures) { + PD->printContext(llvm::errs()); llvm::errs() << "\n"; llvm::errs() << "Generic signature: "; sig->print(llvm::errs()); @@ -649,32 +613,124 @@ void TypeChecker::validateGenericTypeSignature(GenericTypeDecl *typeDecl) { sig->getCanonicalSignature()->print(llvm::errs()); llvm::errs() << "\n"; } + return sig; + } - return; + // We can fast-path computing the generic signature of non-generic + // declarations by re-using the parent context's signature. + auto *gp = GC->getGenericParams(); + if (!gp) { + return GC->getParent()->getGenericSignatureOfContext(); + } + + // Setup the depth of the generic parameters. + gp->setDepth(GC->getGenericContextDepth()); + + // Accessors can always use the generic context of their storage + // declarations. This is a compile-time optimization since it lets us + // avoid the requirements-gathering phase, but it also simplifies that + // work for accessors which don't mention the value type in their formal + // signatures (like the read and modify coroutines, since yield types + // aren't tracked in the AST type yet). + if (auto accessor = dyn_cast(GC->getAsDecl())) { + return cast(accessor->getStorage())->getGenericSignature(); } - assert(!typeDecl->getGenericEnvironment()); + bool allowConcreteGenericParams = false; + SmallVector inferenceSources; + SmallVector sameTypeReqs; + if (auto VD = dyn_cast_or_null(GC->getAsDecl())) { + auto func = dyn_cast(VD); + auto subscr = dyn_cast(VD); + + // For functions and subscripts, resolve the parameter and result types and + // note them as inference sources. + if (subscr || func) { + // Gather requirements from the parameter list. + auto resolution = TypeResolution::forStructural(GC); + + TypeResolutionOptions options = + (func ? TypeResolverContext::AbstractFunctionDecl + : TypeResolverContext::SubscriptDecl); + + auto params = func ? func->getParameters() : subscr->getIndices(); + for (auto param : *params) { + auto *typeRepr = param->getTypeLoc().getTypeRepr(); + if (typeRepr == nullptr) + continue; - // We don't go down this path for protocols; instead, the generic signature - // is simple enough that GenericContext::getGenericSignature() can build it - // directly. - assert(!isa(typeDecl)); + auto paramOptions = options; + paramOptions.setContext(param->isVariadic() + ? TypeResolverContext::VariadicFunctionInput + : TypeResolverContext::FunctionInput); + paramOptions |= TypeResolutionFlags::Direct; - auto *gp = typeDecl->getGenericParams(); - auto *dc = typeDecl->getDeclContext(); + auto type = resolution.resolveType(typeRepr, paramOptions); - if (!gp) { - typeDecl->setGenericSignature(dc->getGenericSignatureOfContext()); - return; - } + if (auto *specifier = dyn_cast(typeRepr)) + typeRepr = specifier->getBase(); + + inferenceSources.emplace_back(typeRepr, type); + } + + // Gather requirements from the result type. + auto *resultTypeRepr = [&subscr, &func]() -> TypeRepr * { + if (subscr) { + return subscr->getElementTypeLoc().getTypeRepr(); + } else if (auto *FD = dyn_cast(func)) { + return FD->getBodyResultTypeLoc().getTypeRepr(); + } else { + return nullptr; + } + }(); + if (resultTypeRepr && !isa(resultTypeRepr)) { + auto resultType = resolution.resolveType( + resultTypeRepr, TypeResolverContext::FunctionResult); - gp->setDepth(typeDecl->getGenericContextDepth()); + inferenceSources.emplace_back(resultTypeRepr, resultType); + } + } + } else if (auto *ext = dyn_cast(GC)) { + // Form the interface type of the extension so we can use it as an inference + // source. + // + // FIXME: Push this into the "get interface type" request. + bool mustInferRequirements = false; + Type extInterfaceType = + formExtensionInterfaceType(ext, ext->getExtendedType(), + gp, sameTypeReqs, + mustInferRequirements); + + auto cannotReuseNominalSignature = [&]() -> bool { + const auto finalDepth = gp->getParams().back()->getDepth(); + return mustInferRequirements + || !sameTypeReqs.empty() + || ext->getTrailingWhereClause() + || (getExtendedTypeGenericDepth(ext) != finalDepth); + }; + + // Re-use the signature of the type being extended by default. + if (!cannotReuseNominalSignature()) { + return ext->getSelfNominalTypeDecl()->getGenericSignatureOfContext(); + } + + // Allow parameters to be equated with concrete types. + allowConcreteGenericParams = true; + inferenceSources.emplace_back(nullptr, extInterfaceType); + } - auto *sig = TypeChecker::checkGenericSignature( - gp, dc, - dc->getGenericSignatureOfContext(), - /*allowConcreteGenericParams=*/false); - typeDecl->setGenericSignature(sig); + // EGREGIOUS HACK: The GSB cannot handle the addition of parent signatures + // from malformed decls in many cases. Check the invalid bit and null out the + // parent signature. + auto *parentSig = GC->getParent()->getGenericSignatureOfContext(); + if (auto *DD = GC->getParent()->getAsDecl()) { + parentSig = DD->isInvalid() ? nullptr : parentSig; + } + + return TypeChecker::checkGenericSignature( + gp, GC, parentSig, + allowConcreteGenericParams, + sameTypeReqs, inferenceSources); } /// @@ -910,15 +966,37 @@ RequirementRequest::evaluate(Evaluator &evaluator, } llvm::Expected -swift::StructuralTypeRequest::evaluate(Evaluator &evaluator, - TypeAliasDecl *D) const { - TypeResolutionOptions options(TypeResolverContext::TypeAliasDecl); - if (!D->getDeclContext()->isCascadingContextForLookup( - /*functionsAreNonCascading*/true)) { +StructuralTypeRequest::evaluate(Evaluator &evaluator, + TypeAliasDecl *typeAlias) const { + TypeResolutionOptions options((typeAlias->getGenericParams() + ? TypeResolverContext::GenericTypeAliasDecl + : TypeResolverContext::TypeAliasDecl)); + + if (!typeAlias->getDeclContext()->isCascadingContextForLookup( + /*functionsAreNonCascading*/ true)) { options |= TypeResolutionFlags::KnownNonCascadingDependency; } + + // This can happen when code completion is attempted inside + // of typealias underlying type e.g. `typealias F = () -> Int#^TOK^#` + auto &ctx = typeAlias->getASTContext(); + auto underlyingTypeRepr = typeAlias->getUnderlyingTypeRepr(); + if (!underlyingTypeRepr) { + typeAlias->setInvalid(); + return ErrorType::get(ctx); + } - auto typeRepr = D->getUnderlyingTypeLoc().getTypeRepr(); - auto resolution = TypeResolution::forStructural(D); - return resolution.resolveType(typeRepr, options); + auto resolution = TypeResolution::forStructural(typeAlias); + auto type = resolution.resolveType(underlyingTypeRepr, options); + + auto *genericSig = typeAlias->getGenericSignature(); + SubstitutionMap subs; + if (genericSig) + subs = genericSig->getIdentitySubstitutionMap(); + + Type parent; + auto parentDC = typeAlias->getDeclContext(); + if (parentDC->isTypeContext()) + parent = parentDC->getDeclaredInterfaceType(); + return TypeAliasType::get(typeAlias, parent, subs, type); } diff --git a/lib/Sema/TypeCheckNameLookup.cpp b/lib/Sema/TypeCheckNameLookup.cpp index dc7979df10424..4e6d82e4ba6cf 100644 --- a/lib/Sema/TypeCheckNameLookup.cpp +++ b/lib/Sema/TypeCheckNameLookup.cpp @@ -423,10 +423,9 @@ LookupTypeResult TypeChecker::lookupMemberType(DeclContext *dc, auto *typeDecl = cast(decl); // FIXME: This should happen before we attempt shadowing checks. - if (!typeDecl->hasInterfaceType()) { - dc->getASTContext().getLazyResolver()->resolveDeclSignature(typeDecl); - if (!typeDecl->hasInterfaceType()) // FIXME: recursion-breaking hack - continue; + if (!typeDecl->getInterfaceType()) { + // FIXME: recursion-breaking hack + continue; } auto memberType = typeDecl->getDeclaredInterfaceType(); @@ -497,7 +496,7 @@ LookupTypeResult TypeChecker::lookupMemberType(DeclContext *dc, auto *protocol = cast(assocType->getDeclContext()); // If we're validating the protocol recursively, bail out. - if (!protocol->hasValidSignature()) + if (!protocol->hasInterfaceType()) continue; auto conformance = conformsToProtocol(type, protocol, dc, diff --git a/lib/Sema/TypeCheckPattern.cpp b/lib/Sema/TypeCheckPattern.cpp index 587d2644bedb4..497083195b026 100644 --- a/lib/Sema/TypeCheckPattern.cpp +++ b/lib/Sema/TypeCheckPattern.cpp @@ -1497,7 +1497,7 @@ bool TypeChecker::coercePatternToType(Pattern *&P, TypeResolution resolution, } // If there is a subpattern, push the enum element type down onto it. - validateDeclForNameLookup(elt); + auto argType = elt->getArgumentInterfaceType(); if (EEP->hasSubPattern()) { Pattern *sub = EEP->getSubPattern(); if (!elt->hasAssociatedValues()) { @@ -1510,7 +1510,7 @@ bool TypeChecker::coercePatternToType(Pattern *&P, TypeResolution resolution, } Type elementType; - if (auto argType = elt->getArgumentInterfaceType()) + if (argType) elementType = enumTy->getTypeOfMember(elt->getModuleContext(), elt, argType); else @@ -1524,7 +1524,7 @@ bool TypeChecker::coercePatternToType(Pattern *&P, TypeResolution resolution, if (coercePatternToType(sub, resolution, elementType, newSubOptions)) return true; EEP->setSubPattern(sub); - } else if (auto argType = elt->getArgumentInterfaceType()) { + } else if (argType) { // Else if the element pattern has no sub-pattern but the element type has // associated values, expand it to be semantically equivalent to an // element pattern of wildcards. diff --git a/lib/Sema/TypeCheckPropertyWrapper.cpp b/lib/Sema/TypeCheckPropertyWrapper.cpp index 01fa9a7e116bc..9d4b6894f5e88 100644 --- a/lib/Sema/TypeCheckPropertyWrapper.cpp +++ b/lib/Sema/TypeCheckPropertyWrapper.cpp @@ -126,13 +126,9 @@ static ConstructorDecl *findInitialValueInit(ASTContext &ctx, } // Retrieve the type of the 'value' property. - if (!valueVar->hasInterfaceType()) - ctx.getLazyResolver()->resolveDeclSignature(valueVar); Type valueVarType = valueVar->getValueInterfaceType(); // Retrieve the parameter type of the initializer. - if (!init->hasInterfaceType()) - ctx.getLazyResolver()->resolveDeclSignature(init); Type paramType; if (auto *curriedInitType = init->getInterfaceType()->getAs()) { @@ -301,9 +297,9 @@ PropertyWrapperTypeInfoRequest::evaluate( if (!valueVar) return PropertyWrapperTypeInfo(); - if (!valueVar->hasInterfaceType()) - static_cast(*ctx.getLazyResolver()).validateDecl(valueVar); - + // FIXME: Remove this one + (void)valueVar->getInterfaceType(); + PropertyWrapperTypeInfo result; result.valueVar = valueVar; result.wrappedValueInit = @@ -529,7 +525,8 @@ PropertyWrapperBackingPropertyTypeRequest::evaluate( unsigned index = binding->getPatternEntryIndexForVarDecl(var); TypeChecker &tc = *static_cast(ctx.getLazyResolver()); if (binding->isInitialized(index)) { - tc.validateDecl(var); + // FIXME(InterfaceTypeRequest): Remove this. + (void)var->getInterfaceType(); if (!binding->isInitializerChecked(index)) tc.typeCheckPatternBinding(binding, index); @@ -539,7 +536,8 @@ PropertyWrapperBackingPropertyTypeRequest::evaluate( } // Compute the type of the property to plug in to the wrapper type. - tc.validateDecl(var); + // FIXME(InterfaceTypeRequest): Remove this. + (void)var->getInterfaceType(); Type propertyType = var->getType(); if (!propertyType || propertyType->hasError()) return Type(); @@ -609,17 +607,11 @@ Type swift::computeWrappedValueType(VarDecl *var, Type backingStorageType, // Follow the chain of wrapped value properties. Type wrappedValueType = backingStorageType; DeclContext *dc = var->getDeclContext(); - ASTContext &ctx = dc->getASTContext(); for (unsigned i : range(realLimit)) { auto wrappedInfo = var->getAttachedPropertyWrapperTypeInfo(i); if (!wrappedInfo) return wrappedValueType; - if (!wrappedInfo.valueVar->hasInterfaceType()) { - static_cast(*ctx.getLazyResolver()).validateDecl( - wrappedInfo.valueVar); - } - wrappedValueType = wrappedValueType->getTypeOfMember( dc->getParentModule(), wrappedInfo.valueVar, diff --git a/lib/Sema/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp index e42fdd389e778..812fdee10256f 100644 --- a/lib/Sema/TypeCheckProtocol.cpp +++ b/lib/Sema/TypeCheckProtocol.cpp @@ -329,18 +329,12 @@ swift::matchWitness( if (req->getKind() != witness->getKind()) return RequirementMatch(witness, MatchKind::KindConflict); - // If the witness has not been validated yet, do so now. - if (!witness->hasValidSignature()) { - auto &ctx = dc->getASTContext(); - ctx.getLazyResolver()->resolveDeclSignature(witness); - } - // If the witness is invalid, record that and stop now. if (witness->isInvalid()) return RequirementMatch(witness, MatchKind::WitnessInvalid); // If we're currently validating the witness, bail out. - if (!witness->hasValidSignature()) + if (!witness->getInterfaceType()) return RequirementMatch(witness, MatchKind::Circularity); // Get the requirement and witness attributes. @@ -1602,8 +1596,10 @@ checkIndividualConformance(NormalProtocolConformance *conformance, conformance->setState(ProtocolConformanceState::Checking); SWIFT_DEFER { conformance->setState(ProtocolConformanceState::Complete); }; - TC.validateDecl(Proto); - + // FIXME(InterfaceTypeRequest): isInvalid() should be based on the interface + // type. + (void)Proto->getInterfaceType(); + // If the protocol itself is invalid, there's nothing we can do. if (Proto->isInvalid()) { conformance->setInvalid(); @@ -2288,11 +2284,7 @@ ConformanceChecker::ConformanceChecker( Conformance(conformance), Loc(conformance->getLoc()), GlobalMissingWitnesses(GlobalMissingWitnesses), LocalMissingWitnessesStartIndex(GlobalMissingWitnesses.size()), - SuppressDiagnostics(suppressDiagnostics) { - // The protocol may have only been validatedDeclForNameLookup'd until - // here, so fill in any information that's missing. - tc.validateDecl(conformance->getProtocol()); -} + SuppressDiagnostics(suppressDiagnostics) { } ArrayRef ConformanceChecker::getReferencedAssociatedTypes(ValueDecl *req) { @@ -2563,7 +2555,9 @@ void ConformanceChecker::recordTypeWitness(AssociatedTypeDecl *assocType, DC); aliasDecl->setGenericSignature(DC->getGenericSignatureOfContext()); aliasDecl->setUnderlyingType(type); - + aliasDecl->setValidationToChecked(); + aliasDecl->computeType(); + aliasDecl->setImplicit(); if (type->hasError()) aliasDecl->setInvalid(); @@ -3486,6 +3480,8 @@ CheckTypeWitnessResult swift::checkTypeWitness(TypeChecker &tc, DeclContext *dc, Type contextType = type->hasTypeParameter() ? dc->mapTypeIntoContext(type) : type; + // FIXME: This is incorrect; depTy is written in terms of the protocol's + // associated types, and we need to substitute in known type witnesses. if (auto superclass = genericSig->getSuperclassBound(depTy)) { if (!superclass->isExactSuperclassOf(contextType)) return superclass; @@ -3933,11 +3929,8 @@ void ConformanceChecker::resolveValueWitnesses() { continue; } - // Make sure we've validated the requirement. - if (!requirement->hasInterfaceType()) - TC.validateDecl(requirement); - - if (requirement->isInvalid() || !requirement->hasValidSignature()) { + // Make sure we've got an interface type. + if (!requirement->getInterfaceType() || requirement->isInvalid()) { Conformance->setInvalid(); continue; } @@ -4053,7 +4046,7 @@ static void diagnoseConformanceFailure(Type T, TypeChecker::containsProtocol(T, Proto, DC, None)) { if (!T->isObjCExistentialType()) { - diags.diagnose(ComplainLoc, diag::protocol_does_not_conform_objc, + diags.diagnose(ComplainLoc, diag::type_cannot_conform, true, T, Proto->getDeclaredType()); return; } diff --git a/lib/Sema/TypeCheckProtocolInference.cpp b/lib/Sema/TypeCheckProtocolInference.cpp index de33075c90ccf..eaa223dae4091 100644 --- a/lib/Sema/TypeCheckProtocolInference.cpp +++ b/lib/Sema/TypeCheckProtocolInference.cpp @@ -188,21 +188,22 @@ AssociatedTypeInference::inferTypeWitnessesViaValueWitnesses( // Invalid case. if (extendedNominal == nullptr) return true; - + // Assume unconstrained concrete extensions we found witnesses in are // always viable. if (!isa(extendedNominal)) return !extension->isConstrainedExtension(); - - // Build a generic signature. - tc.validateExtension(extension); - - // The extension may not have a generic signature set up yet, as a - // recursion breaker, in which case we can't yet confidently reject its - // witnesses. - if (!extension->getGenericSignature()) + + // FIXME: The extension may not have a generic signature set up yet as + // resolving signatures may trigger associated type inference. This cycle + // is now detectable and we should look into untangling it + // - see rdar://55263708 + if (!extension->hasComputedGenericSignature()) return true; + // Build a generic signature. + auto *extensionSig = extension->getGenericSignature(); + // The condition here is a bit more fickle than // `isExtensionApplied`. That check would prematurely reject // extensions like `P where AssocType == T` if we're relying on a @@ -211,8 +212,7 @@ AssociatedTypeInference::inferTypeWitnessesViaValueWitnesses( // because those have to be explicitly declared on the type somewhere // so won't be affected by whatever answer inference comes up with. auto selfTy = extension->getSelfInterfaceType(); - for (const Requirement &reqt - : extension->getGenericSignature()->getRequirements()) { + for (const Requirement &reqt : extensionSig->getRequirements()) { switch (reqt.getKind()) { case RequirementKind::Conformance: case RequirementKind::Superclass: @@ -447,8 +447,7 @@ AssociatedTypeInference::inferTypeWitnessesViaValueWitnesses( } // Validate the requirement. - tc.validateDecl(req); - if (req->isInvalid() || !req->hasValidSignature()) + if (!req->getInterfaceType() || req->isInvalid()) continue; // Check whether any of the associated types we care about are @@ -493,10 +492,10 @@ static Type mapErrorTypeToOriginal(Type type) { static Type getWitnessTypeForMatching(TypeChecker &tc, NormalProtocolConformance *conformance, ValueDecl *witness) { - if (!witness->hasInterfaceType()) - tc.validateDecl(witness); + if (!witness->getInterfaceType()) + return Type(); - if (witness->isInvalid() || !witness->hasValidSignature()) + if (witness->isInvalid()) return Type(); if (!witness->getDeclContext()->isTypeContext()) { @@ -765,7 +764,6 @@ AssociatedTypeDecl *AssociatedTypeInference::findDefaultedAssociatedType( TypeChecker &tc, AssociatedTypeDecl *assocType) { // If this associated type has a default, we're done. - tc.validateDecl(assocType); if (assocType->hasDefaultDefinitionType()) return assocType; @@ -2031,10 +2029,7 @@ void ConformanceChecker::resolveSingleWitness(ValueDecl *requirement) { SWIFT_DEFER { ResolvingWitnesses.erase(requirement); }; // Make sure we've validated the requirement. - if (!requirement->hasInterfaceType()) - TC.validateDecl(requirement); - - if (requirement->isInvalid() || !requirement->hasValidSignature()) { + if (!requirement->getInterfaceType() || requirement->isInvalid()) { Conformance->setInvalid(); return; } diff --git a/lib/Sema/TypeCheckREPL.cpp b/lib/Sema/TypeCheckREPL.cpp index 5b17866ce853e..5760db078057c 100644 --- a/lib/Sema/TypeCheckREPL.cpp +++ b/lib/Sema/TypeCheckREPL.cpp @@ -21,6 +21,7 @@ #include "swift/AST/Expr.h" #include "swift/AST/NameLookup.h" #include "swift/AST/ParameterList.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/Stmt.h" #include "swift/Parse/LocalContext.h" #include "llvm/ADT/SmallString.h" diff --git a/lib/Sema/TypeCheckStmt.cpp b/lib/Sema/TypeCheckStmt.cpp index 4ed8adf5f1898..3eb19fa014638 100644 --- a/lib/Sema/TypeCheckStmt.cpp +++ b/lib/Sema/TypeCheckStmt.cpp @@ -30,6 +30,7 @@ #include "swift/AST/NameLookup.h" #include "swift/AST/ParameterList.h" #include "swift/AST/PrettyStackTrace.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/TypeCheckRequests.h" #include "swift/Basic/Range.h" #include "swift/Basic/STLExtras.h" @@ -2144,7 +2145,8 @@ TypeCheckFunctionBodyUntilRequest::evaluate(Evaluator &evaluator, if (tc.DebugTimeFunctionBodies || tc.WarnLongFunctionBodies) timer.emplace(AFD, tc.DebugTimeFunctionBodies, tc.WarnLongFunctionBodies); - tc.validateDecl(AFD); + // FIXME(InterfaceTypeRequest): Remove this. + (void)AFD->getInterfaceType(); tc.checkDefaultArguments(AFD->getParameters(), AFD); BraceStmt *body = AFD->getBody(); diff --git a/lib/Sema/TypeCheckStorage.cpp b/lib/Sema/TypeCheckStorage.cpp index dfd74a50f9d3a..6ee02d0f28963 100644 --- a/lib/Sema/TypeCheckStorage.cpp +++ b/lib/Sema/TypeCheckStorage.cpp @@ -29,6 +29,7 @@ #include "swift/AST/ParameterList.h" #include "swift/AST/Pattern.h" #include "swift/AST/PropertyWrappers.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/TypeCheckRequests.h" #include "swift/AST/Types.h" using namespace swift; @@ -268,8 +269,9 @@ void swift::validatePatternBindingEntries(TypeChecker &tc, llvm::Expected IsGetterMutatingRequest::evaluate(Evaluator &evaluator, AbstractStorageDecl *storage) const { - bool result = (!storage->isStatic() && - doesContextHaveValueSemantics(storage->getDeclContext())); + auto storageDC = storage->getDeclContext(); + bool result = (!storage->isStatic() && storageDC->isTypeContext() && + storageDC->hasValueSemantics()); // 'lazy' overrides the normal accessor-based rules and heavily // restricts what accessors can be used. The getter is considered @@ -297,7 +299,7 @@ IsGetterMutatingRequest::evaluate(Evaluator &evaluator, // Protocol requirements are always written as '{ get }' or '{ get set }'; // the @_borrowed attribute determines if getReadImpl() becomes Get or Read. - if (isa(storage->getDeclContext())) + if (isa(storageDC)) return checkMutability(AccessorKind::Get); switch (storage->getReadImpl()) { @@ -323,8 +325,9 @@ IsSetterMutatingRequest::evaluate(Evaluator &evaluator, AbstractStorageDecl *storage) const { // By default, the setter is mutating if we have an instance member of a // value type, but this can be overridden below. - bool result = (!storage->isStatic() && - doesContextHaveValueSemantics(storage->getDeclContext())); + auto storageDC = storage->getDeclContext(); + bool result = (!storage->isStatic() && storageDC->isTypeContext() && + storageDC->hasValueSemantics()); // If we have an attached property wrapper, the setter is mutating // or not based on the composition of the wrappers. @@ -583,10 +586,8 @@ static Expr *buildStorageReference(AccessorDecl *accessor, TargetImpl target, bool isLValue, ASTContext &ctx) { - // FIXME: Temporary workaround. - if (!accessor->hasInterfaceType()) - ctx.getLazyResolver()->resolveDeclSignature(accessor); - + (void)accessor->getInterfaceType(); + // Local function to "finish" the expression, creating a member reference // to the given sequence of underlying variables. Optional enclosingSelfAccess; @@ -830,30 +831,10 @@ createPropertyLoadOrCallSuperclassGetter(AccessorDecl *accessor, ctx); } -/// Look up the NSCopying protocol from the Foundation module, if present. -/// Otherwise return null. -static ProtocolDecl *getNSCopyingProtocol(ASTContext &ctx, - DeclContext *DC) { - auto foundation = ctx.getLoadedModule(ctx.Id_Foundation); - if (!foundation) - return nullptr; - - SmallVector results; - DC->lookupQualified(foundation, - ctx.getSwiftId(KnownFoundationEntity::NSCopying), - NL_QualifiedDefault | NL_KnownNonCascadingDependency, - results); - - if (results.size() != 1) - return nullptr; - - return dyn_cast(results.front()); -} - static Optional checkConformanceToNSCopying(ASTContext &ctx, VarDecl *var, Type type) { auto dc = var->getDeclContext(); - auto proto = getNSCopyingProtocol(ctx, dc); + auto proto = ctx.getNSCopyingDecl(); if (proto) { auto result = TypeChecker::conformsToProtocol(type, proto, dc, None); @@ -2041,12 +2022,8 @@ LazyStoragePropertyRequest::evaluate(Evaluator &evaluator, NameBuf += "$__lazy_storage_$_"; NameBuf += VD->getName().str(); auto StorageName = Context.getIdentifier(NameBuf); - - if (!VD->hasInterfaceType()) - Context.getLazyResolver()->resolveDeclSignature(VD); - - auto StorageTy = OptionalType::get(VD->getType()); auto StorageInterfaceTy = OptionalType::get(VD->getInterfaceType()); + auto StorageTy = OptionalType::get(VD->getType()); auto *Storage = new (Context) VarDecl(/*IsStatic*/false, VarDecl::Introducer::Var, /*IsCaptureList*/false, VD->getLoc(), @@ -2121,9 +2098,6 @@ static VarDecl *synthesizePropertyWrapperStorageWrapperProperty( Identifier name = ctx.getIdentifier(nameBuf); // Determine the type of the property. - if (!wrapperVar->hasInterfaceType()) { - static_cast(*ctx.getLazyResolver()).validateDecl(wrapperVar); - } Type propertyType = wrapperType->getTypeOfMember( var->getModuleContext(), wrapperVar, wrapperVar->getValueInterfaceType()); @@ -2304,18 +2278,13 @@ PropertyWrapperBackingPropertyInfoRequest::evaluate(Evaluator &evaluator, Type storageInterfaceType = wrapperType; Type storageType = dc->mapTypeIntoContext(storageInterfaceType); - if (!var->hasInterfaceType()) { - auto &tc = *static_cast(ctx.getLazyResolver()); - tc.validateDecl(var); - assert(var->hasInterfaceType()); - } - // Make sure that the property type matches the value of the // wrapper type. if (!storageInterfaceType->hasError()) { Type expectedPropertyType = computeWrappedValueType(var, storageInterfaceType); Type propertyType = var->getValueInterfaceType(); + assert(propertyType); if (!expectedPropertyType->hasError() && !propertyType->hasError() && !propertyType->isEqual(expectedPropertyType)) { @@ -2349,8 +2318,8 @@ PropertyWrapperBackingPropertyInfoRequest::evaluate(Evaluator &evaluator, pbdPattern->setType(storageType); pbdPattern = TypedPattern::createImplicit(ctx, pbdPattern, storageType); auto pbd = PatternBindingDecl::createImplicit( - ctx, backingVar->getCorrectStaticSpelling(), pbdPattern, - /*init*/nullptr, dc, SourceLoc()); + ctx, var->getCorrectStaticSpelling(), pbdPattern, + /*init*/ nullptr, dc, SourceLoc()); addMemberToContextIfNeeded(pbd, dc, var); pbd->setStatic(var->isStatic()); diff --git a/lib/Sema/TypeCheckSwitchStmt.cpp b/lib/Sema/TypeCheckSwitchStmt.cpp index 3ac5af0634cc2..2b818581e11c2 100644 --- a/lib/Sema/TypeCheckSwitchStmt.cpp +++ b/lib/Sema/TypeCheckSwitchStmt.cpp @@ -774,15 +774,9 @@ namespace { auto children = E->getAllElements(); std::transform(children.begin(), children.end(), std::back_inserter(arr), [&](EnumElementDecl *eed) { - // We need the interface type of this enum case but it may - // not have been computed. - if (!eed->hasInterfaceType()) { - TC.validateDecl(eed); - } - - // If there's still no interface type after validation then there's + // If there's still no interface type then there's // not much else we can do here. - if (!eed->hasInterfaceType()) { + if (!eed->getInterfaceType()) { return Space(); } @@ -1429,8 +1423,6 @@ namespace { } case PatternKind::EnumElement: { auto *VP = cast(item); - TC.validateDecl(item->getType()->getEnumOrBoundGenericEnum()); - auto *SP = VP->getSubPattern(); if (!SP) { // If there's no sub-pattern then there's no further recursive diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index 137bcde507fb7..74cca1fb9eab4 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -34,6 +34,7 @@ #include "swift/AST/ParameterList.h" #include "swift/AST/PrettyStackTrace.h" #include "swift/AST/ProtocolConformance.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/TypeLoc.h" #include "swift/AST/TypeResolutionStage.h" #include "swift/Basic/SourceManager.h" @@ -222,10 +223,7 @@ Type TypeResolution::resolveDependentMemberType( // or it's a typealias declared in protocol or protocol extension. // Substitute the base type into it. auto concrete = ref->getBoundDecl(); - auto lazyResolver = ctx.getLazyResolver(); - if (lazyResolver) - lazyResolver->resolveDeclSignature(concrete); - if (!concrete->hasInterfaceType()) { + if (!concrete->getInterfaceType()) { ctx.Diags.diagnose(ref->getIdLoc(), diag::recursive_decl_reference, concrete->getDescriptiveKind(), concrete->getName()); concrete->diagnose(diag::kind_declared_here, @@ -410,7 +408,8 @@ static Type getPointerType(TypeChecker &tc, SourceLoc loc, Type pointeeType, return Type(); } - tc.validateDecl(pointerDecl); + // FIXME(InterfaceTypeRequest): isInvalid() should be based on the interface type. + (void)pointerDecl->getInterfaceType(); if (pointerDecl->isInvalid()) return Type(); @@ -485,12 +484,10 @@ TypeChecker::getDynamicBridgedThroughObjCClass(DeclContext *dc, return Context.getBridgedToObjC(dc, valueType); } -Type TypeChecker::resolveTypeInContext( - TypeDecl *typeDecl, - DeclContext *foundDC, - TypeResolution resolution, - TypeResolutionOptions options, - bool isSpecialized) { +Type TypeChecker::resolveTypeInContext(TypeDecl *typeDecl, DeclContext *foundDC, + TypeResolution resolution, + TypeResolutionOptions options, + bool isSpecialized) { auto fromDC = resolution.getDeclContext(); ASTContext &ctx = fromDC->getASTContext(); @@ -498,7 +495,7 @@ Type TypeChecker::resolveTypeInContext( // If we found a generic parameter, map to the archetype if there is one. if (auto genericParam = dyn_cast(typeDecl)) { return resolution.mapTypeIntoContext( - genericParam->getDeclaredInterfaceType()); + genericParam->getDeclaredInterfaceType()); } if (!isSpecialized) { @@ -506,19 +503,18 @@ Type TypeChecker::resolveTypeInContext( // a generic type with no generic arguments or a non-generic type, use the // type within the context. if (auto *nominalType = dyn_cast(typeDecl)) { - for (auto *parentDC = fromDC; - !parentDC->isModuleScopeContext(); + for (auto *parentDC = fromDC; !parentDC->isModuleScopeContext(); parentDC = parentDC->getParent()) { auto *parentNominal = parentDC->getSelfNominalTypeDecl(); if (parentNominal == nominalType) return resolution.mapTypeIntoContext( - parentDC->getDeclaredInterfaceType()); + parentDC->getDeclaredInterfaceType()); if (isa(parentDC)) { auto *extendedType = parentNominal; while (extendedType != nullptr) { if (extendedType == nominalType) return resolution.mapTypeIntoContext( - extendedType->getDeclaredInterfaceType()); + extendedType->getDeclaredInterfaceType()); extendedType = extendedType->getParent()->getSelfNominalTypeDecl(); } } @@ -528,26 +524,39 @@ Type TypeChecker::resolveTypeInContext( // If we're inside an extension of a type alias, allow the type alias to be // referenced without generic arguments as well. if (auto *aliasDecl = dyn_cast(typeDecl)) { - for (auto *parentDC = fromDC; - !parentDC->isModuleScopeContext(); - parentDC = parentDC->getParent()) { + for (auto *parentDC = fromDC; !parentDC->isModuleScopeContext(); + parentDC = parentDC->getParent()) { if (auto *ext = dyn_cast(parentDC)) { auto extendedType = ext->getExtendedType(); - if (auto *unboundGeneric = dyn_cast(extendedType.getPointer())) { - if (auto *ugAliasDecl = dyn_cast(unboundGeneric->getAnyGeneric())) { - if (ugAliasDecl == aliasDecl) + if (auto *unboundGeneric = + dyn_cast(extendedType.getPointer())) { + if (auto *ugAliasDecl = + dyn_cast(unboundGeneric->getAnyGeneric())) { + if (ugAliasDecl == aliasDecl) { + if (resolution.getStage() == TypeResolutionStage::Structural && + !aliasDecl->hasInterfaceType()) { + return resolution.mapTypeIntoContext( + aliasDecl->getStructuralType()); + } return resolution.mapTypeIntoContext( - aliasDecl->getDeclaredInterfaceType()); + aliasDecl->getDeclaredInterfaceType()); + } extendedType = unboundGeneric->getParent(); continue; } } - if (auto *aliasType = dyn_cast(extendedType.getPointer())) { - if (aliasType->getDecl() == aliasDecl) + if (auto *aliasType = + dyn_cast(extendedType.getPointer())) { + if (aliasType->getDecl() == aliasDecl) { + if (resolution.getStage() == TypeResolutionStage::Structural && + !aliasDecl->hasInterfaceType()) { + return resolution.mapTypeIntoContext( + aliasDecl->getStructuralType()); + } return resolution.mapTypeIntoContext( aliasDecl->getDeclaredInterfaceType()); - + } extendedType = aliasType->getParent(); continue; } @@ -566,9 +575,13 @@ Type TypeChecker::resolveTypeInContext( if (aliasDecl->getGenericParams()) return aliasDecl->getUnboundGenericType(); - // Otherwise, simply return the underlying type. + // Otherwise, return the appropriate type. + if (resolution.getStage() == TypeResolutionStage::Structural && + !aliasDecl->hasInterfaceType()) { + return resolution.mapTypeIntoContext(aliasDecl->getStructuralType()); + } return resolution.mapTypeIntoContext( - aliasDecl->getDeclaredInterfaceType()); + aliasDecl->getDeclaredInterfaceType()); } // When a nominal type used outside its context, return the unbound @@ -595,13 +608,12 @@ Type TypeChecker::resolveTypeInContext( if (!foundDC->getDeclaredInterfaceType()) return ErrorType::get(ctx); - selfType = resolution.mapTypeIntoContext( - foundDC->getDeclaredInterfaceType()); + selfType = + resolution.mapTypeIntoContext(foundDC->getDeclaredInterfaceType()); } else { // Otherwise, we want the protocol 'Self' type for // substituting into alias types and associated types. - selfType = resolution.mapTypeIntoContext( - foundDC->getSelfInterfaceType()); + selfType = resolution.mapTypeIntoContext(foundDC->getSelfInterfaceType()); if (selfType->is()) { if (typeDecl->getDeclContext()->getSelfProtocolDecl()) { @@ -617,8 +629,8 @@ Type TypeChecker::resolveTypeInContext( // the Collection.SubSequence default, even when the conforming // type wants to conform to Collection. if (resolution.getStage() == TypeResolutionStage::Structural) { - return resolution.resolveSelfAssociatedType( - selfType, foundDC, typeDecl->getName()); + return resolution.resolveSelfAssociatedType(selfType, foundDC, + typeDecl->getName()); } else if (auto assocType = dyn_cast(typeDecl)) { typeDecl = assocType->getAssociatedTypeAnchor(); } @@ -642,10 +654,10 @@ Type TypeChecker::resolveTypeInContext( } } } - + // Finally, substitute the base type into the member type. - return substMemberTypeWithBase(fromDC->getParentModule(), typeDecl, - selfType, resolution.usesArchetypes()); + return substMemberTypeWithBase(fromDC->getParentModule(), typeDecl, selfType, + resolution.usesArchetypes()); } static TypeResolutionOptions @@ -755,7 +767,7 @@ Type TypeChecker::applyGenericArguments(Type type, } // FIXME: More principled handling of circularity. - if (!genericDecl->hasValidSignature()) { + if (!genericDecl->getGenericSignature()) { diags.diagnose(loc, diag::recursive_decl_reference, genericDecl->getDescriptiveKind(), genericDecl->getName()); genericDecl->diagnose(diag::kind_declared_here, DescriptiveDeclKind::Type); @@ -884,7 +896,7 @@ Type TypeChecker::applyUnboundGenericArguments( // later. auto typealias = dyn_cast(decl); if (typealias) { - resultType = typealias->getUnderlyingTypeLoc().getType(); + resultType = typealias->getUnderlyingType(); } // Apply the substitution map to the interface type of the declaration. @@ -962,8 +974,7 @@ static void maybeDiagnoseBadConformanceRef(DeclContext *dc, /// Returns a valid type or ErrorType in case of an error. static Type resolveTypeDecl(TypeDecl *typeDecl, SourceLoc loc, - DeclContext *foundDC, - TypeResolution resolution, + DeclContext *foundDC, TypeResolution resolution, GenericIdentTypeRepr *generic, TypeResolutionOptions options) { auto fromDC = resolution.getDeclContext(); @@ -971,30 +982,33 @@ static Type resolveTypeDecl(TypeDecl *typeDecl, SourceLoc loc, ASTContext &ctx = typeDecl->getASTContext(); auto &diags = ctx.Diags; - auto lazyResolver = ctx.getLazyResolver(); - // Don't validate nominal type declarations during extension binding. - if (!options.is(TypeResolverContext::ExtensionBinding) || - !isa(typeDecl)) { - // Validate the declaration. - if (lazyResolver) - lazyResolver->resolveDeclSignature(typeDecl); + // Hack: Don't validate nested typealiases if we only need the structural + // type. + auto prevalidatingAlias = [](TypeDecl *typeDecl, TypeResolution res) { + return isa(typeDecl) + && !typeDecl->hasInterfaceType() + && typeDecl->getDeclContext()->isTypeContext() + && res.getStage() == TypeResolutionStage::Structural; + }; + // Don't validate nominal type declarations during extension binding. + if ((!options.is(TypeResolverContext::ExtensionBinding) || + !isa(typeDecl)) && + !prevalidatingAlias(typeDecl, resolution)) { // If we were not able to validate recursively, bail out. - if (!typeDecl->hasInterfaceType()) { + if (!typeDecl->getInterfaceType()) { diags.diagnose(loc, diag::recursive_decl_reference, - typeDecl->getDescriptiveKind(), typeDecl->getName()); - typeDecl->diagnose(diag::kind_declared_here, - DescriptiveDeclKind::Type); + typeDecl->getDescriptiveKind(), typeDecl->getName()); + typeDecl->diagnose(diag::kind_declared_here, DescriptiveDeclKind::Type); return ErrorType::get(ctx); } } // Resolve the type declaration to a specific type. How this occurs // depends on the current context and where the type was found. - Type type = - TypeChecker::resolveTypeInContext(typeDecl, foundDC, resolution, options, - generic); + Type type = TypeChecker::resolveTypeInContext(typeDecl, foundDC, resolution, + options, generic); if (type->is() && !generic && !options.is(TypeResolverContext::TypeAliasDecl) && @@ -1005,8 +1019,7 @@ static Type resolveTypeDecl(TypeDecl *typeDecl, SourceLoc loc, if (type->hasError() && foundDC && (isa(typeDecl) || isa(typeDecl))) { - maybeDiagnoseBadConformanceRef(fromDC, - foundDC->getDeclaredInterfaceType(), + maybeDiagnoseBadConformanceRef(fromDC, foundDC->getDeclaredInterfaceType(), loc, typeDecl); } @@ -3172,10 +3185,6 @@ Type TypeResolver::resolveDictionaryType(DictionaryTypeRepr *repr, if (auto dictTy = TypeChecker::getDictionaryType(repr->getBrackets().Start, keyTy, valueTy)) { - // Check the requirements on the generic arguments. - if (auto lazyResolver = Context.getLazyResolver()) - lazyResolver->resolveDeclSignature(dictDecl); - auto unboundTy = dictDecl->getDeclaredType()->castTo(); Type args[] = {keyTy, valueTy}; @@ -3531,19 +3540,10 @@ Type TypeChecker::substMemberTypeWithBase(ModuleDecl *module, aliasDecl, baseTy, aliasDecl->getASTContext()); } - - // FIXME: If this is a protocol typealias and we haven't built the - // protocol's generic environment yet, do so now, to ensure the - // typealias's underlying type has fully resolved dependent - // member types. - if (auto *protoDecl = dyn_cast(aliasDecl->getDeclContext())) { - ASTContext &ctx = protoDecl->getASTContext(); - ctx.getLazyResolver()->resolveProtocolEnvironment(protoDecl); - } } Type resultType; - auto memberType = aliasDecl ? aliasDecl->getUnderlyingTypeLoc().getType() + auto memberType = aliasDecl ? aliasDecl->getUnderlyingType() : member->getDeclaredInterfaceType(); SubstitutionMap subs; if (baseTy) { diff --git a/lib/Sema/TypeChecker.cpp b/lib/Sema/TypeChecker.cpp index bddded1c48dbd..773fe7d484010 100644 --- a/lib/Sema/TypeChecker.cpp +++ b/lib/Sema/TypeChecker.cpp @@ -33,6 +33,7 @@ #include "swift/AST/NameLookup.h" #include "swift/AST/PrettyStackTrace.h" #include "swift/AST/ProtocolConformance.h" +#include "swift/AST/SourceFile.h" #include "swift/Basic/Statistic.h" #include "swift/Basic/STLExtras.h" #include "swift/Basic/Timer.h" @@ -67,8 +68,7 @@ ProtocolDecl *TypeChecker::getProtocol(SourceLoc loc, KnownProtocolKind kind) { Context.getIdentifier(getProtocolName(kind))); } - if (protocol && !protocol->hasInterfaceType()) { - validateDecl(protocol); + if (protocol && !protocol->getInterfaceType()) { if (protocol->isInvalid()) return nullptr; } @@ -359,12 +359,14 @@ void swift::performTypeChecking(SourceFile &SF, TopLevelContext &TLC, if (SF.ASTStage == SourceFile::TypeChecked) return; - // Eagerly build a scope tree before type checking - // because type-checking mutates the AST and that throws off the scope-based - // lookups. + // Eagerly build the top-level scopes tree before type checking + // because type-checking expressions mutates the AST and that throws off the + // scope-based lookups. Only the top-level scopes because extensions have not + // been bound yet. if (SF.getASTContext().LangOpts.EnableASTScopeLookup && SF.isSuitableForASTScopes()) - SF.getScope().buildScopeTreeEagerly(); + SF.getScope() + .buildEnoughOfTreeForTopLevelExpressionsButDontRequestGenericsOrExtendedNominals(); auto &Ctx = SF.getASTContext(); BufferIndirectlyCausingDiagnosticRAII cpr(SF); @@ -619,12 +621,16 @@ void swift::typeCheckCompletionDecl(Decl *D) { auto &Ctx = D->getASTContext(); DiagnosticSuppression suppression(Ctx.Diags); - TypeChecker &TC = createTypeChecker(Ctx); - - if (auto ext = dyn_cast(D)) - TC.validateExtension(ext); - else - TC.validateDecl(cast(D)); + (void)createTypeChecker(Ctx); + if (auto ext = dyn_cast(D)) { + if (auto *nominal = ext->getExtendedNominal()) { + // FIXME(InterfaceTypeRequest): Remove this. + (void)nominal->getInterfaceType(); + } + } else { + // FIXME(InterfaceTypeRequest): Remove this. + (void)cast(D)->getInterfaceType(); + } } void swift::typeCheckPatternBinding(PatternBindingDecl *PBD, diff --git a/lib/Sema/TypeChecker.h b/lib/Sema/TypeChecker.h index 955707c60a06c..6817691fd08f4 100644 --- a/lib/Sema/TypeChecker.h +++ b/lib/Sema/TypeChecker.h @@ -219,6 +219,8 @@ enum ContextualTypePurpose { CTP_AssignSource, ///< AssignExpr source operand coerced to result type. CTP_SubscriptAssignSource, ///< AssignExpr source operand coerced to subscript ///< result type. + CTP_Condition, ///< Condition expression of various statements e.g. + ///< `if`, `for`, `while` etc. CTP_CannotFail, ///< Conversion can never fail. abort() if it does. }; @@ -783,9 +785,6 @@ class TypeChecker final : public LazyResolver { void validateDecl(OperatorDecl *decl); void validateDecl(PrecedenceGroupDecl *decl); - /// Perform just enough validation for looking up names using the Decl. - void validateDeclForNameLookup(ValueDecl *D); - /// Validate the given extension declaration, ensuring that it /// properly extends the nominal type it names. void validateExtension(ExtensionDecl *ext); @@ -864,6 +863,28 @@ class TypeChecker final : public LazyResolver { static Type substMemberTypeWithBase(ModuleDecl *module, TypeDecl *member, Type baseTy, bool useArchetypes = true); + /// Determine whether this is a "pass-through" typealias, which has the + /// same type parameters as the nominal type it references and specializes + /// the underlying nominal type with exactly those type parameters. + /// For example, the following typealias \c GX is a pass-through typealias: + /// + /// \code + /// struct X { } + /// typealias GX = X + /// \endcode + /// + /// whereas \c GX2 and \c GX3 are not pass-through because \c GX2 has + /// different type parameters and \c GX3 doesn't pass its type parameters + /// directly through. + /// + /// \code + /// typealias GX2 = X + /// typealias GX3 = X + /// \endcode + static bool isPassThroughTypealias(TypeAliasDecl *typealias, + Type underlyingType, + NominalTypeDecl *nominal); + /// Determine whether one type is a subtype of another. /// /// \param t1 The potential subtype. @@ -995,15 +1016,7 @@ class TypeChecker final : public LazyResolver { void checkDefaultArguments(ParameterList *params, ValueDecl *VD); virtual void resolveDeclSignature(ValueDecl *VD) override { - validateDeclForNameLookup(VD); - } - - virtual void resolveProtocolEnvironment(ProtocolDecl *proto) override { - validateDecl(proto); - } - - virtual void resolveExtension(ExtensionDecl *ext) override { - validateExtension(ext); + validateDecl(VD); } virtual void resolveImplicitConstructors(NominalTypeDecl *nominal) override { @@ -1017,13 +1030,6 @@ class TypeChecker final : public LazyResolver { /// Infer default value witnesses for all requirements in the given protocol. void inferDefaultWitnesses(ProtocolDecl *proto); - /// Compute the generic signature, generic environment and interface type - /// of a generic function or subscript. - void validateGenericFuncOrSubscriptSignature( - PointerUnion - funcOrSubscript, - ValueDecl *decl, GenericContext *genCtx); - /// For a generic requirement in a protocol, make sure that the requirement /// set didn't add any requirements to Self or its associated types. void checkProtocolSelfRequirements(ValueDecl *decl); @@ -1059,11 +1065,6 @@ class TypeChecker final : public LazyResolver { SmallVector additionalRequirements = {}, SmallVector inferenceSources = {}); - /// Validate the signature of a generic type. - /// - /// \param nominal The generic type. - void validateGenericTypeSignature(GenericTypeDecl *nominal); - /// Create a text string that describes the bindings of generic parameters /// that are relevant to the given set of types, e.g., /// "[with T = Bar, U = Wibble]". @@ -1494,9 +1495,7 @@ class TypeChecker final : public LazyResolver { return getUnopenedTypeOfReference( value, baseType, UseDC, [&](VarDecl *var) -> Type { - validateDecl(var); - - if (!var->hasValidSignature() || var->isInvalid()) + if (!var->getInterfaceType() || var->isInvalid()) return ErrorType::get(Context); return wantInterfaceType ? value->getInterfaceType() diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp index 014a3f9b1fa78..c4ca2331e8f35 100644 --- a/lib/Serialization/Deserialization.cpp +++ b/lib/Serialization/Deserialization.cpp @@ -1120,9 +1120,10 @@ static void filterValues(Type expectedTy, ModuleDecl *expectedModule, if (isType != isa(value)) return true; - if (!value->hasInterfaceType()) + auto ifaceTy = value->getInterfaceType(); + if (!ifaceTy) return true; - if (canTy && value->getInterfaceType()->getCanonicalType() != canTy) + if (canTy && ifaceTy->getCanonicalType() != canTy) return true; if (value->isStatic() != isStatic) return true; @@ -2287,10 +2288,14 @@ class swift::DeclDeserializer { SourceLoc(), genericParams, DC); declOrOffset = alias; - alias->setGenericSignature(MF.getGenericSignature(genericSigID)); - - alias->setUnderlyingType(MF.getType(underlyingTypeID)); + auto *genericSig = MF.getGenericSignature(genericSigID); + alias->setGenericSignature(genericSig); + auto underlying = MF.getType(underlyingTypeID); + alias->setUnderlyingType(underlying); + alias->computeType(); + alias->setValidationToChecked(); + if (auto accessLevel = getActualAccessLevel(rawAccessLevel)) alias->setAccess(*accessLevel); else @@ -4471,7 +4476,7 @@ class swift::TypeDeserializer { // Look through compatibility aliases that are now unavailable. if (alias->getAttrs().isUnavailable(ctx) && alias->isCompatibilityAlias()) { - return alias->getUnderlyingTypeLoc().getType(); + return alias->getUnderlyingType(); } return alias->getDeclaredInterfaceType(); @@ -4539,7 +4544,7 @@ class swift::TypeDeserializer { if (alias && alias->getAttrs().isUnavailable(ctx) && alias->isCompatibilityAlias()) { - return alias->getUnderlyingTypeLoc().getType().subst(subMap); + return alias->getUnderlyingType().subst(subMap); } auto parentType = parentTypeOrError.get(); @@ -4567,7 +4572,7 @@ class swift::TypeDeserializer { // using the Type wrapper. const TypeBase *underlyingTy = nullptr; while (alias->isCompatibilityAlias()) { - underlyingTy = alias->getUnderlyingTypeLoc().getType().getPointer(); + underlyingTy = alias->getUnderlyingType().getPointer(); // If the underlying type is itself a typealias, it might be another // compatibility alias, meaning we need to go around the loop again. diff --git a/lib/Serialization/ModuleFile.h b/lib/Serialization/ModuleFile.h index 5dce4c9b0d39b..2d532e66300b6 100644 --- a/lib/Serialization/ModuleFile.h +++ b/lib/Serialization/ModuleFile.h @@ -17,6 +17,7 @@ #include "swift/AST/Identifier.h" #include "swift/AST/LazyResolver.h" #include "swift/AST/LinkLibrary.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/Module.h" #include "swift/AST/RawComment.h" #include "swift/AST/TypeLoc.h" diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index 8c52bb72dea99..e2eec56f8a08d 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -29,6 +29,7 @@ #include "swift/AST/PropertyWrappers.h" #include "swift/AST/ProtocolConformance.h" #include "swift/AST/RawComment.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/TypeCheckRequests.h" #include "swift/AST/TypeVisitor.h" #include "swift/Basic/Dwarf.h" @@ -2865,7 +2866,7 @@ class Serializer::DeclSerializer : public DeclVisitor { auto contextID = S.addDeclContextRef(typeAlias->getDeclContext()); - auto underlying = typeAlias->getUnderlyingTypeLoc().getType(); + auto underlying = typeAlias->getUnderlyingType(); llvm::SmallSetVector dependencies; collectDependenciesFromType(dependencies, underlying->getCanonicalType(), @@ -3329,10 +3330,10 @@ class Serializer::DeclSerializer : public DeclVisitor { // // FIXME: Once accessor synthesis and getInterfaceType() itself are // request-ified this goes away. - if (!fn->hasValidSignature()) { + if (!fn->hasInterfaceType()) { assert(fn->isImplicit()); - S.M->getASTContext().getLazyResolver()->resolveDeclSignature( - const_cast(fn)); + // FIXME: Remove this one + (void)fn->getInterfaceType(); } using namespace decls_block; @@ -3796,7 +3797,7 @@ class Serializer::TypeSerializer : public TypeVisitor { void visitTypeAliasType(const TypeAliasType *alias) { using namespace decls_block; const TypeAliasDecl *typeAlias = alias->getDecl(); - auto underlyingType = typeAlias->getUnderlyingTypeLoc().getType(); + auto underlyingType = typeAlias->getUnderlyingType(); unsigned abbrCode = S.DeclTypeAbbrCodes[TypeAliasTypeLayout::Code]; TypeAliasTypeLayout::emitRecord( diff --git a/lib/Serialization/SerializeDoc.cpp b/lib/Serialization/SerializeDoc.cpp index e37aff3235ffe..d3a0e58c43d8c 100644 --- a/lib/Serialization/SerializeDoc.cpp +++ b/lib/Serialization/SerializeDoc.cpp @@ -18,6 +18,7 @@ #include "swift/AST/DiagnosticsCommon.h" #include "swift/AST/Module.h" #include "swift/AST/ParameterList.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/USRGeneration.h" #include "swift/Basic/SourceManager.h" #include "llvm/Support/DJB.h" diff --git a/lib/Syntax/Syntax.cpp b/lib/Syntax/Syntax.cpp index 38d08ff4da8de..57aa313597c7b 100644 --- a/lib/Syntax/Syntax.cpp +++ b/lib/Syntax/Syntax.cpp @@ -98,13 +98,13 @@ llvm::Optional Syntax::getChild(const size_t N) const { return Syntax {Root, ChildData.get()}; } -Optional Syntax::getFirstToken() { +Optional Syntax::getFirstToken() const { if (auto tok = getData().getFirstToken()) return TokenSyntax(Root, tok.get()); return None; } -Optional Syntax::getLastToken() { +Optional Syntax::getLastToken() const { if (auto tok = getData().getLastToken()) return TokenSyntax(Root, tok.get()); return None; diff --git a/lib/Syntax/SyntaxBuilders.cpp.gyb b/lib/Syntax/SyntaxBuilders.cpp.gyb index 8c93726dc5123..9309327befe07 100644 --- a/lib/Syntax/SyntaxBuilders.cpp.gyb +++ b/lib/Syntax/SyntaxBuilders.cpp.gyb @@ -25,7 +25,7 @@ using namespace swift; using namespace swift::syntax; -% for node in SYNTAX_NODES: +% for node in SYNTAX_NODES + PARSEONLY_NODES: % if node.is_buildable(): % for child in node.children: ${node.name}Builder & diff --git a/lib/Syntax/SyntaxFactory.cpp.gyb b/lib/Syntax/SyntaxFactory.cpp.gyb index dc6ad1a8c90dd..fc8394411358f 100644 --- a/lib/Syntax/SyntaxFactory.cpp.gyb +++ b/lib/Syntax/SyntaxFactory.cpp.gyb @@ -63,7 +63,7 @@ SyntaxFactory::makeUnknownSyntax(llvm::ArrayRef Tokens, Syntax SyntaxFactory::makeBlankCollectionSyntax(SyntaxKind Kind) { switch(Kind) { -% for node in SYNTAX_NODES: +% for node in SYNTAX_NODES + PARSEONLY_NODES: % if node.is_syntax_collection(): case SyntaxKind::${node.syntax_kind}: return makeBlank${node.syntax_kind}(); % end @@ -76,7 +76,7 @@ Syntax SyntaxFactory::makeBlankCollectionSyntax(SyntaxKind Kind) { std::pair SyntaxFactory::countChildren(SyntaxKind Kind){ switch(Kind) { -% for node in SYNTAX_NODES: +% for node in SYNTAX_NODES + PARSEONLY_NODES: % if not node.is_syntax_collection(): case SyntaxKind::${node.syntax_kind}: % child_count = len(node.children) @@ -92,7 +92,7 @@ SyntaxFactory::countChildren(SyntaxKind Kind){ bool SyntaxFactory::canServeAsCollectionMemberRaw(SyntaxKind CollectionKind, SyntaxKind MemberKind) { switch (CollectionKind) { -% for node in SYNTAX_NODES: +% for node in SYNTAX_NODES + PARSEONLY_NODES: % if node.is_syntax_collection(): case SyntaxKind::${node.syntax_kind}: % if node.collection_element_choices: @@ -125,7 +125,7 @@ RC SyntaxFactory::createRaw(SyntaxKind Kind, llvm::ArrayRef> Elements, RC Arena) { switch (Kind) { -% for node in SYNTAX_NODES: +% for node in SYNTAX_NODES + PARSEONLY_NODES: case SyntaxKind::${node.syntax_kind}: { % if node.children: % child_count = len(node.children) @@ -178,7 +178,7 @@ Optional SyntaxFactory::createSyntax(SyntaxKind Kind, return None; } -% for node in SYNTAX_NODES: +% for node in SYNTAX_NODES + PARSEONLY_NODES: % if node.children: % child_params = [] % for child in node.children: diff --git a/lib/Syntax/SyntaxKind.cpp.gyb b/lib/Syntax/SyntaxKind.cpp.gyb index 7603508970385..7e4d070c19a83 100644 --- a/lib/Syntax/SyntaxKind.cpp.gyb +++ b/lib/Syntax/SyntaxKind.cpp.gyb @@ -52,7 +52,7 @@ bool isTokenKeyword(tok kind) { bool parserShallOmitWhenNoChildren(syntax::SyntaxKind Kind) { switch(Kind) { -% for node in SYNTAX_NODES: +% for node in SYNTAX_NODES + PARSEONLY_NODES: % if node.shall_be_omitted_when_empty(): case syntax::SyntaxKind::${node.syntax_kind}: % end @@ -73,7 +73,7 @@ void dumpSyntaxKind(llvm::raw_ostream &os, const SyntaxKind kind) { case SyntaxKind::Unknown: os << "Unknown"; break; -% for node in SYNTAX_NODES: +% for node in SYNTAX_NODES + PARSEONLY_NODES: case SyntaxKind::${node.syntax_kind}: os << "${node.syntax_kind}"; break; @@ -83,7 +83,7 @@ void dumpSyntaxKind(llvm::raw_ostream &os, const SyntaxKind kind) { bool isCollectionKind(SyntaxKind Kind) { switch(Kind) { -% for node in SYNTAX_NODES: +% for node in SYNTAX_NODES + PARSEONLY_NODES: % if node.is_syntax_collection(): case SyntaxKind::${node.syntax_kind}: % end @@ -147,7 +147,7 @@ SyntaxKind getUnknownKind(SyntaxKind Kind) { llvm::raw_ostream &llvm::operator<<(llvm::raw_ostream &OS, swift::syntax::SyntaxKind Kind) { switch (Kind) { -% for node in SYNTAX_NODES: +% for node in SYNTAX_NODES + PARSEONLY_NODES: case swift::syntax::SyntaxKind::${node.syntax_kind}: OS << "${node.syntax_kind}"; break; diff --git a/lib/Syntax/SyntaxNodes.cpp.gyb b/lib/Syntax/SyntaxNodes.cpp.gyb index 34418e182f1ca..55c024a68fbd0 100644 --- a/lib/Syntax/SyntaxNodes.cpp.gyb +++ b/lib/Syntax/SyntaxNodes.cpp.gyb @@ -24,7 +24,7 @@ using namespace swift; using namespace swift::syntax; -% for node in SYNTAX_NODES: +% for node in SYNTAX_NODES + PARSEONLY_NODES: % if node.requires_validation(): void ${node.name}::validate() const { #ifndef NDEBUG @@ -55,14 +55,14 @@ void ${node.name}::validate() const { % for child in node.children: % if child.is_optional: -llvm::Optional<${child.type_name}> ${node.name}::get${child.name}() { +llvm::Optional<${child.type_name}> ${node.name}::get${child.name}() const { auto ChildData = Data->getChild(Cursor::${child.name}); if (!ChildData) return llvm::None; return ${child.type_name} {Root, ChildData.get()}; } % else: -${child.type_name} ${node.name}::get${child.name}() { +${child.type_name} ${node.name}::get${child.name}() const { return ${child.type_name} {Root, Data->getChild(Cursor::${child.name}).get()}; } % end diff --git a/lib/Syntax/SyntaxVisitor.cpp.gyb b/lib/Syntax/SyntaxVisitor.cpp.gyb index 722ab5d46f4e7..f98a0d958e994 100644 --- a/lib/Syntax/SyntaxVisitor.cpp.gyb +++ b/lib/Syntax/SyntaxVisitor.cpp.gyb @@ -21,7 +21,7 @@ #include "swift/Syntax/SyntaxVisitor.h" #include "swift/Basic/Defer.h" -% for node in SYNTAX_NODES: +% for node in SYNTAX_NODES + PARSEONLY_NODES: % if is_visitable(node): void swift::syntax::SyntaxVisitor::visit(${node.name} node) { visitChildren(node); @@ -36,7 +36,7 @@ void swift::syntax::SyntaxVisitor::visit(Syntax node) { case SyntaxKind::Token: visit(node.castTo()); return; -% for node in SYNTAX_NODES: +% for node in SYNTAX_NODES + PARSEONLY_NODES: % if is_visitable(node): case SyntaxKind::${node.syntax_kind}: visit(node.castTo<${node.name}>()); diff --git a/lib/SyntaxParse/SyntaxTreeCreator.cpp b/lib/SyntaxParse/SyntaxTreeCreator.cpp index f5a71dd8ef25b..04ae25f660963 100644 --- a/lib/SyntaxParse/SyntaxTreeCreator.cpp +++ b/lib/SyntaxParse/SyntaxTreeCreator.cpp @@ -20,6 +20,7 @@ #include "swift/AST/ASTContext.h" #include "swift/AST/DiagnosticsParse.h" #include "swift/AST/Module.h" +#include "swift/AST/SourceFile.h" #include "swift/Basic/OwnedString.h" #include "RawSyntaxTokenCache.h" diff --git a/lib/TBDGen/TBDGen.cpp b/lib/TBDGen/TBDGen.cpp index bc2c1e3a0b0ec..4b747e2a58be4 100644 --- a/lib/TBDGen/TBDGen.cpp +++ b/lib/TBDGen/TBDGen.cpp @@ -645,7 +645,7 @@ static void enumeratePublicSymbolsAndWrite(ModuleDecl *M, FileUnit *singleFile, file.setPlatform(tapi::internal::mapToSinglePlatform(target)); auto arch = tapi::internal::getArchType(target.getArchName()); file.setArch(arch); - file.setInstallAPI(); + file.setInstallAPI(opts.IsInstallAPI); TBDGenVisitor visitor(file, arch, symbols, linkInfo, M, opts); diff --git a/lib/TBDGen/TBDGenVisitor.h b/lib/TBDGen/TBDGenVisitor.h index 136a8434bc4c2..5453322f810da 100644 --- a/lib/TBDGen/TBDGenVisitor.h +++ b/lib/TBDGen/TBDGenVisitor.h @@ -18,6 +18,7 @@ #include "swift/AST/ASTMangler.h" #include "swift/AST/ASTVisitor.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/Module.h" #include "swift/AST/ParameterList.h" #include "swift/Basic/LLVM.h" diff --git a/stdlib/private/OSLog/OSLogIntegerTypes.swift b/stdlib/private/OSLog/OSLogIntegerTypes.swift index 900c212671d1f..53b4c60004fdb 100644 --- a/stdlib/private/OSLog/OSLogIntegerTypes.swift +++ b/stdlib/private/OSLog/OSLogIntegerTypes.swift @@ -106,7 +106,7 @@ extension OSLogInterpolation { /// This function must be constant evaluable and all its arguments /// must be known at compile time. @inlinable - @_semantics("oslog.interpolation.getFormatSpecifier") + @_semantics("constant_evaluable") @_effects(readonly) @_optimize(none) internal func getIntegerFormatSpecifier( @@ -150,7 +150,7 @@ extension OSLogArguments { /// Return the number of bytes needed for serializing an integer argument as /// specified by os_log. This function must be constant evaluable. @inlinable -@_semantics("oslog.integers.sizeForEncoding") +@_semantics("constant_evaluable") @_effects(readonly) @_optimize(none) internal func sizeForEncoding( diff --git a/stdlib/private/OSLog/OSLogMessage.swift b/stdlib/private/OSLog/OSLogMessage.swift index 9c7cacab893db..ed84469f916fa 100644 --- a/stdlib/private/OSLog/OSLogMessage.swift +++ b/stdlib/private/OSLog/OSLogMessage.swift @@ -95,7 +95,7 @@ public struct OSLogInterpolation : StringInterpolationProtocol { /// argument header. The first two bits are used to indicate privacy and /// the other two are reserved. @usableFromInline - @_frozen + @frozen internal enum ArgumentFlag { case privateFlag case publicFlag @@ -117,7 +117,7 @@ public struct OSLogInterpolation : StringInterpolationProtocol { /// (Note that an auto-generated rawValue is not constant evaluable because /// it cannot be annotated so.) @usableFromInline - @_frozen + @frozen internal enum ArgumentType { case scalar, count, string, pointer, object @@ -147,7 +147,7 @@ public struct OSLogInterpolation : StringInterpolationProtocol { /// mask indicate whether there is an argument that is private, and whether /// there is an argument that is non-scalar: String, NSObject or Pointer. @usableFromInline - @_frozen + @frozen internal enum PreambleBitMask { case privateBitMask case nonScalarBitMask @@ -195,7 +195,7 @@ public struct OSLogInterpolation : StringInterpolationProtocol { /// An internal initializer that should be used only when there are no /// interpolated expressions. This function must be constant evaluable. @inlinable - @_semantics("oslog.interpolation.init") + @_semantics("constant_evaluable") @_optimize(none) internal init() { formatString = "" @@ -216,7 +216,7 @@ public struct OSLogInterpolation : StringInterpolationProtocol { /// Return true if and only if the parameter is .private. /// This function must be constant evaluable. @inlinable - @_semantics("oslog.interpolation.isPrivate") + @_semantics("constant_evaluable") @_effects(readonly) @_optimize(none) internal func isPrivate(_ privacy: Privacy) -> Bool { @@ -233,7 +233,7 @@ public struct OSLogInterpolation : StringInterpolationProtocol { /// of the header byte, respectively. /// This function should be constant evaluable. @inlinable - @_semantics("oslog.interpolation.getArgumentHeader") + @_semantics("constant_evaluable") @_effects(readonly) @_optimize(none) internal func getArgumentHeader( @@ -248,7 +248,7 @@ public struct OSLogInterpolation : StringInterpolationProtocol { /// Compute the new preamble based whether the current argument is private /// or not. This function must be constant evaluable. @inlinable - @_semantics("oslog.interpolation.getUpdatedPreamble") + @_semantics("constant_evaluable") @_effects(readonly) @_optimize(none) internal func getUpdatedPreamble( @@ -268,7 +268,8 @@ public struct OSLogInterpolation : StringInterpolationProtocol { extension String { /// Replace all percents "%" in the string by "%%" so that the string can be - /// interpreted as a C format string. + /// interpreted as a C format string. This function is constant evaluable + /// and its semantics is modeled within the evaluator. public var percentEscapedString: String { @_semantics("string.escapePercent.get") @_effects(readonly) @@ -292,6 +293,7 @@ public struct OSLogMessage : @inlinable @_optimize(none) @_semantics("oslog.message.init_interpolation") + @_semantics("constant_evaluable") public init(stringInterpolation: OSLogInterpolation) { self.interpolation = stringInterpolation } @@ -301,6 +303,7 @@ public struct OSLogMessage : @inlinable @_optimize(none) @_semantics("oslog.message.init_stringliteral") + @_semantics("constant_evaluable") public init(stringLiteral value: String) { var s = OSLogInterpolation() s.appendLiteral(value) @@ -332,7 +335,7 @@ internal struct OSLogArguments { /// This function must be constant evaluable. @inlinable - @_semantics("oslog.arguments.init_empty") + @_semantics("constant_evaluable") @_optimize(none) internal init() { argumentClosures = nil diff --git a/stdlib/private/OSLog/OSLogStringTypes.swift b/stdlib/private/OSLog/OSLogStringTypes.swift index 46ce0a5bea8f5..a423e6295e59f 100644 --- a/stdlib/private/OSLog/OSLogStringTypes.swift +++ b/stdlib/private/OSLog/OSLogStringTypes.swift @@ -74,7 +74,7 @@ extension OSLogInterpolation { /// This function must be constant evaluable and all its arguments /// must be known at compile time. @inlinable - @_semantics("oslog.interpolation.getFormatSpecifier") + @_semantics("constant_evaluable") @_effects(readonly) @_optimize(none) internal func getStringFormatSpecifier(_ isPrivate: Bool) -> String { @@ -102,7 +102,7 @@ extension OSLogArguments { @inlinable @_optimize(none) @_effects(readonly) -@_semantics("oslog.string.sizeForEncoding") +@_semantics("constant_evaluable") internal func sizeForEncoding() -> Int { return Int.bitWidth &>> logBitsPerByte } diff --git a/stdlib/public/Reflection/TypeLowering.cpp b/stdlib/public/Reflection/TypeLowering.cpp index 84873fec98c42..a2da93e41790e 100644 --- a/stdlib/public/Reflection/TypeLowering.cpp +++ b/stdlib/public/Reflection/TypeLowering.cpp @@ -198,7 +198,7 @@ BuiltinTypeInfo::BuiltinTypeInfo(const BuiltinTypeDescriptor *descriptor) descriptor->Stride, descriptor->NumExtraInhabitants, descriptor->isBitwiseTakable()), - Name(descriptor->getMangledTypeName(0)) {} + Name(descriptor->getMangledTypeName()) {} /// Utility class for building values that contain witness tables. class ExistentialTypeInfoBuilder { diff --git a/stdlib/public/Reflection/TypeRefBuilder.cpp b/stdlib/public/Reflection/TypeRefBuilder.cpp index b4d08e4c03323..aff7ff6ad93c1 100644 --- a/stdlib/public/Reflection/TypeRefBuilder.cpp +++ b/stdlib/public/Reflection/TypeRefBuilder.cpp @@ -31,8 +31,8 @@ TypeRefBuilder::getRemoteAddrOfTypeRefPointer(const void *pointer) { // Find what type ref section the pointer resides in, if any. const ReflectionInfo *containingInfo = nullptr; for (auto &info : ReflectionInfos) { - auto start = (uint64_t)info.TypeReference.Metadata.startAddress(); - auto size = (uint64_t)info.TypeReference.Metadata.size(); + auto start = (uint64_t)info.TypeReference.startAddress(); + auto size = (uint64_t)info.TypeReference.size(); if (start <= (uint64_t)pointer && (uint64_t)pointer < start + size) { containingInfo = &info; break; @@ -44,8 +44,7 @@ TypeRefBuilder::getRemoteAddrOfTypeRefPointer(const void *pointer) { return (uint64_t)pointer + containingInfo->RemoteStartAddress - - containingInfo->LocalStartAddress - + containingInfo->TypeReference.SectionOffset; + - containingInfo->LocalStartAddress; } TypeRefBuilder::TypeRefBuilder() : TC(*this) {} @@ -87,27 +86,21 @@ lookupTypeWitness(const std::string &MangledTypeName, // Cache missed - we need to look through all of the assocty sections // for all images that we've been notified about. for (auto &Info : ReflectionInfos) { - uint64_t TypeRefOffset = Info.AssociatedType.SectionOffset - - Info.TypeReference.SectionOffset; - uint64_t NameOffset = Info.AssociatedType.SectionOffset - - Info.ReflectionString.SectionOffset; - for (const auto &AssocTyDescriptor : Info.AssociatedType.Metadata) { + for (const auto &AssocTyDescriptor : Info.AssociatedType) { if (!reflectionNameMatches( - AssocTyDescriptor.getMangledConformingTypeName(TypeRefOffset), + AssocTyDescriptor.getMangledConformingTypeName(), MangledTypeName)) continue; - if (!reflectionNameMatches( - AssocTyDescriptor.getMangledProtocolTypeName(TypeRefOffset), - Protocol)) + if (!reflectionNameMatches(AssocTyDescriptor.getMangledProtocolTypeName(), + Protocol)) continue; for (auto &AssocTy : AssocTyDescriptor) { - if (Member.compare(AssocTy.getName(NameOffset)) != 0) + if (Member.compare(AssocTy.getName()) != 0) continue; - auto SubstitutedTypeName = - AssocTy.getMangledSubstitutedTypeName(TypeRefOffset); + auto SubstitutedTypeName = AssocTy.getMangledSubstitutedTypeName(); auto Demangled = demangleTypeRef(SubstitutedTypeName); auto *TypeWitness = swift::Demangle::decodeMangledType(*this, Demangled); @@ -128,9 +121,7 @@ lookupSuperclass(const TypeRef *TR) { if (!FD.first->hasSuperclass()) return nullptr; - auto TypeRefOffset = FD.second->Field.SectionOffset - - FD.second->TypeReference.SectionOffset; - auto Demangled = demangleTypeRef(FD.first->getSuperclass(TypeRefOffset)); + auto Demangled = demangleTypeRef(FD.first->getSuperclass()); auto Unsubstituted = swift::Demangle::decodeMangledType(*this, Demangled); if (!Unsubstituted) return nullptr; @@ -159,12 +150,10 @@ TypeRefBuilder::getFieldTypeInfo(const TypeRef *TR) { // On failure, fill out the cache with everything we know about. std::vector> Fields; for (auto &Info : ReflectionInfos) { - uint64_t TypeRefOffset = Info.Field.SectionOffset - - Info.TypeReference.SectionOffset; - for (auto &FD : Info.Field.Metadata) { + for (auto &FD : Info.Field) { if (!FD.hasMangledTypeName()) continue; - auto CandidateMangledName = FD.getMangledTypeName(TypeRefOffset); + auto CandidateMangledName = FD.getMangledTypeName(); auto NormalizedName = normalizeReflectionName(CandidateMangledName); FieldTypeInfoCache[NormalizedName] = {&FD, &Info}; Dem.clear(); @@ -191,13 +180,9 @@ bool TypeRefBuilder::getFieldTypeRefs( return false; for (auto &Field : *FD.first) { - auto TypeRefOffset = FD.second->Field.SectionOffset - - FD.second->TypeReference.SectionOffset; - auto FieldOffset = FD.second->Field.SectionOffset - - FD.second->ReflectionString.SectionOffset; - auto Low = (uintptr_t)(FD.second->ReflectionString.Metadata.startAddress()); - auto High = (uintptr_t)(FD.second->ReflectionString.Metadata.endAddress()); - auto FieldName = Field.getFieldName(FieldOffset, Low, High); + auto Low = (uintptr_t)(FD.second->ReflectionString.startAddress()); + auto High = (uintptr_t)(FD.second->ReflectionString.endAddress()); + auto FieldName = Field.getFieldName(Low, High); // Empty cases of enums do not have a type if (FD.first->isEnum() && !Field.hasMangledTypeName()) { @@ -205,7 +190,7 @@ bool TypeRefBuilder::getFieldTypeRefs( continue; } - auto Demangled = demangleTypeRef(Field.getMangledTypeName(TypeRefOffset)); + auto Demangled = demangleTypeRef(Field.getMangledTypeName()); auto Unsubstituted = swift::Demangle::decodeMangledType(*this, Demangled); if (!Unsubstituted) return false; @@ -235,16 +220,14 @@ TypeRefBuilder::getBuiltinTypeInfo(const TypeRef *TR) { return nullptr; for (auto Info : ReflectionInfos) { - uint64_t TypeRefOffset = Info.Builtin.SectionOffset - - Info.TypeReference.SectionOffset; - for (auto &BuiltinTypeDescriptor : Info.Builtin.Metadata) { + for (auto &BuiltinTypeDescriptor : Info.Builtin) { assert(BuiltinTypeDescriptor.Size > 0); assert(BuiltinTypeDescriptor.getAlignment() > 0); assert(BuiltinTypeDescriptor.Stride > 0); if (!BuiltinTypeDescriptor.hasMangledTypeName()) continue; auto CandidateMangledName = - BuiltinTypeDescriptor.getMangledTypeName(TypeRefOffset); + BuiltinTypeDescriptor.getMangledTypeName(); if (!reflectionNameMatches(CandidateMangledName, MangledName)) continue; return &BuiltinTypeDescriptor; @@ -257,7 +240,7 @@ TypeRefBuilder::getBuiltinTypeInfo(const TypeRef *TR) { const CaptureDescriptor * TypeRefBuilder::getCaptureDescriptor(uint64_t RemoteAddress) { for (auto Info : ReflectionInfos) { - for (auto &CD : Info.Capture.Metadata) { + for (auto &CD : Info.Capture) { auto OtherAddr = (reinterpret_cast(&CD) - Info.LocalStartAddress + Info.RemoteStartAddress); if (OtherAddr == RemoteAddress) @@ -270,14 +253,13 @@ TypeRefBuilder::getCaptureDescriptor(uint64_t RemoteAddress) { /// Get the unsubstituted capture types for a closure context. ClosureContextInfo -TypeRefBuilder::getClosureContextInfo(const CaptureDescriptor &CD, - uint64_t TypeRefOffset) { +TypeRefBuilder::getClosureContextInfo(const CaptureDescriptor &CD) { ClosureContextInfo Info; for (auto i = CD.capture_begin(), e = CD.capture_end(); i != e; ++i) { const TypeRef *TR = nullptr; if (i->hasMangledTypeName()) { - auto MangledName = i->getMangledTypeName(TypeRefOffset); + auto MangledName = i->getMangledTypeName(); auto DemangleTree = demangleTypeRef(MangledName); TR = swift::Demangle::decodeMangledType(*this, DemangleTree); } @@ -287,14 +269,14 @@ TypeRefBuilder::getClosureContextInfo(const CaptureDescriptor &CD, for (auto i = CD.source_begin(), e = CD.source_end(); i != e; ++i) { const TypeRef *TR = nullptr; if (i->hasMangledTypeName()) { - auto MangledName = i->getMangledTypeName(TypeRefOffset); + auto MangledName = i->getMangledTypeName(); auto DemangleTree = demangleTypeRef(MangledName); TR = swift::Demangle::decodeMangledType(*this, DemangleTree); } const MetadataSource *MS = nullptr; if (i->hasMangledMetadataSource()) { - auto MangledMetadataSource = i->getMangledMetadataSource(TypeRefOffset); + auto MangledMetadataSource = i->getMangledMetadataSource(); MS = MetadataSource::decode(MSB, MangledMetadataSource); } @@ -329,26 +311,22 @@ TypeRefBuilder::dumpTypeRef(StringRef MangledName, void TypeRefBuilder::dumpFieldSection(std::ostream &OS) { for (const auto §ions : ReflectionInfos) { - uint64_t TypeRefOffset = sections.Field.SectionOffset - - sections.TypeReference.SectionOffset; - uint64_t NameOffset = sections.Field.SectionOffset - - sections.ReflectionString.SectionOffset; - for (const auto &descriptor : sections.Field.Metadata) { + for (const auto &descriptor : sections.Field) { auto TypeDemangling = demangleTypeRef( - dropSwiftManglingPrefix(descriptor.getMangledTypeName(TypeRefOffset))); + dropSwiftManglingPrefix(descriptor.getMangledTypeName())); auto TypeName = nodeToString(TypeDemangling); OS << TypeName << '\n'; for (size_t i = 0; i < TypeName.size(); ++i) OS << '-'; OS << '\n'; for (auto &field : descriptor) { - auto Low = (uintptr_t)sections.ReflectionString.Metadata.startAddress(); - auto High = (uintptr_t)sections.ReflectionString.Metadata.endAddress(); - OS << std::string(field.getFieldName(NameOffset, Low, High).begin(), - field.getFieldName(NameOffset, Low, High).end()); + auto Low = (uintptr_t)sections.ReflectionString.startAddress(); + auto High = (uintptr_t)sections.ReflectionString.endAddress(); + OS << std::string(field.getFieldName(Low, High).begin(), + field.getFieldName(Low, High).end()); if (field.hasMangledTypeName()) { OS << ": "; - dumpTypeRef(field.getMangledTypeName(TypeRefOffset), OS); + dumpTypeRef(field.getMangledTypeName(), OS); } else { OS << "\n\n"; } @@ -359,26 +337,21 @@ void TypeRefBuilder::dumpFieldSection(std::ostream &OS) { void TypeRefBuilder::dumpAssociatedTypeSection(std::ostream &OS) { for (const auto §ions : ReflectionInfos) { - uint64_t TypeRefOffset = sections.AssociatedType.SectionOffset - - sections.TypeReference.SectionOffset; - uint64_t NameOffset = sections.AssociatedType.SectionOffset - - sections.ReflectionString.SectionOffset; - for (const auto &descriptor : sections.AssociatedType.Metadata) { + for (const auto &descriptor : sections.AssociatedType) { auto conformingTypeNode = demangleTypeRef( - descriptor.getMangledConformingTypeName(TypeRefOffset)); + descriptor.getMangledConformingTypeName()); auto conformingTypeName = nodeToString(conformingTypeNode); auto protocolNode = demangleTypeRef(dropSwiftManglingPrefix( - descriptor.getMangledProtocolTypeName(TypeRefOffset))); + descriptor.getMangledProtocolTypeName())); auto protocolName = nodeToString(protocolNode); OS << "- " << conformingTypeName << " : " << protocolName; OS << '\n'; for (const auto &associatedType : descriptor) { - std::string name = associatedType.getName(NameOffset); + std::string name = associatedType.getName(); OS << "typealias " << name << " = "; - dumpTypeRef( - associatedType.getMangledSubstitutedTypeName(TypeRefOffset), OS); + dumpTypeRef(associatedType.getMangledSubstitutedTypeName(), OS); } } } @@ -386,11 +359,8 @@ void TypeRefBuilder::dumpAssociatedTypeSection(std::ostream &OS) { void TypeRefBuilder::dumpBuiltinTypeSection(std::ostream &OS) { for (const auto §ions : ReflectionInfos) { - uint64_t TypeRefOffset = sections.Builtin.SectionOffset - - sections.TypeReference.SectionOffset; - for (const auto &descriptor : sections.Builtin.Metadata) { - auto typeNode = demangleTypeRef( - descriptor.getMangledTypeName(TypeRefOffset)); + for (const auto &descriptor : sections.Builtin) { + auto typeNode = demangleTypeRef(descriptor.getMangledTypeName()); auto typeName = nodeToString(typeNode); OS << "\n- " << typeName << ":\n"; @@ -431,10 +401,8 @@ void ClosureContextInfo::dump(std::ostream &OS) const { void TypeRefBuilder::dumpCaptureSection(std::ostream &OS) { for (const auto §ions : ReflectionInfos) { - uint64_t TypeRefOffset = sections.Capture.SectionOffset - - sections.TypeReference.SectionOffset; - for (const auto &descriptor : sections.Capture.Metadata) { - auto info = getClosureContextInfo(descriptor, TypeRefOffset); + for (const auto &descriptor : sections.Capture) { + auto info = getClosureContextInfo(descriptor); info.dump(OS); } } diff --git a/stdlib/public/SwiftRemoteMirror/SwiftRemoteMirror.cpp b/stdlib/public/SwiftRemoteMirror/SwiftRemoteMirror.cpp index bc4a7bb1f661f..a888a6c93545e 100644 --- a/stdlib/public/SwiftRemoteMirror/SwiftRemoteMirror.cpp +++ b/stdlib/public/SwiftRemoteMirror/SwiftRemoteMirror.cpp @@ -119,7 +119,29 @@ swift_reflection_addReflectionInfo(SwiftReflectionContextRef ContextRef, swift_reflection_info_t Info) { auto Context = ContextRef->nativeContext; - Context->addReflectionInfo(*reinterpret_cast(&Info)); + // The `offset` fields must be zero. + if (Info.field.offset != 0 + || Info.associated_types.offset != 0 + || Info.builtin_types.offset != 0 + || Info.capture.offset != 0 + || Info.type_references.offset != 0 + || Info.reflection_strings.offset != 0) { + fprintf(stderr, "reserved field in swift_reflection_info_t is not zero\n"); + abort(); + } + + ReflectionInfo ContextInfo{ + {Info.field.section.Begin, Info.field.section.End}, + {Info.associated_types.section.Begin, Info.associated_types.section.End}, + {Info.builtin_types.section.Begin, Info.builtin_types.section.End}, + {Info.capture.section.Begin, Info.capture.section.End}, + {Info.type_references.section.Begin, Info.type_references.section.End}, + {Info.reflection_strings.section.Begin, Info.reflection_strings.section.End}, + Info.LocalStartAddress, + Info.RemoteStartAddress + }; + + Context->addReflectionInfo(ContextInfo); } int diff --git a/stdlib/public/core/Array.swift b/stdlib/public/core/Array.swift index 3ebbc6d682a07..44260a599c5cf 100644 --- a/stdlib/public/core/Array.swift +++ b/stdlib/public/core/Array.swift @@ -1971,7 +1971,8 @@ extension Array.DifferentiableView : EuclideanDifferentiable } } -extension Array.DifferentiableView : Equatable where Element : Equatable { +extension Array.DifferentiableView : Equatable + where Element : Differentiable & Equatable { public static func == ( lhs: Array.DifferentiableView, rhs: Array.DifferentiableView @@ -1980,13 +1981,15 @@ extension Array.DifferentiableView : Equatable where Element : Equatable { } } -extension Array.DifferentiableView : ExpressibleByArrayLiteral { +extension Array.DifferentiableView : ExpressibleByArrayLiteral + where Element : Differentiable { public init(arrayLiteral elements: Element...) { self.init(elements) } } -extension Array.DifferentiableView : CustomStringConvertible { +extension Array.DifferentiableView : CustomStringConvertible + where Element : Differentiable { public var description: String { return base.description } @@ -1997,7 +2000,7 @@ extension Array.DifferentiableView : CustomStringConvertible { /// Note that `Array.DifferentiableView([])` is the zero in the product spaces /// of all counts. extension Array.DifferentiableView : AdditiveArithmetic - where Element : AdditiveArithmetic { + where Element : AdditiveArithmetic & Differentiable { public static var zero: Array.DifferentiableView { return Array.DifferentiableView([]) diff --git a/stdlib/public/runtime/ReflectionMirror.mm b/stdlib/public/runtime/ReflectionMirror.mm index eb595472e6e6d..31dc898e2b584 100644 --- a/stdlib/public/runtime/ReflectionMirror.mm +++ b/stdlib/public/runtime/ReflectionMirror.mm @@ -328,13 +328,13 @@ static bool _shouldReportMissingReflectionMetadataWarnings() { const FieldDescriptor &descriptor = *fields; auto &field = descriptor.getFields()[index]; // Bounds are always valid as the offset is constant. - auto name = field.getFieldName(0, 0, std::numeric_limits::max()); + auto name = field.getFieldName(0, std::numeric_limits::max()); // Enum cases don't always have types. if (!field.hasMangledTypeName()) return {name, FieldType().withIndirect(field.isIndirectCase())}; - auto typeName = field.getMangledTypeName(0); + auto typeName = field.getMangledTypeName(); SubstGenericParametersFromMetadata substitutions(base); auto typeInfo = swift_getTypeByMangledName(MetadataState::Complete, diff --git a/stdlib/public/stubs/ThreadLocalStorage.cpp b/stdlib/public/stubs/ThreadLocalStorage.cpp index 7a51daaf0da56..50168f955bc6c 100644 --- a/stdlib/public/stubs/ThreadLocalStorage.cpp +++ b/stdlib/public/stubs/ThreadLocalStorage.cpp @@ -23,6 +23,8 @@ void _stdlib_destroyTLS(void *); SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_API void *_stdlib_createTLS(void); +#if !SWIFT_TLS_HAS_RESERVED_PTHREAD_SPECIFIC || (defined(_WIN32) && !defined(__CYGWIN__)) + static void #if defined(_M_IX86) __stdcall @@ -31,6 +33,8 @@ destroyTLS_CCAdjustmentThunk(void *ptr) { _stdlib_destroyTLS(ptr); } +#endif + #if defined(_WIN32) && !defined(__CYGWIN__) typedef diff --git a/test/Constraints/closures.swift b/test/Constraints/closures.swift index 0850eac442e7c..7680bab6e13c6 100644 --- a/test/Constraints/closures.swift +++ b/test/Constraints/closures.swift @@ -394,7 +394,7 @@ func rdar20868864(_ s: String) { func r22058555() { var firstChar: UInt8 = 0 "abc".withCString { chars in - firstChar = chars[0] // expected-error {{cannot assign value of type 'Int8' to type 'UInt8'}} + firstChar = chars[0] // expected-error {{cannot assign value of type 'Int8' to type 'UInt8'}} {{17-17=UInt8(}} {{25-25=)}} } } diff --git a/test/Constraints/diagnostics.swift b/test/Constraints/diagnostics.swift index bc76267222193..a93bc79768ecd 100644 --- a/test/Constraints/diagnostics.swift +++ b/test/Constraints/diagnostics.swift @@ -28,6 +28,9 @@ func f3(_: @escaping (_: @escaping (Int) -> Float) -> Int) {} func f4(_ x: Int) -> Int { } func f5(_ : T) { } +// expected-note@-1 {{required by global function 'f5' where 'T' = '(Int) -> Int'}} +// expected-note@-2 {{required by global function 'f5' where 'T' = '(Int, String)'}} +// expected-note@-3 {{required by global function 'f5' where 'T' = 'Int.Type'}} func f6(_ t: T, _ u: U) where T.SomeType == U.SomeType {} @@ -46,8 +49,10 @@ f0(i, i, i) // expected-error{{extra argument in call}} -// Position mismatch -f5(f4) // expected-error {{argument type '(Int) -> Int' does not conform to expected type 'P2'}} +// Cannot conform to protocols. +f5(f4) // expected-error {{type '(Int) -> Int' cannot conform to 'P2'; only struct/enum/class types can conform to protocols}} +f5((1, "hello")) // expected-error {{type '(Int, String)' cannot conform to 'P2'; only struct/enum/class types can conform to protocols}} +f5(Int.self) // expected-error {{type 'Int.Type' cannot conform to 'P2'; only struct/enum/class types can conform to protocols}} // Tuple element not convertible. f0(i, @@ -94,10 +99,11 @@ func f7() -> (c: Int, v: A) { } func f8(_ n: T, _ f: @escaping (T) -> T) {} +// expected-note@-1 {{required by global function 'f8' where 'T' = 'Tup' (aka '(Int, Double)')}} f8(3, f4) // expected-error {{argument type 'Int' does not conform to expected type 'P2'}} typealias Tup = (Int, Double) func f9(_ x: Tup) -> Tup { return x } -f8((1,2.0), f9) // expected-error {{argument type 'Tup' (aka '(Int, Double)') does not conform to expected type 'P2'}} +f8((1,2.0), f9) // expected-error {{type 'Tup' (aka '(Int, Double)') cannot conform to 'P2'; only struct/enum/class types can conform to protocols}} // QoI: Incorrect diagnostic for calling nonexistent members on literals 1.doesntExist(0) // expected-error {{value of type 'Int' has no member 'doesntExist'}} @@ -188,10 +194,10 @@ func r17224804(_ monthNumber : Int) { // QoI: Operand of postfix '!' should have optional type; type is 'Int?' func r17020197(_ x : Int?, y : Int) { - if x! { } // expected-error {{'Int' is not convertible to 'Bool'}} + if x! { } // expected-error {{cannot convert value of type 'Int' to expected condition type 'Bool'}} // QoI: diagnostic for using an integer in a condition is utterly terrible - if y {} // expected-error {{'Int' is not convertible to 'Bool'}} + if y {} // expected-error {{cannot convert value of type 'Int' to expected condition type 'Bool'}} } // QoI: Boolean expr not treated as Bool type when function return type is different @@ -299,6 +305,62 @@ func rdar21784170() { (Array.init as (Double...) -> Array)(initial as (Double, Double)) // expected-error {{cannot convert value of type '(Double, Double)' to expected argument type 'Double'}} } +// Diagnose passing an array in lieu of variadic parameters +func variadic(_ x: Int...) {} +func variadicArrays(_ x: [Int]...) {} +func variadicAny(_ x: Any...) {} +struct HasVariadicSubscript { + subscript(_ x: Int...) -> Int { + get { 0 } + } +} +let foo = HasVariadicSubscript() + +let array = [1,2,3] +let arrayWithOtherEltType = ["hello", "world"] + +variadic(array) // expected-error {{cannot pass array of type '[Int]' as variadic arguments of type 'Int'}} +variadic([1,2,3]) // expected-error {{cannot pass array of type '[Int]' as variadic arguments of type 'Int'}} +// expected-note@-1 {{remove brackets to pass array elements directly}} {{10-11=}} {{16-17=}} +variadic([1,2,3,]) // expected-error {{cannot pass array of type '[Int]' as variadic arguments of type 'Int'}} +// expected-note@-1 {{remove brackets to pass array elements directly}} {{10-11=}} {{16-17=}} {{17-18=}} +variadic(0, array, 4) // expected-error {{cannot pass array of type '[Int]' as variadic arguments of type 'Int'}} +variadic(0, [1,2,3], 4) // expected-error {{cannot pass array of type '[Int]' as variadic arguments of type 'Int'}} +// expected-note@-1 {{remove brackets to pass array elements directly}} {{13-14=}} {{19-20=}} +variadic(0, [1,2,3,], 4) // expected-error {{cannot pass array of type '[Int]' as variadic arguments of type 'Int'}} +// expected-note@-1 {{remove brackets to pass array elements directly}} {{13-14=}} {{19-20=}} {{20-21=}} +variadic(arrayWithOtherEltType) // expected-error {{cannot convert value of type '[String]' to expected argument type 'Int'}} +variadic(1, arrayWithOtherEltType) // expected-error {{cannot convert value of type '[String]' to expected argument type 'Int'}} + +// FIXME: SR-11104 +variadic(["hello", "world"]) // expected-error 2 {{cannot convert value of type 'String' to expected element type 'Int'}} +// expected-error@-1 {{cannot pass array of type '[Int]' as variadic arguments of type 'Int'}} +// expected-note@-2 {{remove brackets to pass array elements directly}} + +variadic([1] + [2] as [Int]) // expected-error {{cannot pass array of type '[Int]' as variadic arguments of type 'Int'}} + +foo[array] // expected-error {{cannot pass array of type '[Int]' as variadic arguments of type 'Int'}} +foo[[1,2,3]] // expected-error {{cannot pass array of type '[Int]' as variadic arguments of type 'Int'}} +// expected-note@-1 {{remove brackets to pass array elements directly}} {{5-6=}} {{11-12=}} +foo[0, [1,2,3], 4] // expected-error {{cannot pass array of type '[Int]' as variadic arguments of type 'Int'}} +// expected-note@-1 {{remove brackets to pass array elements directly}} {{8-9=}} {{14-15=}} + +variadicAny(array) +variadicAny([1,2,3]) +variadicArrays(array) +variadicArrays([1,2,3]) +variadicArrays(arrayWithOtherEltType) // expected-error {{cannot convert value of type '[String]' to expected argument type '[Int]'}} +// expected-note@-1 {{arguments to generic parameter 'Element' ('String' and 'Int') are expected to be equal}} +variadicArrays(1,2,3) // expected-error 3 {{cannot convert value of type 'Int' to expected argument type '[Int]'}} + +protocol Proto {} +func f(x: [T]) {} +func f(x: Int...) {} +f(x: [1,2,3]) +// TODO(diagnostics): Diagnose both the missing conformance and the disallowed array splat to cover both overloads. +// expected-error@-2 {{cannot pass array of type '[Int]' as variadic arguments of type 'Int'}} +// expected-note@-3 {{remove brackets to pass array elements directly}} + // BOGUS: unexpected trailing closure func expect(_: T) -> (U.Type) -> Int { return { a in 0 } } func expect(_: T, _: Int = 1) -> (U.Type) -> String { return { a in "String" } } diff --git a/test/Constraints/fixes.swift b/test/Constraints/fixes.swift index fd114c918a0a5..028977eeafde7 100644 --- a/test/Constraints/fixes.swift +++ b/test/Constraints/fixes.swift @@ -321,3 +321,18 @@ func test_explicit_call_with_overloads() { foo(S().foo) // expected-error@-1 {{function produces expected type 'Int'; did you mean to call it with '()'?}} {{14-14=()}} } + +// SR-11476 +func testKeyPathSubscriptArgFixes(_ fn: @escaping () -> Int) { + struct S { + subscript(x: Int) -> Int { x } + } + + var i: Int? + _ = \S.[i] // expected-error {{value of optional type 'Int?' must be unwrapped to a value of type 'Int'}} + // expected-note@-1{{coalesce using '??' to provide a default when the optional value contains 'nil'}}{{12-12= ?? <#default value#>}} + // expected-note@-2{{force-unwrap using '!' to abort execution if the optional value contains 'nil'}}{{12-12=!}} + + _ = \S.[nil] // expected-error {{'nil' is not compatible with expected argument type 'Int'}} + _ = \S.[fn] // expected-error {{function produces expected type 'Int'; did you mean to call it with '()'?}} {{13-13=()}} +} diff --git a/test/Constraints/function_builder_diags.swift b/test/Constraints/function_builder_diags.swift index e88268dcd53d2..d7de38e317334 100644 --- a/test/Constraints/function_builder_diags.swift +++ b/test/Constraints/function_builder_diags.swift @@ -144,7 +144,7 @@ struct TupleP : P { @_functionBuilder struct Builder { - static func buildBlock(_ stmt1: S0, _ stmt2: S1) // expected-note {{where 'S1' = 'Label.Type'}} + static func buildBlock(_ stmt1: S0, _ stmt2: S1) // expected-note {{required by static method 'buildBlock' where 'S1' = 'Label.Type'}} -> TupleP<(S0, S1)> where S0: P, S1: P { return TupleP((stmt1, stmt2)) } @@ -166,7 +166,7 @@ struct Label : P where L : P { // expected-note {{'L' declared as parameter t } func test_51167632() -> some P { - AnyP(G { // expected-error {{static method 'buildBlock' requires that 'Label.Type' conform to 'P'}} + AnyP(G { // expected-error {{type 'Label.Type' cannot conform to 'P'; only struct/enum/class types can conform to protocols}} Text("hello") Label // expected-error {{generic parameter 'L' could not be inferred}} // expected-note@-1 {{explicitly specify the generic arguments to fix this issue}} {{10-10=<<#L: P#>>}} diff --git a/test/Constraints/generics.swift b/test/Constraints/generics.swift index 4ae79c4a1cf38..854ba2a963fff 100644 --- a/test/Constraints/generics.swift +++ b/test/Constraints/generics.swift @@ -188,7 +188,8 @@ func r22459135() { // QoI: Friendlier error message for "[] as Set" // QoI: "argument for generic parameter 'Element' could not be inferred" lacks context -_ = [] as Set // expected-error {{protocol type 'Any' cannot conform to 'Hashable' because only concrete types can conform to protocols}} +_ = [] as Set // expected-error {{value of protocol type 'Any' cannot conform to 'Hashable'; only struct/enum/class types can conform to protocols}} +// expected-note@-1 {{required by generic struct 'Set' where 'Element' = 'Any'}} // QoI: Error when unable to infer generic archetype lacks greatness diff --git a/test/Constraints/invalid_logicvalue_coercion.swift b/test/Constraints/invalid_logicvalue_coercion.swift index 32fb212948540..f703295130a12 100644 --- a/test/Constraints/invalid_logicvalue_coercion.swift +++ b/test/Constraints/invalid_logicvalue_coercion.swift @@ -2,8 +2,8 @@ class C {} var c = C() -if c as C { // expected-error{{'C' is not convertible to 'Bool'}} +if c as C { // expected-error{{cannot convert value of type 'C' to expected condition type 'Bool'}} } -if ({1} as () -> Int) { // expected-error{{'() -> Int' is not convertible to 'Bool'}} +if ({1} as () -> Int) { // expected-error{{cannot convert value of type '() -> Int' to expected condition type 'Bool'}} } diff --git a/test/Constraints/operator.swift b/test/Constraints/operator.swift index ca26d1a366bd3..14cdeb624d2e2 100644 --- a/test/Constraints/operator.swift +++ b/test/Constraints/operator.swift @@ -220,7 +220,8 @@ func rdar46459603() { // expected-error@-1 {{binary operator '==' cannot be applied to operands of type 'Dictionary.Values' and '[E]'}} // expected-note@-2 {{expected an argument list of type '(Self, Self)'}} _ = [arr.values] == [[e]] - // expected-error@-1 {{protocol type 'Any' cannot conform to 'Equatable' because only concrete types can conform to protocols}} + // expected-error@-1 {{value of protocol type 'Any' cannot conform to 'Equatable'; only struct/enum/class types can conform to protocols}} + // expected-note@-2 {{requirement from conditional conformance of '[Any]' to 'Equatable'}} } // SR-10843 diff --git a/test/Generics/conditional_conformances_literals.swift b/test/Generics/conditional_conformances_literals.swift index 5bb0c3726f923..f722b89c3ae56 100644 --- a/test/Generics/conditional_conformances_literals.swift +++ b/test/Generics/conditional_conformances_literals.swift @@ -16,6 +16,7 @@ extension Array: Conforms where Element: Conforms {} // expected-note@-1 5 {{requirement from conditional conformance of '[Fails]' to 'Conforms'}} extension Dictionary: Conforms where Value: Conforms {} // expected-note@-1 3 {{requirement from conditional conformance of '[Int : Fails]' to 'Conforms'}} +// expected-note@-2 2 {{requirement from conditional conformance of '[Int : Conforms]' to 'Conforms'}} let works = Works() let fails = Fails() @@ -127,9 +128,9 @@ func combined() { // Needs self conforming protocols: let _: Conforms = [[0: [1 : [works]] as Conforms]] - // expected-error@-1 {{protocol type 'Conforms' cannot conform to 'Conforms' because only concrete types can conform to protocols}} + // expected-error@-1 {{value of protocol type 'Conforms' cannot conform to 'Conforms'; only struct/enum/class types can conform to protocols}} let _: Conforms = [[0: [1 : [fails]] as Conforms]] // expected-error@-1 {{protocol 'Conforms' requires that 'Fails' conform to 'Conforms'}} - // expected-error@-2 {{protocol type 'Conforms' cannot conform to 'Conforms' because only concrete types can conform to protocols}} + // expected-error@-2 {{value of protocol type 'Conforms' cannot conform to 'Conforms'; only struct/enum/class types can conform to protocols}} } diff --git a/test/Generics/deduction.swift b/test/Generics/deduction.swift index ea7a3deb426ca..e10bf9fffaa8f 100644 --- a/test/Generics/deduction.swift +++ b/test/Generics/deduction.swift @@ -22,7 +22,7 @@ func useIdentity(_ x: Int, y: Float, i32: Int32) { // Deduction where the result type and input type can get different results var xx : X, yy : Y - xx = identity(yy) // expected-error{{cannot convert value of type 'Y' to expected argument type 'X'}} + xx = identity(yy) // expected-error{{cannot assign value of type 'Y' to type 'X'}} xx = identity2(yy) // expected-error{{cannot convert value of type 'Y' to expected argument type 'X'}} } diff --git a/test/Generics/existential_restrictions.swift b/test/Generics/existential_restrictions.swift index 9731372ae7f6e..8f1d2e459dabc 100644 --- a/test/Generics/existential_restrictions.swift +++ b/test/Generics/existential_restrictions.swift @@ -9,7 +9,10 @@ protocol CP : class { } } func fP(_ t: T) { } +// expected-note@-1 {{required by global function 'fP' where 'T' = 'P'}} +// expected-note@-2 {{required by global function 'fP' where 'T' = 'OP & P'}} func fOP(_ t: T) { } +// expected-note@-1 {{required by global function 'fOP' where 'T' = 'OP & P'}} func fOPE(_ t: OP) { } func fSP(_ t: T) { } func fAO(_ t: T) { } @@ -17,7 +20,7 @@ func fAOE(_ t: AnyObject) { } func fT(_ t: T) { } func testPassExistential(_ p: P, op: OP, opp: OP & P, cp: CP, sp: SP, any: Any, ao: AnyObject) { - fP(p) // expected-error{{protocol type 'P' cannot conform to 'P' because only concrete types can conform to protocols}} + fP(p) // expected-error{{value of protocol type 'P' cannot conform to 'P'; only struct/enum/class types can conform to protocols}} fAO(p) // expected-error{{cannot invoke 'fAO' with an argument list of type '(P)'}} // expected-note{{expected an argument list of type '(T)'}} fAOE(p) // expected-error{{argument type 'P' does not conform to expected type 'AnyObject'}} fT(p) @@ -31,8 +34,8 @@ func testPassExistential(_ p: P, op: OP, opp: OP & P, cp: CP, sp: SP, any: Any, fAOE(cp) fT(cp) - fP(opp) // expected-error{{protocol type 'OP & P' cannot conform to 'P' because only concrete types can conform to protocols}} - fOP(opp) // expected-error{{protocol type 'OP & P' cannot conform to 'OP' because only concrete types can conform to protocols}} + fP(opp) // expected-error{{value of protocol type 'OP & P' cannot conform to 'P'; only struct/enum/class types can conform to protocols}} + fOP(opp) // expected-error{{value of protocol type 'OP & P' cannot conform to 'OP'; only struct/enum/class types can conform to protocols}} fAO(opp) // expected-error{{cannot invoke 'fAO' with an argument list of type '(OP & P)'}} // expected-note{{expected an argument list of type '(T)'}} fAOE(opp) fT(opp) @@ -58,9 +61,9 @@ class GAO {} // expected-note 2{{requirement specified as 'T' : ' func blackHole(_ t: Any) {} func testBindExistential() { - blackHole(GP

()) // expected-error{{protocol type 'P' cannot conform to 'P' because only concrete types can conform to protocols}} + blackHole(GP

()) // expected-error{{value of protocol type 'P' cannot conform to 'P'; only struct/enum/class types can conform to protocols}} blackHole(GOP()) - blackHole(GCP()) // expected-error{{protocol type 'CP' cannot conform to 'CP' because only concrete types can conform to protocols}} + blackHole(GCP()) // expected-error{{value of protocol type 'CP' cannot conform to 'CP'; only struct/enum/class types can conform to protocols}} blackHole(GAO

()) // expected-error{{'GAO' requires that 'P' be a class type}} blackHole(GAO()) blackHole(GAO()) // expected-error{{'GAO' requires that 'CP' be a class type}} @@ -73,6 +76,7 @@ protocol Mine {} class M1: Mine {} class M2: Mine {} extension Collection where Iterator.Element : Mine { +// expected-note@-1 {{required by referencing instance method 'takeAll()' on 'Collection'}} func takeAll() {} } @@ -85,5 +89,5 @@ func foo() { // generic no overloads error path. The error should actually talk // about the return type, and this can happen in other contexts as well; // tracks improving QoI here. - allMine.takeAll() // expected-error{{protocol type 'Mine' cannot conform to 'Mine' because only concrete types can conform to protocols}} + allMine.takeAll() // expected-error{{value of protocol type 'Mine' cannot conform to 'Mine'; only struct/enum/class types can conform to protocols}} } diff --git a/test/Generics/generic_types.swift b/test/Generics/generic_types.swift index 33e6aa36eb6bc..54af5d8858056 100644 --- a/test/Generics/generic_types.swift +++ b/test/Generics/generic_types.swift @@ -230,6 +230,8 @@ class Top {} class Bottom> {} // expected-error@-1 {{generic class 'Bottom' references itself}} // expected-note@-2 {{type declared here}} +// expected-error@-3 {{circular reference}} +// expected-note@-4 {{through reference here}} // Invalid inheritance clause diff --git a/test/Generics/requirement_inference.swift b/test/Generics/requirement_inference.swift index 60afcd73d7e59..6f29047e0b100 100644 --- a/test/Generics/requirement_inference.swift +++ b/test/Generics/requirement_inference.swift @@ -383,7 +383,7 @@ struct X28 : P2 { } // CHECK-LABEL: .P28@ -// CHECK-NEXT: Requirement signature: +// CHECK-NEXT: Requirement signature: // CHECK-NEXT: Canonical requirement signature: <τ_0_0 where τ_0_0 : P3, τ_0_0.P3Assoc == X28> protocol P28: P3 { typealias P3Assoc = X28 // expected-warning{{typealias overriding associated type}} diff --git a/test/IDE/complete_associated_types.swift b/test/IDE/complete_associated_types.swift index 711c615cf7525..6da3919844627 100644 --- a/test/IDE/complete_associated_types.swift +++ b/test/IDE/complete_associated_types.swift @@ -20,6 +20,15 @@ // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=BROKEN_CONFORMANCE_1 > %t.types.txt // RUN: %FileCheck %s -check-prefix=BROKEN_CONFORMANCE_1 < %t.types.txt +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=BROKEN_CONFORMANCE_UNASSIGNABLE > %t.types.txt +// RUN: %FileCheck %s -check-prefix=BROKEN_CONFORMANCE_UNASSIGNABLE < %t.types.txt + +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=BROKEN_CONFORMANCE_UNASSIGNABLE_2 > %t.types.txt +// RUN: %FileCheck %s -check-prefix=BROKEN_CONFORMANCE_UNASSIGNABLE < %t.types.txt + +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=BROKEN_CONFORMANCE_ASSIGNABLE > %t.types.txt +// RUN: %FileCheck %s -check-prefix=BROKEN_CONFORMANCE_ASSIGNABLE < %t.types.txt + // FIXME: extensions that introduce conformances? protocol FooBaseProtocolWithAssociatedTypes { @@ -300,3 +309,44 @@ func testBrokenConformances1() { // BROKEN_CONFORMANCE_1-DAG: Decl[InstanceMethod]/Super: deduceFooBaseC({#(self): StructWithBrokenConformance#})[#() -> StructWithBrokenConformance.FooBaseDeducedTypeC#]{{; name=.+$}} // BROKEN_CONFORMANCE_1-DAG: Decl[InstanceMethod]/Super: deduceFooBaseD({#(self): StructWithBrokenConformance#})[#() -> StructWithBrokenConformance.FooBaseDeducedTypeD#]{{; name=.+$}} // BROKEN_CONFORMANCE_1: End completions + + +protocol MyProto { + associatedtype Element +} + +extension MyProto { + var matches: (Int, (Int, Int)) { fatalError() } + func first() -> Element { + fatalError() + } +} + +// Does not conform - Element not specified +struct A: MyProto { + func foo() { + self.first = #^BROKEN_CONFORMANCE_UNASSIGNABLE^# + } + + func foo2() { + var (a, b): (Int, Int) + let exact = (1, (2, 4)) + (a, (b, self.first)) = #^BROKEN_CONFORMANCE_UNASSIGNABLE_2^# + } + + func foo3() { + var (a, b, c): (Int, Int, Int) + let exact = (1, (2, 4)) + (a, (b, c)) = #^BROKEN_CONFORMANCE_ASSIGNABLE^# + } +} +// BROKEN_CONFORMANCE_UNASSIGNABLE: Begin completions +// BROKEN_CONFORMANCE_UNASSIGNABLE-NOT: TypeRelation +// BROKEN_CONFORMANCE_UNASSIGNABLE: Decl[InstanceMethod]/Super: first()[#MyProto.Element#]; name=first() +// BROKEN_CONFORMANCE_UNASSIGNABLE-NOT: TypeRelation +// BROKEN_CONFORMANCE_UNASSIGNABLE: End completions + +// BROKEN_CONFORMANCE_ASSIGNABLE: Begin completions +// BROKEN_CONFORMANCE_ASSIGNABLE-DAG: Decl[LocalVar]/Local/TypeRelation[Identical]: exact[#(Int, (Int, Int))#]; name=exact +// BROKEN_CONFORMANCE_ASSIGNABLE-DAG: Decl[InstanceVar]/Super/TypeRelation[Identical]: matches[#(Int, (Int, Int))#]; name=matches +// BROKEN_CONFORMANCE_ASSIGNABLE: End completions diff --git a/test/IRGen/polymorphic_builtins.swift b/test/IRGen/polymorphic_builtins.swift new file mode 100644 index 0000000000000..cda952f90b9e0 --- /dev/null +++ b/test/IRGen/polymorphic_builtins.swift @@ -0,0 +1,50 @@ +// This line tests that IRGen is properly turning the unspecialized builtins +// into traps. +// +// RUN: %target-swift-frontend -emit-ir -parse-as-library -parse-stdlib %s | %FileCheck %s + +// Make sure we are not eliminating these builtins before IRGen runs. As part of +// the builtin's contract, we expect IRGen to convert them to traps, not +// anything before. +// +// RUN: %target-swift-frontend -emit-sil -parse-as-library -parse-stdlib %s | %FileCheck --check-prefix=SIL %s + +import Swift + +// SIL-LABEL: sil [transparent] [serialized] @$s20polymorphic_builtins11_isConcrete4typeSbxm_tlF : $@convention(thin) (@thick T.Type) -> Bool { +// SIL: builtin "isConcrete"({{%[0-9]*}} : $@thick T.Type) : $Builtin.Int1 +// SIL: // end sil function '$s20polymorphic_builtins11_isConcrete4typeSbxm_tlF' +@_transparent +public func _isConcrete(type: T.Type) -> Bool { + return Bool(_builtinBooleanLiteral: Builtin.isConcrete(type)) +} + +// SIL-LABEL: sil [transparent] [serialized] @$s20polymorphic_builtins41calleeAddVectorsGenericTransparentGuardedyxx_xtlF : $@convention(thin) (@in_guaranteed T, @in_guaranteed T) -> @out T { +// SIL: builtin "isConcrete"({{%[0-9]*}} : $@thick T.Type) : $Builtin.Int1 +// SIL: builtin "generic_add"( +// SIL: } // end sil function '$s20polymorphic_builtins41calleeAddVectorsGenericTransparentGuardedyxx_xtlF' + +// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc void @"$s20polymorphic_builtins41calleeAddVectorsGenericTransparentGuardedyxx_xtlF"( +// CHECK: br i1 false, label %[[CONCRETE_LABEL:[0-9][0-9]*]], label %[[NON_CONCRETE_LABEL:[0-9][0-9]*]] +// +// CHECK: (A.Type, IntFormat, Bool) -> String +// CHECK-NOT: error: +// CHECK-LABEL: @sizeForEncoding(A.Type) -> Int +// CHECK-NOT: error: +// CHECK-LABEL: @getArgumentHeader(isPrivate: Bool, type: ArgumentType) -> UInt8 +// CHECK-NOT: error: +// CHECK-LABEL: @getUpdatedPreamble(isPrivate: Bool, isScalar: Bool) -> UInt8 +// CHECK-NOT: error: +// CHECK-LABEL: @init(stringInterpolation: OSLogInterpolation) -> OSLogMessage +// CHECK-NOT: error: +@_semantics("test_driver") +func intValueInterpolationTest() -> OSLogMessage { + return "An integer value \(10)" +} + +// CHECK-LABEL: @getStringFormatSpecifier(Bool) -> String +// CHECK-NOT: error: +// CHECK-LABEL: @sizeForEncoding() -> Int +// CHECK-NOT: error: +@_semantics("test_driver") +func stringValueInterpolationTest() -> OSLogMessage { + return "A string value \("xyz")" +} diff --git a/test/SILOptimizer/constant_evaluable_subset_test.swift b/test/SILOptimizer/constant_evaluable_subset_test.swift new file mode 100644 index 0000000000000..a362a82d15aee --- /dev/null +++ b/test/SILOptimizer/constant_evaluable_subset_test.swift @@ -0,0 +1,698 @@ +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend -emit-silgen -primary-file %s -o %t/constant_evaluable_subset_test_silgen.sil +// +// Run the (mandatory) passes on which constant evaluator depends, and test the +// constant evaluator on the SIL produced after the dependent passes are run. +// +// RUN: not %target-sil-opt -silgen-cleanup -raw-sil-inst-lowering -allocbox-to-stack -mandatory-inlining -constexpr-limit 3000 -test-constant-evaluable-subset %t/constant_evaluable_subset_test_silgen.sil > /dev/null 2> %t/error-output +// +// RUN: %FileCheck %s < %t/error-output +// +// Test the constant evaluator on the output of the mandatory pipeline. This is +// to test that constant evaluability is not affected by mandatory +// optimizations. Note that it can be affected by non-mandatory optimizations, +// especially performance inlining as it inlines functions such as String.+= +// that the evaluator has special knowledge about. +// +// RUN: not %target-sil-opt -silgen-cleanup -diagnose-invalid-escaping-captures -diagnose-static-exclusivity -capture-promotion -access-enforcement-selection -allocbox-to-stack -noreturn-folding -mark-uninitialized-fixup -definite-init -raw-sil-inst-lowering -closure-lifetime-fixup -semantic-arc-opts -destroy-hoisting -ownership-model-eliminator -mandatory-inlining -predictable-memaccess-opts -os-log-optimization -diagnostic-constant-propagation -predictable-deadalloc-elim -guaranteed-arc-opts -diagnose-unreachable -diagnose-infinite-recursion -yield-once-check -dataflow-diagnostics -split-non-cond_br-critical-edges -constexpr-limit 3000 -test-constant-evaluable-subset %t/constant_evaluable_subset_test_silgen.sil > /dev/null 2> %t/error-output-mandatory +// +// RUN: %FileCheck %s < %t/error-output-mandatory + +// TODO(TF-799): Re-enable test after SR-11336 is fixed. +// XFAIL: * + +// Test Swift code snippets that are expected to be constant evaluable and those +// that are not. If any of the test here fails, it indicates a change in the +// output of SILGen or the mandatory passes that affects the constant +// evaluability of the corresponding Swift code. + +// CHECK-LABEL: @leftShift +// CHECK-NOT: error: +@_semantics("constant_evaluable") +internal func leftShift(x: Int, y: Int) -> Int { + return x &<< y +} + +// The test driver must only call functions marked as constant evaluable +// with literal arguments. +@_semantics("test_driver") +internal func interpretLeftShiftTest() -> Int { + return leftShift(x: 10, y: 2) +} + +// CHECK-LABEL: @leftShiftWithTraps +// CHECK-NOT: error: +// This is an expensive function to evaluate requiring evaluating approximately +// 1024 instructions. +@_semantics("constant_evaluable") +internal func leftShiftWithTraps(x: Int, y: Int) -> Int { + return x << y +} + +@_semantics("test_driver") +internal func interpretLeftShiftWithTraps() -> Int { + return leftShiftWithTraps(x: 34, y: 3) +} + +// CHECK-LABEL: @rightShift +// CHECK-NOT: error: +@_semantics("constant_evaluable") +internal func rightShift(x: Int, y: Int) -> Int { + return x &>> y +} + +@_semantics("test_driver") +internal func interpretRightShift() -> Int { + return rightShift(x: 10, y: 2) +} + +// CHECK-LABEL: @rightShiftWithTraps +// CHECK-NOT: error: +// This is an expensive function to evaluate requiring evaluating approximately +// 1024 instructions. +@_semantics("constant_evaluable") +internal func rightShiftWithTraps(x: Int, y: Int) -> Int { + return x >> y +} + +@_semantics("test_driver") +internal func interpretRightShiftWithTraps() -> Int { + return rightShiftWithTraps(x: 34, y: 3) +} + +// CHECK-LABEL: @arithmetic +// CHECK-NOT: error: +@_semantics("constant_evaluable") +internal func arithmetic(x: Int, y: Int) -> Int { + let z = x + y + let w = x &+ z + let a = w * y + let b = a &* z + let c = b - a + let d = c &- x + let e = x / d + return e +} + +@_semantics("test_driver") +internal func interpretArithmetic() -> Int { + return arithmetic(x: 142, y: 212) +} + +// CHECK-LABEL: @booleanoperations +// CHECK-NOT: error: +@_semantics("constant_evaluable") +internal func booleanoperations(a: Bool, b: Bool) -> Bool { + return (a && b) || (a || b) && !a +} + +@_semantics("test_driver") +internal func interpretBooleanOperations() -> Bool { + return booleanoperations(a: true, b: false) +} + +// CHECK-LABEL: @comparisons +// CHECK-NOT: error: +@_semantics("constant_evaluable") +internal func comparisons(a: Int, b: Int, c: Int8, d: Int8) -> Bool { + let r1 = a < b + let r2 = c > d + return r1 && r2 +} + +@_semantics("test_driver") +internal func interpretComparisions() -> Bool { + return comparisons(a: 20, b: 55, c: 56, d: 101) +} + +// CHECK-LABEL: @heterogenousIntComparisons +// CHECK-NOT: error: +@_semantics("constant_evaluable") +internal func heterogenousIntComparisons(a: Int, b: Int16, c: Int8) -> Bool { + return (a < b) && (c < b) +} + +@_semantics("test_driver") +internal func interpretHeterogenousComparisons() -> Bool { + return heterogenousIntComparisons(a: 101, b: 20, c: 56) +} + +// CHECK-LABEL: @bitwiseOperations +// CHECK-NOT: error: +@_semantics("constant_evaluable") +internal func bitwiseOperations(a: Int16, b: Int16, c: Int16) -> Int16 { + return a & ((b | c) | ~c) +} + +@_semantics("test_driver") +internal func interpretBitWiseOperations() -> Int16 { + return bitwiseOperations(a: 0xff, b: 0xef, c: 0x7fef) +} + +// CHECK-LABEL: @testIntExtensions +// CHECK-NOT: error: +@_semantics("constant_evaluable") +internal func testIntExtensions(a: Int8, b: Int16) -> Int32 { + return Int32(a) + Int32(b) + Int32(Int16(a)) +} + +@_semantics("test_driver") +internal func interpretIntExtensions() -> Int32 { + return testIntExtensions(a: 100, b: -130) +} + +// CHECK-LABEL: @testUIntExtensions +// CHECK-NOT: error: +@_semantics("constant_evaluable") +internal func testUIntExtensions(a: UInt8, b: UInt16) -> UInt32 { + return UInt32(a) + UInt32(b) + UInt32(UInt16(a)) +} + +@_semantics("test_driver") +internal func interpretUIntExtensions() -> UInt32 { + return testUIntExtensions(a: 100, b: 130) +} + +// CHECK-LABEL: @testIntTruncations +// CHECK-NOT: error: +// This is an expensive function to evaluate requiring evaluating approximately +// 2048 instructions with optimized stdlib and 3000 instructions with +// unoptimized stdlib. +@_semantics("constant_evaluable") +internal func testIntTruncations(a: Int32) -> Int8 { + let b = Int16(a) + let c = Int8(b) + return c +} + +@_semantics("test_driver") +internal func interpretIntTruncations() -> Int8 { + return testIntTruncations(a: 100) +} + +// CHECK-LABEL: @testInvalidIntTruncations +// CHECK: error: not constant evaluable +@_semantics("constant_evaluable") +internal func testInvalidIntTruncations(a: Int32) -> Int8 { + return Int8(a) + // CHECK: note: {{.*}}: Not enough bits to represent the passed value + // CHECK: note: operation performed during this call traps + // CHECK: function_ref @$sSZss17FixedWidthIntegerRzrlEyxqd__cSzRd__lufC +} + +@_semantics("test_driver") +internal func interpretInvalidIntTruncations() -> Int8 { + return testInvalidIntTruncations(a: 130) +} + +// CHECK-LABEL: @testUIntTruncations +// CHECK-NOT: error: +// This is an expensive function to evaluate requiring evaluating approximately +// 2048 instructions. +@_semantics("constant_evaluable") +internal func testUIntTruncations(a: UInt32) -> UInt8 { + let b = UInt32(a) + let c = UInt16(b) + let d = UInt8(c) + return d +} + +@_semantics("test_driver") +internal func interpretUIntTruncations() -> UInt8 { + return testUIntTruncations(a: 100) +} + +// CHECK-LABEL: @testSingedUnsignedConversions +// CHECK-NOT: error: +// This is an expensive function to evaluate requiring evaluating approximately +// 2048 instructions. +@_semantics("constant_evaluable") +internal func testSingedUnsignedConversions(a: Int32, b: UInt8) -> UInt32 { + return UInt32(a) + UInt32(Int8(b)) +} + +@_semantics("test_driver") +internal func interpretSingedUnsignedConversions() -> UInt32 { + return testSingedUnsignedConversions(a: 100, b: 120) +} + +// CHECK-LABEL: @testInvalidSingedUnsignedConversions +// CHECK: error: not constant evaluable +@_semantics("constant_evaluable") +internal func testInvalidSingedUnsignedConversions(a: Int64) -> UInt64 { + return UInt64(a) + // CHECK: note: {{.*}}: Negative value is not representable + // CHECK: note: operation performed during this call traps + // CHECK: function_ref @$sSUss17FixedWidthIntegerRzrlEyxqd__cSzRd__lufC +} + +@_semantics("test_driver") +internal func interpretInvalidSingedUnsignedConversions() -> UInt64 { + return testInvalidSingedUnsignedConversions(a: -130) +} + +// CHECK-LABEL: @testIO +// CHECK: error: not constant evaluable +@_semantics("constant_evaluable") +internal func testIO() -> String? { + return readLine() + // CHECK: note: encountered call to 'Swift.readLine(strippingNewline: Swift.Bool) -> Swift.Optional' whose body is not available + // CHECK: note: function whose body is not available +} + +@_semantics("test_driver") +internal func interpretIO() -> String? { + return testIO() +} + +// CHECK-LABEL: @testLoop +// CHECK: error: not constant evaluable +@_semantics("constant_evaluable") +func testLoop() -> Int { + var x = 0 + while x <= 42 { + x += 1 + } + return x + // CHECK: note: control-flow loop found during evaluation + // CHECK: note: found loop here +} + +@_semantics("test_driver") +internal func interpretLoop() -> Int { + return testLoop() +} + +// CHECK-LABEL: @testRecursion +// CHECK-NOT: error: +@_semantics("constant_evaluable") +func testRecursion(_ a: Int) -> Int { + return a <= 0 ? 0 : testRecursion(a-1) +} + +@_semantics("test_driver") +internal func interpretRecursion() -> Int { + return testRecursion(10) +} + +// CHECK-LABEL: @testLongRecursion +// CHECK: error: not constant evaluable +@_semantics("constant_evaluable") +func testLongRecursion(_ a: Int) -> Int { + return a == 0 ? 0 : testLongRecursion(a-1) + // CHECK: note: exceeded instruction limit: + // CHECK: note: limit exceeded here +} + +@_semantics("test_driver") +internal func interpretLongRecursion() -> Int { + return testLongRecursion(-100) +} + +// CHECK-LABEL: @testConditional +// CHECK-NOT: error: +@_semantics("constant_evaluable") +func testConditional(_ x: Int) -> Int { + if x < 0 { + return 0 + } else { + return x + } +} + +@_semantics("test_driver") +func interpretConditional() -> Int { + testConditional(-1) +} + +// CHECK-LABEL: @testIntAddOverflow +// CHECK: error: not constant evaluable +@_semantics("constant_evaluable") +func testIntAddOverflow(_ x: Int8) -> Int8 { + return x + 1 + // CHECK: note: integer overflow detected + // CHECK: note: operation overflows +} + +@_semantics("test_driver") +func interpretIntAddOverflow() -> Int8 { + return testIntAddOverflow(127) +} + +// CHECK-LABEL: @testDivideByZero +// CHECK: error: not constant evaluable +@_semantics("constant_evaluable") +func testDivideByZero(_ x: Int, _ y: Int) -> Int { + return x / y + // CHECK: note: {{.*}}: Division by zero + // CHECK: note: operation traps +} + +@_semantics("test_driver") +func interpretDivideByZero() -> Int { + return testDivideByZero(127, 0) +} + +// CHECK-LABEL: @testDivideOverflow +// CHECK: error: not constant evaluable +@_semantics("constant_evaluable") +func testDivideOverflow(_ x: Int8, _ y: Int8) -> Int8 { + return x / y + // CHECK: note: {{.*}}: Division results in an overflow + // CHECK: note: operation traps +} + +@_semantics("test_driver") +func interpretDivideOverflow() -> Int8 { + return testDivideOverflow(-128, -1) +} + +// CHECK-LABEL: @testInOut +// CHECK-NOT: error: +@_semantics("constant_evaluable") +func testInOut(_ x: inout Int) { + x += 1 +} + +@_semantics("test_driver") +func interpretInOut() -> Int { + var x = 10 + testInOut(&x) + return x +} + +struct A { + var x, y: Int + + // CHECK-LABEL: @init(initialValue: Int) -> A + // CHECK-NOT: error: + @_semantics("constant_evaluable") + init(initialValue: Int) { + x = initialValue + y = initialValue + } + + // CHECK-LABEL: @sum + // CHECK-NOT: error: + @_semantics("constant_evaluable") + @_optimize(none) + func sum() -> Int { + return x + y + } + + // CHECK-LABEL: @increment + // CHECK-NOT: error: + @_semantics("constant_evaluable") + @_optimize(none) + mutating func increment(by step: Int) { + x += step + y += step + } +} + +@_semantics("test_driver") +func interpretStructInitAndMethods() -> A { + var a = A(initialValue: 0) + let z = a.sum(); + a.increment(by: z) + return a +} + +struct OuterStruct { + var inner: A + var z: Int + + // CHECK-LABEL: @sumInner + // CHECK-NOT: error: + @_semantics("constant_evaluable") + @_optimize(none) + func sumInner() -> Int { + return inner.sum() + } +} + +@_semantics("test_driver") +func interpretNestedStructAndDefaultInit() -> Int { + let ostruct = OuterStruct(inner: A(initialValue: 1), z: 10) + return ostruct.sumInner() +} + +struct EmptyStruct { + func get() -> Int { + return 0 + } +} + +// CHECK-LABEL: @testEmptyStruct +// CHECK-NOT: error: +@_semantics("constant_evaluable") +func testEmptyStruct() -> Int { + let emp = EmptyStruct() + return emp.get() +} + +@_semantics("test_driver") +func interpretEmptyStructTest() -> Int { + return testEmptyStruct() +} + +// CHECK-LABEL: @testTuple +// CHECK-NOT: error: +@_semantics("constant_evaluable") +func testTuple(_ a: Int, _ b: Bool) -> Bool { + func extractSecond(_ tuple: (Int, Bool)) -> Bool { + return tuple.1 + } + return extractSecond((a, b)) +} + +@_semantics("test_driver") +func interpretTuple() -> Bool { + return testTuple(10, false) +} + +// CHECK-LABEL: @testGenericFunction +// CHECK-NOT: error: +@_semantics("constant_evaluable") +func testGenericFunction(_ a: T, _ b: T) -> Bool { + return a == b +} + +@_semantics("test_driver") +func interpretGenericFunction() -> Bool { + return testGenericFunction(10, 11) +} + +protocol P { + mutating func clear() -> Int +} + +struct PImpl: P { + var i = 100 + mutating func clear() -> Int { + let prev = i + i = 0 + return prev + } +} + +// CHECK-LABEL: @testCustomGenericConstraint +// CHECK-NOT: error: +@_semantics("constant_evaluable") +func testCustomGenericConstraint(_ a: inout T) -> Int { + return a.clear() +} + +@_semantics("test_driver") +func interpretCustomGenericConstraint() -> Int { + var s = PImpl(); + return testCustomGenericConstraint(&s) +} + +// CHECK-LABEL: @testProtocolMethodDispatch +// CHECK: error: not constant evaluable +@_semantics("constant_evaluable") +func testProtocolMethodDispatch(_ s: PImpl) -> Int { + func innerFunc(_ proto: P) -> Int { + var tmp = proto + return tmp.clear() + } + return innerFunc(s) + // CHECK: note: encountered operation not supported by the evaluator: init_existential_addr + // CHECK: note: operation not supported by the evaluator +} + +@_semantics("test_driver") +func interpretProtocolMethodDispatch() -> Int { + return testProtocolMethodDispatch(PImpl()) +} + +struct SGeneric { + var x: X + var y: Y + + // CHECK-LABEL: @methodWithGeneric + // CHECK-NOT: error: + @_semantics("constant_evaluable") + @_optimize(none) + func methodWithGeneric(_ z: Z) -> SGeneric { + return SGeneric(x: z, y: y) + } +} + +@_semantics("test_driver") +func interpretStructAndMethodWithGeneric() -> SGeneric { + let s = SGeneric(x: 10, y: true) + return s.methodWithGeneric(240) +} + +protocol ProtoWithInit { + init(_ x: Int) +} + +struct C : ProtoWithInit { + init(_ x: Int) { + } +} + +// CHECK-LABEL: @testGenericConstruction +// CHECK-NOT: error: +@_semantics("constant_evaluable") +func testGenericConstruction(_: T.Type) -> T { + return T(0) +} + +@_semantics("test_driver") +func interpretGenericConstruction() -> C { + return testGenericConstruction(C.self) +} + +// CHECK-LABEL: @testSupportedStringOperations +// CHECK-NOT: error: +@_semantics("constant_evaluable") +func testSupportedStringOperations(_ x: String, _ y: String) -> Bool { + var z = x + z += y + return z == x +} + +@_semantics("test_driver") +func interpretSupportedStringOperations() -> Bool { + return testSupportedStringOperations("abc", "zyx") +} + +// CHECK-LABEL: @testOptional +// CHECK-NOT: error: +@_semantics("constant_evaluable") +func testOptional(_ xopt: String?) -> String { + if let x = xopt { + return x + } + return "" +} + +@_semantics("test_driver") +func interpretOptionalTest() -> String { + return testOptional("a") +} + +enum Side { + case right + case left +} + +// CHECK-LABEL: @testEnumSwitch +// CHECK-NOT: error: +@_semantics("constant_evaluable") +func testEnumSwitch(_ side: Side) -> Int { + switch side { + case .right: + return 1 + case .left: + return 0 + } +} + +@_semantics("test_driver") +func interpretEnumSwitch() -> Int { + return testEnumSwitch(.right) +} + +// CHECK-LABEL: @testEnumEquality +// CHECK-NOT: error: +@_semantics("constant_evaluable") +func testEnumEquality(_ side: Side, _ otherSide: Side) -> Bool { + return side == otherSide +} + +@_semantics("test_driver") +func interpretEnumEquality() -> Bool { + return testEnumEquality(.right, .left) +} + +enum Shape { + case circle(radius: Int) + case rectangle(length: Int, breadth: Int) +} + +// CHECK-LABEL: @testEnumWithData +// CHECK-NOT: error: +@_semantics("constant_evaluable") +func testEnumWithData(_ shape: Shape) -> Int { + switch shape { + case .circle(radius: let x): + return x + case .rectangle(length: let x, breadth: let y): + return x + y + } +} + +@_semantics("test_driver") +func interpretEnumWithData() -> Int { + return testEnumWithData(.circle(radius: 11)) +} + +enum Number { + case integer(T) + case rational(T, T) +} + +// CHECK-LABEL: @testAddressOnlyEnum +// CHECK-NOT: error: +@_semantics("constant_evaluable") +func testAddressOnlyEnum(_ number: Number) -> T { + switch number { + case .integer(let x): + return x + case .rational(let x, let y): + return x + y + } +} + +@_semantics("test_driver") +func interpretAddressOnlyEnum() -> Int { + return testAddressOnlyEnum(.rational(22, 7)) +} + +indirect enum Nat { + case zero + case succ(Nat) +} + +// CHECK-LABEL: @testIndirectEnum +// CHECK: error: not constant evaluable +@_semantics("constant_evaluable") +func testIndirectEnum(_ nat: Nat) -> Bool { + switch nat { + case .zero: + return true + case .succ: + return false + } + // CHECK-NOTE: note: encountered operation not supported by the evaluator: alloc_box +} + +@_semantics("test_driver") +func interpretIndirectEnum() -> Bool { + return testIndirectEnum(.succ(.zero)) +} diff --git a/test/SILOptimizer/constant_evaluable_subset_test_arch32.swift b/test/SILOptimizer/constant_evaluable_subset_test_arch32.swift new file mode 100644 index 0000000000000..cd8ab82a59aaa --- /dev/null +++ b/test/SILOptimizer/constant_evaluable_subset_test_arch32.swift @@ -0,0 +1,102 @@ +// REQUIRES: PTRSIZE=32 +// +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend -emit-silgen -primary-file %s -o %t/constant_evaluable_subset_test_arch32_silgen.sil +// +// Run the (mandatory) passes on which constant evaluator depends, and test the +// constant evaluator on the SIL produced after the dependent passes are run. +// +// RUN: not %target-sil-opt -silgen-cleanup -raw-sil-inst-lowering -allocbox-to-stack -mandatory-inlining -constexpr-limit 3000 -test-constant-evaluable-subset %t/constant_evaluable_subset_test_arch32_silgen.sil > /dev/null 2> %t/error-output +// +// RUN: %FileCheck %s < %t/error-output + +// Test Swift code snippets that are expected to be constant evaluable and those +// that are not. If any of the test here fails, it indicates a change in the +// output of SILGen or the mandatory passes that affects the constant +// evaluability of the corresponding Swift code. The tests here are specific +// to 32bit architecture. + +// Unfortunately, on 32bit architectures the following operations are not +// constant evaluable, as it requires supporting co-routines in the evaluator. +// They are however constant evaluable on 64bit architectures. This difference +// arises because in 32bit architecture Int64 occupies multiple words and +// the following operations involves iterating through the words in Int64. This +// causes the interpreted code to change between 64bit and 32bit architectures. + +// CHECK-LABEL: @testIntExtensions +// CHECK: error: not constant evaluable +// CHECK: note: encountered operation not supported by the evaluator: begin_apply +@_semantics("constant_evaluable") +internal func testIntExtensions(a: Int8, b: Int16, c: Int32) -> Int64 { + return Int64(a) + Int64(b) + Int64(c) +} + +@_semantics("test_driver") +internal func interpretIntExtensions() -> Int64 { + return testIntExtensions(a: 100, b: -130, c: -50000) +} + +// CHECK-LABEL: @testUIntExtensions +// CHECK: error: not constant evaluable +// CHECK: note: encountered operation not supported by the evaluator: begin_apply +@_semantics("constant_evaluable") +internal func testUIntExtensions(a: UInt8, b: UInt16, c: UInt32) -> UInt64 { + return UInt64(a) + UInt64(b) + UInt64(c) +} + +@_semantics("test_driver") +internal func interpretUIntExtensions() -> UInt64 { + return testUIntExtensions(a: 100, b: 130, c: 0xffffffff) +} + +// CHECK-LABEL: @testIntTruncations +// CHECK: error: not constant evaluable +// CHECK: note: encountered operation not supported by the evaluator: begin_apply +@_semantics("constant_evaluable") +internal func testIntTruncations(a: Int64) -> Int16 { + return Int16(a) +} + +@_semantics("test_driver") +internal func interpretIntTruncations() -> Int16 { + return testIntTruncations(a: 100) +} + +// CHECK-LABEL: @testInvalidIntTruncations +// CHECK: error: not constant evaluable +// CHECK: note: encountered operation not supported by the evaluator: begin_apply +@_semantics("constant_evaluable") +internal func testInvalidIntTruncations(a: Int64) -> Int8 { + return Int8(a) +} + +@_semantics("test_driver") +internal func interpretInvalidIntTruncations() -> Int8 { + return testInvalidIntTruncations(a: 130) +} + +// CHECK-LABEL: @testUIntTruncations +// CHECK: error: not constant evaluable +// CHECK: note: encountered operation not supported by the evaluator: begin_apply +@_semantics("constant_evaluable") +internal func testUIntTruncations(a: UInt64) -> UInt16 { + return UInt16(a) +} + +@_semantics("test_driver") +internal func interpretUIntTruncations() -> UInt16 { + return testUIntTruncations(a: 100) +} + +// CHECK-LABEL: @testSingedUnsignedConversions +// CHECK: error: not constant evaluable +// CHECK: note: encountered operation not supported by the evaluator: begin_apply +@_semantics("constant_evaluable") +internal func testSingedUnsignedConversions(a: Int64, b: UInt8) -> UInt64 { + return UInt64(a) + UInt64(Int8(b)) +} + +@_semantics("test_driver") +internal func interpretSingedUnsignedConversions() -> UInt64 { + return testSingedUnsignedConversions(a: 100, b: 120) +} diff --git a/test/SILOptimizer/constant_evaluable_subset_test_arch64.swift b/test/SILOptimizer/constant_evaluable_subset_test_arch64.swift new file mode 100644 index 0000000000000..917074e565744 --- /dev/null +++ b/test/SILOptimizer/constant_evaluable_subset_test_arch64.swift @@ -0,0 +1,109 @@ +// REQUIRES: PTRSIZE=64 +// +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend -emit-silgen -primary-file %s -o %t/constant_evaluable_subset_test_arch64_silgen.sil +// +// Run the (mandatory) passes on which constant evaluator depends, and test the +// constant evaluator on the SIL produced after the dependent passes are run. +// +// RUN: not %target-sil-opt -silgen-cleanup -raw-sil-inst-lowering -allocbox-to-stack -mandatory-inlining -constexpr-limit 3000 -test-constant-evaluable-subset %t/constant_evaluable_subset_test_arch64_silgen.sil > /dev/null 2> %t/error-output +// +// RUN: %FileCheck %s < %t/error-output +// +// Test the constant evaluator on the output of the mandatory pipeline. This is +// to test that constant evaluability is not affected by mandatory +// optimizations. Note that it can be affected by non-mandatory optimizations, +// especially performance inlining as it inlines functions such as String.+= +// that the evaluator has special knowledge about. +// +// RUN: not %target-sil-opt -silgen-cleanup -diagnose-invalid-escaping-captures -diagnose-static-exclusivity -capture-promotion -access-enforcement-selection -allocbox-to-stack -noreturn-folding -mark-uninitialized-fixup -definite-init -raw-sil-inst-lowering -closure-lifetime-fixup -semantic-arc-opts -destroy-hoisting -ownership-model-eliminator -mandatory-inlining -predictable-memaccess-opts -os-log-optimization -diagnostic-constant-propagation -predictable-deadalloc-elim -guaranteed-arc-opts -diagnose-unreachable -diagnose-infinite-recursion -yield-once-check -dataflow-diagnostics -split-non-cond_br-critical-edges -constexpr-limit 3000 -test-constant-evaluable-subset %t/constant_evaluable_subset_test_arch64_silgen.sil > /dev/null 2> %t/error-output-mandatory +// +// RUN: %FileCheck %s < %t/error-output-mandatory + +// Test Swift code snippets that are expected to be constant evaluable and those +// that are not. If any of the test here fails, it indicates a change in the +// output of SILGen or the mandatory passes that affects the constant +// evaluability of the corresponding Swift code. The tests here are specific +// to 64bit architecture. + +// CHECK-LABEL: @testIntExtensions +// CHECK-NOT: error: +@_semantics("constant_evaluable") +internal func testIntExtensions(a: Int8, b: Int16, c: Int32) -> Int64 { + return Int64(a) + Int64(b) + Int64(c) +} + +@_semantics("test_driver") +internal func interpretIntExtensions() -> Int64 { + return testIntExtensions(a: 100, b: -130, c: -50000) +} + +// CHECK-LABEL: @testUIntExtensions +// CHECK-NOT: error: +@_semantics("constant_evaluable") +internal func testUIntExtensions(a: UInt8, b: UInt16, c: UInt32) -> UInt64 { + return UInt64(a) + UInt64(b) + UInt64(c) +} + +@_semantics("test_driver") +internal func interpretUIntExtensions() -> UInt64 { + return testUIntExtensions(a: 100, b: 130, c: 0xffffffff) +} + +// CHECK-LABEL: @testIntTruncations +// CHECK-NOT: error: +// This is an expensive function to evaluate requiring evaluating approximately +// 2048 instructions with optimized stdlib and 3000 instructions with +// unoptimized stdlib. +@_semantics("constant_evaluable") +internal func testIntTruncations(a: Int64) -> Int16 { + return Int16(a) +} + +@_semantics("test_driver") +internal func interpretIntTruncations() -> Int16 { + return testIntTruncations(a: 100) +} + +// CHECK-LABEL: @testInvalidIntTruncations +// CHECK: error: not constant evaluable +@_semantics("constant_evaluable") +internal func testInvalidIntTruncations(a: Int64) -> Int8 { + return Int8(a) + // CHECK: note: {{.*}} Not enough bits to represent the passed value + // CHECK: note: operation performed during this call traps + // CHECK: function_ref @$sSZss17FixedWidthIntegerRzrlEyxqd__cSzRd__lufC +} + +@_semantics("test_driver") +internal func interpretInvalidIntTruncations() -> Int8 { + return testInvalidIntTruncations(a: 130) +} + +// CHECK-LABEL: @testUIntTruncations +// CHECK-NOT: error: +// This is an expensive function to evaluate requiring evaluating approximately +// 2048 instructions. +@_semantics("constant_evaluable") +internal func testUIntTruncations(a: UInt64) -> UInt16 { + return UInt16(a) +} + +@_semantics("test_driver") +internal func interpretUIntTruncations() -> UInt16 { + return testUIntTruncations(a: 100) +} + +// CHECK-LABEL: @testSingedUnsignedConversions +// CHECK-NOT: error: +// This is an expensive function to evaluate requiring evaluating approximately +// 2048 instructions. +@_semantics("constant_evaluable") +internal func testSingedUnsignedConversions(a: Int64, b: UInt8) -> UInt64 { + return UInt64(a) + UInt64(Int8(b)) +} + +@_semantics("test_driver") +internal func interpretSingedUnsignedConversions() -> UInt64 { + return testSingedUnsignedConversions(a: 100, b: 120) +} diff --git a/test/SILOptimizer/constant_evaluator_test.sil b/test/SILOptimizer/constant_evaluator_test.sil index c29f14b8d8f2f..2a3ce9566412b 100644 --- a/test/SILOptimizer/constant_evaluator_test.sil +++ b/test/SILOptimizer/constant_evaluator_test.sil @@ -279,7 +279,7 @@ bb0: %0 = integer_literal $Builtin.Int64, -5 %2 = function_ref @factorial : $@convention(thin) (Builtin.Int64) -> Builtin.Int64 %3 = apply %2(%0) : $@convention(thin) (Builtin.Int64) -> Builtin.Int64 - // CHECK: {{.*}}:[[@LINE-1]]:{{.*}}: note: exceeded instruction limit: 512 when evaluating the expression at compile time + // CHECK: {{.*}}:[[@LINE-1]]:{{.*}}: note: exceeded instruction limit: {{.*}} when evaluating the expression at compile time // CHECK: {{.*}}: note: limit exceeded here return %3 : $Builtin.Int64 } @@ -464,7 +464,7 @@ bb0: // function_ref readLine(strippingNewline:) %2 = function_ref @$ss8readLine16strippingNewlineSSSgSb_tF : $@convention(thin) (Bool) -> @owned Optional %3 = apply %2(%1) : $@convention(thin) (Bool) -> @owned Optional - // CHECK: {{.*}}:[[@LINE-1]]:{{.*}}: note: encountered call to a function whose body is not available + // CHECK: {{.*}}:[[@LINE-1]]:{{.*}}: note: encountered call to 'Swift.readLine(strippingNewline: Swift.Bool) -> Swift.Optional' whose body is not available release_value %3 : $Optional %5 = tuple () return %5 : $() @@ -1152,3 +1152,64 @@ bb0: cond_fail %19 : $Builtin.Int1 return %18 : $Builtin.Int64 } // CHECK: Returns int: 36 + +// Tests for builtin "ptrtoint_Word", which is supported only for string +// constants in order to handle 'StaticString' construction. + +// CHECK-LABEL: @interpretPtrToInt +sil @interpretPtrToInt : $@convention(thin) () -> Builtin.Word { + %0 = string_literal utf8 "Fatal error" + %1 = builtin "ptrtoint_Word"(%0 : $Builtin.RawPointer) : $Builtin.Word + return %1 : $Builtin.Word +} // CHECK: Returns string: "Fatal error" + +// CHECK-LABEL: @interpretStaticStringInit +sil @interpretStaticStringInit : $@convention(thin) () -> Builtin.Word { + %0 = string_literal utf8 "static error message" + %1 = integer_literal $Builtin.Word, 11 + %2 = builtin "ptrtoint_Word"(%0 : $Builtin.RawPointer) : $Builtin.Word + %3 = integer_literal $Builtin.Int8, 2 + %4 = struct $StaticString (%2 : $Builtin.Word, %1 : $Builtin.Word, %3 : $Builtin.Int8) + %5 = struct_extract %4 : $StaticString, #StaticString._startPtrOrData + return %5 : $Builtin.Word +} // CHECK: Returns string: "static error message" + +// Tests for builtin "assert_configuration". Constant evaluator evaluates this +// builtin to 0, meaning that the the configuration is "debug". + +// CHECK-LABEL: @interpretAssertConfiguration +sil @interpretAssertConfiguration : $@convention(thin) () -> Builtin.Int32 { + %0 = builtin "assert_configuration"() : $Builtin.Int32 + return %0 : $Builtin.Int32 +} // CHECK: Returns int: 0 + +// Tests for "assertionFailure" stdlib functions. Such functions have the +// @_semantics attribute: "programtermination_point" + +sil [noinline] [_semantics "programtermination_point"] [canonical] @$assertionFailure : $@convention(thin) (StaticString, StaticString, UInt64) -> Never + +// CHECK-LABEL: @interpretAssertionFailure +sil @interpretAssertionFailure : $@convention(thin) () -> Never { + // Construct error prefix. + %0 = string_literal utf8 "error-prefix" + %1 = integer_literal $Builtin.Word, 12 + %2 = builtin "ptrtoint_Word"(%0 : $Builtin.RawPointer) : $Builtin.Word + %3 = integer_literal $Builtin.Int8, 2 + %4 = struct $StaticString (%2 : $Builtin.Word, %1 : $Builtin.Word, %3 : $Builtin.Int8) + + // Construct error message. + %10 = string_literal utf8 "message" + %11 = integer_literal $Builtin.Word, 7 + %12 = builtin "ptrtoint_Word"(%10 : $Builtin.RawPointer) : $Builtin.Word + %13 = integer_literal $Builtin.Int8, 2 + %14 = struct $StaticString (%12 : $Builtin.Word, %11 : $Builtin.Word, %13 : $Builtin.Int8) + + // Construct line number. + %20 = integer_literal $Builtin.Int64, 1208 + %21 = struct $UInt64 (%20 : $Builtin.Int64) + + %22 = function_ref @$assertionFailure : $@convention(thin) (StaticString, StaticString, UInt64) -> Never + %23 = apply %22(%4, %14, %21) : $@convention(thin) (StaticString, StaticString, UInt64) -> Never + // CHECK: {{.*}}:[[@LINE-1]]:{{.*}}: note: error-prefix: message + unreachable +} diff --git a/test/SILOptimizer/polymorphic_builtins.sil b/test/SILOptimizer/polymorphic_builtins.sil new file mode 100644 index 0000000000000..6b42ca9dbb6cf --- /dev/null +++ b/test/SILOptimizer/polymorphic_builtins.sil @@ -0,0 +1,54 @@ +// RUN: %target-sil-opt -module-name Swift -diagnostic-constant-propagation %s | %FileCheck %s + +sil_stage raw + +import Builtin + +struct MyInt { + var i : Builtin.Int32 +} + +// CHECK-LABEL: sil @concrete_type_object_test : $@convention(thin) (Builtin.Vec4xInt32, Builtin.Vec4xInt32) -> Builtin.Vec4xInt32 { +// CHECK: builtin "add_Vec4xInt32"( +// CHECK: return +// CHECK: } // end sil function 'concrete_type_object_test' +sil @concrete_type_object_test : $@convention(thin) (Builtin.Vec4xInt32, Builtin.Vec4xInt32) -> Builtin.Vec4xInt32 { +bb0(%0 : $Builtin.Vec4xInt32, %1 : $Builtin.Vec4xInt32): + %2 = builtin "generic_add"(%0 : $Builtin.Vec4xInt32, %1 : $Builtin.Vec4xInt32) : $Builtin.Vec4xInt32 + return %2 : $Builtin.Vec4xInt32 +} + +// CHECK-LABEL: sil @concrete_type_address_test : $@convention(thin) (@in_guaranteed Builtin.Vec4xInt32, @in_guaranteed Builtin.Vec4xInt32) -> @out Builtin.Vec4xInt32 { +// CHECK: bb0([[RESULT:%.*]] : $*Builtin.Vec4xInt32, [[ARG0:%.*]] : $*Builtin.Vec4xInt32, [[ARG1:%.*]] : $*Builtin.Vec4xInt32): +// CHECK: [[LOADED_ARG0:%.*]] = load [[ARG0]] +// CHECK: [[LOADED_ARG1:%.*]] = load [[ARG1]] +// CHECK: [[LOADED_RESULT:%.*]] = builtin "add_Vec4xInt32"([[LOADED_ARG0]] : $Builtin.Vec4xInt32, [[LOADED_ARG1]] : $Builtin.Vec4xInt32) : $Builtin.Vec4xInt32 +// CHECK: store [[LOADED_RESULT]] to [[RESULT]] +// CHECK: } // end sil function 'concrete_type_address_test' +sil @concrete_type_address_test : $@convention(thin) (@in_guaranteed Builtin.Vec4xInt32, @in_guaranteed Builtin.Vec4xInt32) -> @out Builtin.Vec4xInt32 { +bb0(%0 : $*Builtin.Vec4xInt32, %1 : $*Builtin.Vec4xInt32, %2 : $*Builtin.Vec4xInt32): + builtin "generic_add"(%0 : $*Builtin.Vec4xInt32, %1 : $*Builtin.Vec4xInt32, %2 : $*Builtin.Vec4xInt32) : $() + %9999 = tuple() + return %9999 : $() +} + +// CHECK-LABEL: sil @concrete_type_object_fail : $@convention(thin) (MyInt, MyInt) -> MyInt { +// CHECK: builtin "generic_add"( +// CHECK: return +// CHECK: } // end sil function 'concrete_type_object_fail' +sil @concrete_type_object_fail : $@convention(thin) (MyInt, MyInt) -> MyInt { +bb0(%0 : $MyInt, %1 : $MyInt): + %2 = builtin "generic_add"(%0 : $MyInt, %1 : $MyInt) : $MyInt + return %2 : $MyInt +} + +// CHECK-LABEL: sil @concrete_type_address_fail : $@convention(thin) (@in_guaranteed MyInt, @in_guaranteed MyInt) -> @out MyInt { +// CHECK: builtin "generic_add"( +// CHECK: return +// CHECK: } // end sil function 'concrete_type_address_fail' +sil @concrete_type_address_fail : $@convention(thin) (@in_guaranteed MyInt, @in_guaranteed MyInt) -> @out MyInt { +bb0(%0 : $*MyInt, %1 : $*MyInt, %2 : $*MyInt): + %3 = builtin "generic_add"(%0 : $*MyInt, %1 : $*MyInt, %2 : $*MyInt) : $() + %9999 = tuple() + return %9999 : $() +} diff --git a/test/SILOptimizer/polymorphic_builtins_diagnostics.sil b/test/SILOptimizer/polymorphic_builtins_diagnostics.sil new file mode 100644 index 0000000000000..3af92adaf7876 --- /dev/null +++ b/test/SILOptimizer/polymorphic_builtins_diagnostics.sil @@ -0,0 +1,29 @@ +// RUN: %target-sil-opt -module-name Swift -dataflow-diagnostics -verify %s + +sil_stage raw + +import Builtin + +struct MyInt { + var i : Builtin.Int32 +} + +sil @concrete_type_object_fail : $@convention(thin) (MyInt, MyInt) -> MyInt { +bb0(%0 : $MyInt, %1 : $MyInt): + %2 = builtin "generic_add"(%0 : $MyInt, %1 : $MyInt) : $MyInt // expected-error {{Argument of type 'MyInt' can not be passed as an argument to a Polymorphic builtin. Polymorphic builtins can only be passed arguments that are trivial builtin typed}} + return %2 : $MyInt +} + +sil @concrete_type_address_fail : $@convention(thin) (@in_guaranteed MyInt, @in_guaranteed MyInt) -> @out MyInt { +bb0(%0 : $*MyInt, %1 : $*MyInt, %2 : $*MyInt): + %3 = builtin "generic_add"(%0 : $*MyInt, %1 : $*MyInt, %2 : $*MyInt) : $() // expected-error {{Argument of type 'MyInt' can not be passed as an argument to a Polymorphic builtin. Polymorphic builtins can only be passed arguments that are trivial builtin typed}} + %9999 = tuple() + return %9999 : $() +} + +sil @concrete_type_address_fail_mismatched_trivial_type : $@convention(thin) (@in_guaranteed Builtin.FPIEEE32, @in_guaranteed Builtin.FPIEEE32) -> @out Builtin.FPIEEE32 { +bb0(%0 : $*Builtin.FPIEEE32, %1 : $*Builtin.FPIEEE32, %2 : $*Builtin.FPIEEE32): + %3 = builtin "generic_add"(%0 : $*Builtin.FPIEEE32, %1 : $*Builtin.FPIEEE32, %2 : $*Builtin.FPIEEE32) : $() // expected-error {{Static overload 'add_FPIEEE32' does not exist for polymorphic builtin 'generic_add'. Static overload implied by passing argument of type 'Builtin.FPIEEE32'}} + %9999 = tuple() + return %9999 : $() +} diff --git a/test/SILOptimizer/polymorphic_builtins_diagnostics.swift b/test/SILOptimizer/polymorphic_builtins_diagnostics.swift new file mode 100644 index 0000000000000..868432eb25182 --- /dev/null +++ b/test/SILOptimizer/polymorphic_builtins_diagnostics.swift @@ -0,0 +1,53 @@ +// RUN: %target-swift-frontend -parse-stdlib -emit-sil -verify %s + +import Swift + +struct MyInt { + var i: Builtin.Int64 +} + +@_transparent +func _isConcrete(type: T.Type) -> Bool { + return Bool(_builtinBooleanLiteral: Builtin.isConcrete(type)) +} + +func addVectorsNoDiagnostic(lhs: Builtin.Vec4xInt32, rhs: Builtin.Vec4xInt32) -> Builtin.Vec4xInt32 { + return Builtin.generic_add(lhs, rhs) +} + +func addVectorsEmitDiagnostic(lhs: MyInt, rhs: MyInt) -> MyInt { + return Builtin.generic_add(lhs, rhs) // expected-error {{Argument of type 'MyInt' can not be passed as an argument to a Polymorphic builtin. Polymorphic builtins can only be passed arguments that are trivial builtin typed}} +} + +func addVectorsGeneric(lhs: T, rhs: T) -> T { + return Builtin.generic_add(lhs, rhs) // expected-error {{Argument of type 'T' can not be passed as an argument to a Polymorphic builtin. Polymorphic builtins can only be passed arguments that are trivial builtin typed}} +} + +@_transparent +func calleeAddVectorsGenericTransparentGuarded(_ lhs: T, _ rhs: T) -> T { + // This will be eliminated during constant propagation ensuring that when we + // call in callerAddVectorsGenericTransparent, we do not get an error from our + // underlying call. + if _isConcrete(T.self) { + return Builtin.generic_add(lhs, rhs) + } + return lhs +} + +func callerAddVectorsGenericTransparent(_ lhs: Builtin.Vec4xInt32, _ rhs: Builtin.Vec4xInt32) -> Builtin.Vec4xInt32 { + // Since after transparent inlining, we have the correct type, we should get an error here.q + return calleeAddVectorsGenericTransparentGuarded(lhs, rhs) +} + +@_transparent +func calleeAddVectorsGenericTransparentUnguarded(_ lhs: T, _ rhs: T) -> T { + return Builtin.generic_add(lhs, rhs) +} + +func callerAddVectorsGenericTransparentUnguardedNoError(_ lhs: Builtin.Vec4xInt32, _ rhs: Builtin.Vec4xInt32) -> Builtin.Vec4xInt32 { + return calleeAddVectorsGenericTransparentUnguarded(lhs, rhs) +} + +func callerAddVectorsGenericTransparentUnguardedError(_ lhs: MyInt, _ rhs: MyInt) -> MyInt { + return calleeAddVectorsGenericTransparentUnguarded(lhs, rhs) // expected-error {{Argument of type 'MyInt' can not be passed as an argument to a Polymorphic builtin. Polymorphic builtins can only be passed arguments that are trivial builtin typed}} +} diff --git a/test/SILOptimizer/pound_assert.swift b/test/SILOptimizer/pound_assert.swift index 49115a24885f0..0aa8785321745 100644 --- a/test/SILOptimizer/pound_assert.swift +++ b/test/SILOptimizer/pound_assert.swift @@ -2,8 +2,6 @@ // SWIFT_ENABLE_TENSORFLOW // TODO(TF-799): Re-enable RUN line after SR-11336 is fixed. // UN: %target-swift-frontend -enable-experimental-static-assert -enable-ownership-stripping-after-serialization -emit-sil %s -verify - -// REQUIRES: optimized_stdlib // REQUIRES: asserts //===----------------------------------------------------------------------===// @@ -41,7 +39,6 @@ func loops1(a: Int) -> Int { func loops2(a: Int) -> Int { var x = 42 - // expected-note @+1 {{operation not supported by the evaluator}} for i in 0 ... a { x += i } diff --git a/test/SILOptimizer/pound_assert_test_recursive.swift b/test/SILOptimizer/pound_assert_test_recursive.swift index 8f99385be1300..e62ef5fceefc0 100644 --- a/test/SILOptimizer/pound_assert_test_recursive.swift +++ b/test/SILOptimizer/pound_assert_test_recursive.swift @@ -10,7 +10,7 @@ // match what we actually want. // CHECK: error: #assert condition not constant -// CHECK: note: exceeded instruction limit: 512 when evaluating the expression at compile time +// CHECK: note: exceeded instruction limit: {{.*}} when evaluating the expression at compile time // CHECK: limit exceeded here func recursive(a: Int) -> Int { return a == 0 ? 0 : recursive(a: a-1) diff --git a/test/SILOptimizer/simplify_cfg.sil b/test/SILOptimizer/simplify_cfg.sil index 8573a3dd2633a..027811125ccf3 100644 --- a/test/SILOptimizer/simplify_cfg.sil +++ b/test/SILOptimizer/simplify_cfg.sil @@ -1425,24 +1425,24 @@ bb6(%r : $Int32): // CHECK: bb0: // CHECK-NEXT: cond_br undef, bb1, bb2 // CHECK: bb1: -// CHECK-NEXT: cond_br undef, bb3, bb4 +// CHECK: enum $Optional, #Optional.none!enumelt +// CHECK: br bb3 // CHECK: bb2: +// CHECK: integer_literal $Builtin.Int32, 0 +// CHECK: enum $Optional, #Optional.some!enumelt.1 +// CHECK: br bb3 +// CHECK: bb3 // CHECK: integer_literal {{.*}}, 27 -// CHECK: br bb5 -// CHECK: bb3: -// CHECK: br bb4 -// CHECK: bb4: // CHECK: integer_literal {{.*}}, 28 -// CHECK: br bb5 -// CHECK: bb5({{.*}}): -// CHECK-NEXT: return +// CHECK: return sil @jumpthread_switch_enum4 : $@convention(thin) () -> Builtin.Int32 { bb0: + %c0 = builtin "assert_configuration"() : $Builtin.Int32 cond_br undef, bb1, bb2 bb1: %4 = enum $Optional, #Optional.none!enumelt - cond_br undef, bb3(%4 : $Optional), bb4(%4 : $Optional) + cond_br undef, bb3(%4 : $Optional), bb4(%4 : $Optional, %c0 : $Builtin.Int32) bb2: %6 = integer_literal $Builtin.Int32, 0 @@ -1454,23 +1454,22 @@ bb2: bb3(%10 : $Optional): // Some instruction which is not "trivial" %c1 = builtin "assert_configuration"() : $Builtin.Int32 - br bb4(%10 : $Optional) - + br bb4(%10 : $Optional, %c1 : $Builtin.Int32) -bb4(%13 : $Optional): +bb4(%13 : $Optional, %carg1 : $Builtin.Int32): switch_enum %13 : $Optional, case #Optional.some!enumelt.1: bb5, case #Optional.none!enumelt: bb6 bb5: %r1 = integer_literal $Builtin.Int32, 27 %c2 = builtin "assert_configuration"() : $Builtin.Int32 - br bb7(%r1 : $Builtin.Int32) + br bb7(%r1 : $Builtin.Int32, %c2 : $Builtin.Int32) bb6: %r2 = integer_literal $Builtin.Int32, 28 %c3 = builtin "assert_configuration"() : $Builtin.Int32 - br bb7(%r2 : $Builtin.Int32) + br bb7(%r2 : $Builtin.Int32, %c3 : $Builtin.Int32) -bb7(%r : $Builtin.Int32): +bb7(%r : $Builtin.Int32, %carg2 : $Builtin.Int32): return %r : $Builtin.Int32 } diff --git a/test/SILOptimizer/simplify_cfg_address_phi.sil b/test/SILOptimizer/simplify_cfg_address_phi.sil new file mode 100644 index 0000000000000..438ee2cbdf246 --- /dev/null +++ b/test/SILOptimizer/simplify_cfg_address_phi.sil @@ -0,0 +1,136 @@ +// RUN: %target-sil-opt -enable-objc-interop -enable-sil-verify-all %s -jumpthread-simplify-cfg | %FileCheck %s +// +// Test SimplifyCFG's handling of address-type phis. In other words, makes sure it doesn't create them at all! + +sil_stage canonical + +import Builtin +import Swift +import SwiftShims + +class C { + @_hasStorage @_hasInitialValue var field: Int { get set } + @objc deinit + init() +} + +sil @getC : $@convention(thin) () -> C + +// Test that jump threading sinks a ref_element_addr, generating a +// non-address phi for its operand. +// +// The retain on separate paths followed by a merged release, and +// target block with a conditional branch are necessary just to get +// jump threading to kick in. +// +// CHECK-LABEL: sil @testJumpThreadRefEltLoop : $@convention(thin) () -> () { +// CHECK: bb0 +// CHECK: function_ref @getC : $@convention(thin) () -> C +// CHECK: cond_br undef, bb1, bb2 +// CHECK: bb1: +// CHECK: [[C1:%.*]] = apply %0() : $@convention(thin) () -> C +// CHECK: strong_retain [[C1]] : $C +// CHECK: strong_release [[C1]] : $C +// CHECK: br bb3([[C1]] : $C) +// CHECK: bb2: +// CHECK: [[C2:%.*]] = apply %0() : $@convention(thin) () -> C +// CHECK: strong_retain [[C2]] : $C +// CHECK: strong_release [[C2]] : $C +// CHECK: br bb3([[C2]] : $C) +// CHECK: bb3([[PHI:%.*]] : $C): +// CHECK: [[ADR:%.*]] = ref_element_addr [[PHI]] : $C, #C.field +// CHECK: begin_access [read] [dynamic] [[ADR]] : $*Int +// CHECK: load +// CHECK: end_access +// CHECK-LABEL: } // end sil function 'testJumpThreadRefEltLoop' +sil @testJumpThreadRefEltLoop : $@convention(thin) () -> () { +bb0: + %f = function_ref @getC : $@convention(thin) () -> C + cond_br undef, bb1, bb2 + +bb1: + %c1 = apply %f() : $@convention(thin) ()->C + strong_retain %c1 : $C + br bb3(%c1 : $C) + +bb2: + %c2 = apply %f() : $@convention(thin) ()->C + strong_retain %c2 : $C + br bb3(%c2 : $C) + +bb3(%arg : $C): + strong_release %arg : $C + %18 = ref_element_addr %arg : $C, #C.field + br bb4 + +bb4: + %19 = begin_access [read] [dynamic] %18 : $*Int + %20 = load %19 : $*Int + end_access %19 : $*Int + cond_br undef, bb4, bb5 + +bb5: + %z = tuple () + return %z : $() +} + +// Test that jump threading sinks a +// ref_tail_addr->index_addr->struct_element_addr chain and generates +// a phi for the index_addr's index operand. +// +// The retain on separate paths followed by a merged release, and +// target block with a conditional branch are necessary just to get +// jump threading to kick in. +// +// CHECK-LABEL: sil @testJumpThreadIndex : $@convention(thin) (__ContiguousArrayStorageBase, Builtin.Int64) -> Builtin.Int32 { +// CHECK: bb0(%0 : $__ContiguousArrayStorageBase, %1 : $Builtin.Int64): +// CHECK: cond_br undef, bb1, bb2 +// CHECK: bb1: +// CHECK: apply +// CHECK: strong_retain +// CHECK: strong_release +// CHECK: [[IDX1:%.*]] = builtin "truncOrBitCast_Int64_Word"(%1 : $Builtin.Int64) : $Builtin.Word +// CHECK: br bb3([[IDX1]] : $Builtin.Word) +// CHECK: bb2: +// CHECK: apply +// CHECK: strong_retain +// CHECK: strong_release +// CHECK: [[IDX2:%.*]] = builtin "truncOrBitCast_Int64_Word"(%1 : $Builtin.Int64) : $Builtin.Word +// CHECK: br bb3([[IDX2]] : $Builtin.Word) +// CHECK: bb3([[PHI:%.*]] : $Builtin.Word): +// CHECK: [[TAIL:%.*]] = ref_tail_addr %0 : $__ContiguousArrayStorageBase, $Int32 +// CHECK: [[ELT:%.*]] = index_addr [[TAIL]] : $*Int32, %14 : $Builtin.Word +// CHECK: [[ADR:%.*]] = struct_element_addr [[ELT]] : $*Int32, #Int32._value +// CHECK: load [[ADR]] : $*Builtin.Int32 +// CHECK: cond_br undef, bb4, bb5 +// CHECK-LABEL: } // end sil function 'testJumpThreadIndex' +sil @testJumpThreadIndex : $@convention(thin) (__ContiguousArrayStorageBase, Builtin.Int64) -> Builtin.Int32 { +bb0(%0 : $__ContiguousArrayStorageBase, %1 : $Builtin.Int64): + %f = function_ref @getC : $@convention(thin) () -> C + cond_br undef, bb1, bb2 + +bb1: + %c1 = apply %f() : $@convention(thin) ()->C + strong_retain %c1 : $C + br bb3(%c1 : $C) + +bb2: + %c2 = apply %f() : $@convention(thin) ()->C + strong_retain %c2 : $C + br bb3(%c2 : $C) + +bb3(%arg : $C): + strong_release %arg : $C + %tail = ref_tail_addr %0 : $__ContiguousArrayStorageBase, $Int32 + %idx = builtin "truncOrBitCast_Int64_Word"(%1 : $Builtin.Int64) : $Builtin.Word + %elt = index_addr %tail : $*Int32, %idx : $Builtin.Word + %adr = struct_element_addr %elt : $*Int32, #Int32._value + br bb4 + +bb4: + %val = load %adr : $*Builtin.Int32 + cond_br undef, bb4, bb5 + +bb5: + return %val : $Builtin.Int32 +} diff --git a/test/Sema/pound_assert.swift b/test/Sema/pound_assert.swift index 598e2f05ea7f8..9f826e251ed1a 100644 --- a/test/Sema/pound_assert.swift +++ b/test/Sema/pound_assert.swift @@ -8,6 +8,6 @@ #assert(false, "error message") -#assert(123) // expected-error{{'Int' is not convertible to 'Bool'}} +#assert(123) // expected-error{{cannot convert value of type 'Int' to expected condition type 'Bool'}} -#assert(123, "error message") // expected-error{{'Int' is not convertible to 'Bool'}} +#assert(123, "error message") // expected-error{{cannot convert value of type 'Int' to expected condition type 'Bool'}} diff --git a/test/SourceKit/CursorInfo/cursor_invalid.swift b/test/SourceKit/CursorInfo/cursor_invalid.swift index 0e435d4d56cd3..5e02283858899 100644 --- a/test/SourceKit/CursorInfo/cursor_invalid.swift +++ b/test/SourceKit/CursorInfo/cursor_invalid.swift @@ -25,7 +25,7 @@ func resyncParser2() {} // RUN: %sourcekitd-test -req=cursor -pos=4:13 %s -- %s | %FileCheck -check-prefix=CHECK1 %s // CHECK1: source.lang.swift.decl.var.local (4:13-4:14) // CHECK1: c -// CHECK1: let c +// CHECK1: let c: C // CHECK1: OVERRIDES BEGIN // CHECK1: OVERRIDES END diff --git a/test/SourceKit/Indexing/index.swift b/test/SourceKit/Indexing/index.swift index 47fcc1077321d..5f66b0120935a 100644 --- a/test/SourceKit/Indexing/index.swift +++ b/test/SourceKit/Indexing/index.swift @@ -52,7 +52,7 @@ extension CC : Prot { var extV : Int { return 0 } } -class SubCC : CC, Prot {} +class SubCC : CC {} var globV2: SubCC diff --git a/test/SourceKit/Indexing/index.swift.response b/test/SourceKit/Indexing/index.swift.response index 9b5ad72f57d60..02bdd9f9d044b 100644 --- a/test/SourceKit/Indexing/index.swift.response +++ b/test/SourceKit/Indexing/index.swift.response @@ -501,13 +501,6 @@ key.usr: , key.line: 55, key.column: 15 - }, - { - key.kind: source.lang.swift.ref.protocol, - key.name: "Prot", - key.usr: , - key.line: 55, - key.column: 19 } ], key.entities: [ @@ -532,18 +525,11 @@ key.line: 55, key.column: 15 }, - { - key.kind: source.lang.swift.ref.protocol, - key.name: "Prot", - key.usr: , - key.line: 55, - key.column: 19 - }, { key.kind: source.lang.swift.decl.function.constructor, key.usr: , key.line: 55, - key.column: 24, + key.column: 18, key.is_implicit: 1, key.related: [ { @@ -1222,6 +1208,13 @@ } ] }, + { + key.kind: source.lang.swift.decl.function.method.instance, + key.name: "meth()", + key.usr: , + key.line: 134, + key.column: 8 + }, { key.kind: source.lang.swift.decl.class, key.name: "CC4", diff --git a/test/Syntax/Outputs/round_trip_invalid.swift.withkinds b/test/Syntax/Outputs/round_trip_invalid.swift.withkinds index ad6518bb11185..20da5f46d975c 100644 --- a/test/Syntax/Outputs/round_trip_invalid.swift.withkinds +++ b/test/Syntax/Outputs/round_trip_invalid.swift.withkinds @@ -19,4 +19,5 @@ class C { struct S { enum E { protocol P { -extension P { +extension P { +public init(a: (Int || String)) diff --git a/test/Syntax/Outputs/round_trip_parse_gen.swift.withkinds b/test/Syntax/Outputs/round_trip_parse_gen.swift.withkinds index 7966604e1d737..a509ee05fed66 100644 --- a/test/Syntax/Outputs/round_trip_parse_gen.swift.withkinds +++ b/test/Syntax/Outputs/round_trip_parse_gen.swift.withkinds @@ -121,7 +121,7 @@ protocol PP { associatedtype B: Sequence associatedtype C = Int associatedtype D: Sequence = [Int] - associatedtype E: Sequence = [[Int]] where A.Element : Sequence + associatedtype E: Sequence = [[Int]] where A.Element : Sequence private associatedtype F @objc associatedtype G } @@ -155,7 +155,7 @@ class Bar: Foo foo: Int = 42 } -class C<A, B> where A: Foo, B == Bar {} +class C<A, B> where A: Foo, B == Bar {} @available(*, unavailable) private class C {} @@ -183,9 +183,9 @@ struct foo { } } -struct S<A, B, C, @objc D> where A:B, B==C, A : C, B.C == D.A, A.B: C.D {} +struct S<A, B, C, @objc D> where A:B, B==C, A : C, B.C == D.A, A.B: C.D {} -private struct S<A, B>: Base where A: B { +private struct S<A, B>: Base where A: B { private struct S: A, B {} } @@ -205,18 +205,18 @@ func foo( a: { @objc @available(*, unavailable) -private static override func foo<a, b, c>(a b: Int, c: Int) throws -> [Int] where a==p1, b:p2 { ddd } +private static override func foo<a, b, c>(a b: Int, c: Int) throws -> [Int] where a==p1, b:p2 { ddd } func rootView() -> Label {} static func ==() -> bool {} static func !=<a, b, c>() -> bool {} } @objc -private protocol foo : bar where A==B {} +private protocol foo : bar where A==B {} protocol foo { func foo() } private protocol foo{} @objc -public protocol foo where A:B {} +public protocol foo where A:B {} #if blah func tryfoo() { @@ -431,7 +431,7 @@ fileprivate extension ext ext : extProtocol {} -extension ext where A == Int, B: Numeric {} +extension ext where A == Int, B: Numeric {} extension ext.a.b {} @@ -478,7 +478,7 @@ enum E1 : String bar = "test", baz(x: Int, String) = 12 indirect case qux(E1) - indirect private enum E2<T>: String where T: SomeProtocol { + indirect private enum E2<T>: String where T: SomeProtocol { case foo, bar, baz } } @@ -507,8 +507,8 @@ func higherOrderFunc() #available(iOS 11, macOS 10.11.2, *) {} -@_specialize(where T == Int) -@_specialize(exported: true, where T == String) +@_specialize(where T == Int) +@_specialize(exported: true, where T == String) public func specializedGenericFunc<T>(_ t: T) -> T { return t } @@ -589,7 +589,7 @@ func foo() jvp: foo(_:_:)) func bar(_ x: Float, _: Float) -> Float { return 1 } -@differentiable(jvp: foo(_:_:) where T : FloatingPoint) +@differentiable(jvp: foo(_:_:) where T : FloatingPoint) func bar<T : Numeric>(_ x: T, _: T) -> T { return 1 } @differentiable(wrt: x, jvp: foo(_:_:)) @@ -598,7 +598,7 @@ func bar(_ x: wrt: (self, x, y), jvp: foo(_:_:)) func bar(_ x: Float, y: Float) -> Float { return 1 } -@differentiable(wrt: (self, x, y), jvp: bar, vjp: foo(_:_:) where T : FloatingPoint) +@differentiable(wrt: (self, x, y), jvp: bar, vjp: foo(_:_:) where T : FloatingPoint) func bar<T : Numeric>(_ x: T, y: T) -> T { return 1 } @differentiating(-) diff --git a/test/Syntax/round_trip_invalid.swift b/test/Syntax/round_trip_invalid.swift index 9cc7750288de3..49817bd8e5261 100644 --- a/test/Syntax/round_trip_invalid.swift +++ b/test/Syntax/round_trip_invalid.swift @@ -20,3 +20,4 @@ struct S { enum E { protocol P { extension P { +public init(a: (Int || String)) diff --git a/test/TBD/installapi-flag.swift b/test/TBD/installapi-flag.swift new file mode 100644 index 0000000000000..cf6b04e8d71ba --- /dev/null +++ b/test/TBD/installapi-flag.swift @@ -0,0 +1,17 @@ +// RUN: %empty-directory(%t) + +// 1. Emit two TBDs, one with -tbd-is-installapi set, and one without + +// RUN: %target-swift-frontend -emit-ir -o /dev/null %s -tbd-is-installapi -emit-tbd -emit-tbd-path %t/flag-provided.tbd +// RUN: %target-swift-frontend -emit-ir -o /dev/null %s -emit-tbd -emit-tbd-path %t/flag-omitted.tbd + +// 2. Ensure that the file with -tbd-is-installapi passed includes the installapi flag + +// RUN: %FileCheck %s --check-prefix FLAG-PROVIDED < %t/flag-provided.tbd + +// 3. Ensure that the file without -tbd-is-installapi passed does not include the installapi flag + +// RUN: %FileCheck %s --check-prefix FLAG-OMITTED < %t/flag-omitted.tbd + +// FLAG-PROVIDED: installapi +// FLAG-OMITTED-NOT: installapi diff --git a/test/decl/ext/extensions.swift b/test/decl/ext/extensions.swift index b4eab4419c218..1dd8801709b95 100644 --- a/test/decl/ext/extensions.swift +++ b/test/decl/ext/extensions.swift @@ -126,7 +126,7 @@ struct WrapperContext { } // Class-constrained extension where protocol does not impose class requirement - +// SR-11298 protocol DoesNotImposeClassReq_1 {} class JustAClass: DoesNotImposeClassReq_1 { @@ -140,8 +140,8 @@ extension DoesNotImposeClassReq_1 where Self: JustAClass { } } -let instanceOfJustAClass = JustAClass() // expected-note {{change 'let' to 'var' to make it mutable}} -instanceOfJustAClass.wrappingProperty = "" // expected-error {{cannot assign to property: 'instanceOfJustAClass' is a 'let' constant}} +let instanceOfJustAClass = JustAClass() +instanceOfJustAClass.wrappingProperty = "" // Okay protocol DoesNotImposeClassReq_2 { var property: String { get set } @@ -150,7 +150,7 @@ protocol DoesNotImposeClassReq_2 { extension DoesNotImposeClassReq_2 where Self : AnyObject { var wrappingProperty: String { get { property } - set { property = newValue } // Okay + set { property = newValue } // expected-error {{cannot assign to property: 'self' is immutable}} } } diff --git a/test/decl/func/dynamic_self.swift b/test/decl/func/dynamic_self.swift index ca499e0571cec..1c748f1b1fd9e 100644 --- a/test/decl/func/dynamic_self.swift +++ b/test/decl/func/dynamic_self.swift @@ -437,3 +437,11 @@ class Iterable : Sequence { return DummyIterator() } } + +// Default arguments of methods cannot capture 'Self' or 'self' +class MathClass { + func invalidDefaultArg(s: Int = Self.intMethod()) {} + // expected-error@-1 {{covariant 'Self' type cannot be referenced from a default argument expression}} + + static func intMethod() -> Int { return 0 } +} diff --git a/test/decl/nested/protocol.swift b/test/decl/nested/protocol.swift index 7db8326c98b92..2d49b831ad82a 100644 --- a/test/decl/nested/protocol.swift +++ b/test/decl/nested/protocol.swift @@ -57,10 +57,10 @@ protocol SillyProtocol { class InnerClass {} // expected-error {{type 'InnerClass' cannot be nested in protocol 'SillyProtocol'}} } +// N.B. Redeclaration checks don't see this case because `protocol A` is invalid. enum OuterEnum { protocol C {} // expected-error{{protocol 'C' cannot be nested inside another declaration}} - // expected-note@-1{{'C' previously declared here}} - case C(C) // expected-error{{invalid redeclaration of 'C'}} + case C(C) } class OuterClass { @@ -105,7 +105,9 @@ func testLookup(_ x: OuterForUFI.Inner) { x.req() x.extMethod() } + +// N.B. Lookup fails here because OuterForUFI.Inner is marked invalid. func testLookup(_ x: T) { - x.req() - x.extMethod() + x.req() // expected-error {{value of type 'T' has no member 'req'}} + x.extMethod() // expected-error {{value of type 'T' has no member 'extMethod'}} } diff --git a/test/decl/overload.swift b/test/decl/overload.swift index 68d3d8dec68f0..9a74468dc430b 100644 --- a/test/decl/overload.swift +++ b/test/decl/overload.swift @@ -536,9 +536,10 @@ enum SR_10084_E_2 { } } +// N.B. Redeclaration checks don't see this case because `protocol A` is invalid. enum SR_10084_E_3 { - protocol A {} //expected-error {{protocol 'A' cannot be nested inside another declaration}} // expected-note {{'A' previously declared here}} - case A // expected-error {{invalid redeclaration of 'A'}} + protocol A {} //expected-error {{protocol 'A' cannot be nested inside another declaration}} + case A } enum SR_10084_E_4 { @@ -551,9 +552,10 @@ enum SR_10084_E_5 { case C // expected-error {{invalid redeclaration of 'C'}} } +// N.B. Redeclaration checks don't see this case because `protocol D` is invalid. enum SR_10084_E_6 { - case D // expected-note {{'D' previously declared here}} - protocol D {} //expected-error {{protocol 'D' cannot be nested inside another declaration}} // expected-error {{invalid redeclaration of 'D'}} + case D + protocol D {} //expected-error {{protocol 'D' cannot be nested inside another declaration}} } enum SR_10084_E_7 { @@ -604,4 +606,4 @@ enum SR_10084_E_15 { enum SR_10084_E_16 { typealias Z = Int // expected-note {{'Z' previously declared here}} case Z // expected-error {{invalid redeclaration of 'Z'}} -} \ No newline at end of file +} diff --git a/test/decl/protocol/conforms/error_self_conformance.swift b/test/decl/protocol/conforms/error_self_conformance.swift index 7293d02b0288e..a5ceb7947a8c3 100644 --- a/test/decl/protocol/conforms/error_self_conformance.swift +++ b/test/decl/protocol/conforms/error_self_conformance.swift @@ -1,6 +1,9 @@ // RUN: %target-typecheck-verify-swift func wantsError(_: T) {} +// expected-note@-1 {{required by global function 'wantsError' where 'T' = 'ErrorRefinement'}} +// expected-note@-2 {{required by global function 'wantsError' where 'T' = 'Error & OtherProtocol'}} +// expected-note@-3 {{required by global function 'wantsError' where 'T' = 'C & Error'}} func testSimple(error: Error) { wantsError(error) @@ -8,15 +11,15 @@ func testSimple(error: Error) { protocol ErrorRefinement : Error {} func testErrorRefinment(error: ErrorRefinement) { - wantsError(error) // expected-error {{protocol type 'ErrorRefinement' cannot conform to 'Error' because only concrete types can conform to protocols}} + wantsError(error) // expected-error {{value of protocol type 'ErrorRefinement' cannot conform to 'Error'; only struct/enum/class types can conform to protocols}} } protocol OtherProtocol {} func testErrorComposition(error: Error & OtherProtocol) { - wantsError(error) // expected-error {{protocol type 'Error & OtherProtocol' cannot conform to 'Error' because only concrete types can conform to protocols}} + wantsError(error) // expected-error {{value of protocol type 'Error & OtherProtocol' cannot conform to 'Error'; only struct/enum/class types can conform to protocols}} } class C {} func testErrorCompositionWithClass(error: Error & C) { - wantsError(error) // expected-error {{protocol type 'C & Error' cannot conform to 'Error' because only concrete types can conform to protocols}} + wantsError(error) // expected-error {{value of protocol type 'C & Error' cannot conform to 'Error'; only struct/enum/class types can conform to protocols}} } diff --git a/test/decl/protocol/req/recursion.swift b/test/decl/protocol/req/recursion.swift index 12af9d8cdf803..0ad3d7b01f69e 100644 --- a/test/decl/protocol/req/recursion.swift +++ b/test/decl/protocol/req/recursion.swift @@ -43,7 +43,7 @@ public protocol P { associatedtype T } -public struct S where A.T == S { +public struct S where A.T == S { // expected-error {{circular reference}} // expected-note@-1 {{type declared here}} // expected-error@-2 {{generic struct 'S' references itself}} func f(a: A.T) { @@ -71,7 +71,7 @@ protocol PI { associatedtype T : I } -struct SI : I where A : I, A.T == SI { +struct SI : I where A : I, A.T == SI { // expected-error {{circular reference}} // expected-note@-1 {{type declared here}} // expected-error@-2 {{generic struct 'SI' references itself}} func ggg(t: T.Type) -> T { diff --git a/test/decl/var/property_wrappers.swift b/test/decl/var/property_wrappers.swift index b09b45d63c38f..a684e6cc1a78f 100644 --- a/test/decl/var/property_wrappers.swift +++ b/test/decl/var/property_wrappers.swift @@ -1013,6 +1013,18 @@ struct Foo { // expected-note {{arguments to generic parameter 'T' ('W' and ' } } +extension Foo : Equatable where T : Equatable { + static func == (lhs: Foo, rhs: Foo) -> Bool { + lhs.wrappedValue == rhs.wrappedValue + } +} + +extension Foo : Hashable where T : Hashable { + func hash(into hasher: inout Hasher) { + hasher.combine(wrappedValue) + } +} + @propertyWrapper struct Bar { var wrappedValue: T @@ -1061,6 +1073,8 @@ struct MissingPropertyWrapperUnwrap { func d(_: W) {} func e(_: Foo) {} + subscript(takesFoo x: Foo) -> Foo { x } + func baz() { self.x.foo() // expected-error {{referencing instance method 'foo()' requires wrapper 'Foo'}}{{10-10=_}} self.x.prop // expected-error {{referencing property 'prop' requires wrapper 'Foo'}} {{10-10=_}} @@ -1094,6 +1108,10 @@ struct MissingPropertyWrapperUnwrap { self.x[q: "ultimate question", 42] // expected-error {{referencing subscript 'subscript(q:_:)' requires wrapper 'Foo'}} {{10-10=_}} self.x[q: "ultimate question", 42] = true // expected-error {{referencing subscript 'subscript(q:_:)' requires wrapper 'Foo'}} {{10-10=_}} + + // SR-11476 + _ = \Self.[takesFoo: self.x] // expected-error {{cannot convert value 'x' of type 'Int' to expected type 'Foo', use wrapper instead}}{{31-31=_}} + _ = \Foo.[x: self._x] // expected-error {{cannot convert value '_x' of type 'Foo' to expected type 'Int', use wrapped value instead}} {{26-27=}} } } @@ -1646,3 +1664,36 @@ struct UseNonMutatingProjectedValueSet { x = 42 // expected-error{{cannot assign to property: 'self' is immutable}} } } + +// SR-11478 + +@propertyWrapper +struct SR_11478_W { + var wrappedValue: Value +} + +class SR_11478_C1 { + @SR_11478_W static var bool1: Bool = true // Ok + @SR_11478_W class var bool2: Bool = true // expected-error {{class stored properties not supported in classes; did you mean 'static'?}} + @SR_11478_W class final var bool3: Bool = true // expected-error {{class stored properties not supported in classes; did you mean 'static'?}} +} + +final class SR_11478_C2 { + @SR_11478_W static var bool1: Bool = true // Ok + @SR_11478_W class var bool2: Bool = true // expected-error {{class stored properties not supported in classes; did you mean 'static'?}} + @SR_11478_W class final var bool3: Bool = true // expected-error {{class stored properties not supported in classes; did you mean 'static'?}} +} + +// SR-11381 + +@propertyWrapper +struct SR_11381_W { + init(wrappedValue: T) {} + var wrappedValue: T { + fatalError() + } +} + +struct SR_11381_S { + @SR_11381_W var foo: Int = nil // expected-error {{'nil' is not compatible with expected argument type 'Int'}} +} diff --git a/test/expr/expressions.swift b/test/expr/expressions.swift index c9de5cca8875c..6a8a4fc3525c1 100644 --- a/test/expr/expressions.swift +++ b/test/expr/expressions.swift @@ -799,14 +799,14 @@ func testOptionalTypeParsing(_ a : AnyObject) -> String { func testParenExprInTheWay() { let x = 42 - if x & 4.0 {} // expected-error {{binary operator '&' cannot be applied to operands of type 'Int' and 'Double'}} expected-note {{expected an argument list of type '(Int, Int)'}} - + if x & 4.0 {} // expected-error {{cannot convert value of type 'Double' to expected argument type 'Int'}} + // expected-error@-1 {{cannot convert value of type 'Int' to expected condition type 'Bool'}} if (x & 4.0) {} // expected-error {{cannot convert value of type 'Double' to expected argument type 'Int'}} - + // expected-error@-1 {{cannot convert value of type 'Int' to expected condition type 'Bool'}} if !(x & 4.0) {} // expected-error {{cannot convert value of type 'Double' to expected argument type 'Int'}} // expected-error@-1 {{cannot convert value of type 'Int' to expected argument type 'Bool'}} - - if x & x {} // expected-error {{'Int' is not convertible to 'Bool'}} + + if x & x {} // expected-error {{cannot convert value of type 'Int' to expected condition type 'Bool'}} } // Mixed method/property overload groups can cause a crash during constraint optimization diff --git a/test/multifile/Inputs/sr11458.swift b/test/multifile/Inputs/sr11458.swift new file mode 100644 index 0000000000000..2aff25bc501c4 --- /dev/null +++ b/test/multifile/Inputs/sr11458.swift @@ -0,0 +1,54 @@ +protocol Observed: AnyObject { +} + +struct Other { + var value: Value + + func hello() -> String { + return "Hello from \(value)" + } +} + +@propertyWrapper +struct Observable { + private var stored: Value + + + init(wrappedValue: Value) { + self.stored = wrappedValue + } + + var wrappedValue: Value { + get { fatalError("called wrappedValue getter") } + set { fatalError("called wrappedValue setter") } + } + + var projectedValue: Other { + get { fatalError("called projectedValue getter") } + set { fatalError("called projectedValue setter") } + } + + static subscript( + _enclosingInstance observed: EnclosingSelf, + wrapped wrappedKeyPath: ReferenceWritableKeyPath, + storage storageKeyPath: ReferenceWritableKeyPath + ) -> Value { + get { + fatalError("blah") + } + set { + } + } + + static subscript( + _enclosingInstance observed: EnclosingSelf, + projected wrappedKeyPath: ReferenceWritableKeyPath>, + storage storageKeyPath: ReferenceWritableKeyPath + ) -> Other { + get { + fatalError("blah") + } + set { + } + } +} diff --git a/test/multifile/property-wrappers-sr11458.swift b/test/multifile/property-wrappers-sr11458.swift new file mode 100644 index 0000000000000..693ae7558be8d --- /dev/null +++ b/test/multifile/property-wrappers-sr11458.swift @@ -0,0 +1,10 @@ +// RUN: %target-swift-frontend -typecheck -primary-file %s %S/Inputs/sr11458.swift + +// SR-11458: crash involving subscript in other file +class MyOtherType: Observed { + @Observable var x: T + + init(x: T) { + self.x = x + } +} diff --git a/test/refactoring/MemberwiseInit/Outputs/class_members/class_members.swift.expected b/test/refactoring/MemberwiseInit/Outputs/class_members/class_members.swift.expected deleted file mode 100644 index 5c3de898efb13..0000000000000 --- a/test/refactoring/MemberwiseInit/Outputs/class_members/class_members.swift.expected +++ /dev/null @@ -1,14 +0,0 @@ -class Person { -internal init(firstName: String?, lastName: String?, age: Int?) { -self.firstName = firstName -self.lastName = lastName -self.age = age -} - - var firstName: String! - var lastName: String! - var age: Int! - var planet = "Earth", solarSystem = "Milky Way" - var avgHeight = 175 -} - diff --git a/test/refactoring/MemberwiseInit/Outputs/generate_memberwise/class_members.swift.expected b/test/refactoring/MemberwiseInit/Outputs/generate_memberwise/class_members.swift.expected new file mode 100644 index 0000000000000..8745fd7235738 --- /dev/null +++ b/test/refactoring/MemberwiseInit/Outputs/generate_memberwise/class_members.swift.expected @@ -0,0 +1,40 @@ +class Person { +internal init(firstName: String? = nil, lastName: String? = nil, age: Int? = nil, planet: String = "Earth", solarSystem: String = "Milky Way", avgHeight: Int = 175) { +self.firstName = firstName +self.lastName = lastName +self.age = age +self.planet = planet +self.solarSystem = solarSystem +self.avgHeight = avgHeight +} + + var firstName: String! + var lastName: String! + var age: Int! + var planet = "Earth", solarSystem = "Milky Way" + var avgHeight = 175 + let line = #line, file = #file, handle = #dsohandle + lazy var idea: Idea = { fatalError() }() +} + +struct Place { + let person: Person + let street: String + let apartment: Optional + let city: String + let state: String + let postalCode: Int + let plusFour: Int? +} + +protocol Thing { + var idea: Idea { get } +} + +enum Idea { + var subject: String { fatalError() } +} + + + + diff --git a/test/refactoring/MemberwiseInit/Outputs/generate_memberwise/struct_members.swift.expected b/test/refactoring/MemberwiseInit/Outputs/generate_memberwise/struct_members.swift.expected new file mode 100644 index 0000000000000..f16631713528f --- /dev/null +++ b/test/refactoring/MemberwiseInit/Outputs/generate_memberwise/struct_members.swift.expected @@ -0,0 +1,41 @@ +class Person { + var firstName: String! + var lastName: String! + var age: Int! + var planet = "Earth", solarSystem = "Milky Way" + var avgHeight = 175 + let line = #line, file = #file, handle = #dsohandle + lazy var idea: Idea = { fatalError() }() +} + +struct Place { +internal init(person: Person, street: String, apartment: Optional, city: String, state: String, postalCode: Int, plusFour: Int?) { +self.person = person +self.street = street +self.apartment = apartment +self.city = city +self.state = state +self.postalCode = postalCode +self.plusFour = plusFour +} + + let person: Person + let street: String + let apartment: Optional + let city: String + let state: String + let postalCode: Int + let plusFour: Int? +} + +protocol Thing { + var idea: Idea { get } +} + +enum Idea { + var subject: String { fatalError() } +} + + + + diff --git a/test/refactoring/MemberwiseInit/class_members.swift b/test/refactoring/MemberwiseInit/class_members.swift deleted file mode 100644 index 78081b6b8f18a..0000000000000 --- a/test/refactoring/MemberwiseInit/class_members.swift +++ /dev/null @@ -1,11 +0,0 @@ -class Person { - var firstName: String! - var lastName: String! - var age: Int! - var planet = "Earth", solarSystem = "Milky Way" - var avgHeight = 175 -} - -// RUN: %empty-directory(%t.result) -// RUN: %refactor -memberwise-init -source-filename %s -pos=1:8 > %t.result/class_members.swift -// RUN: diff -u %S/Outputs/class_members/class_members.swift.expected %t.result/class_members.swift diff --git a/test/refactoring/MemberwiseInit/generate_memberwise.swift b/test/refactoring/MemberwiseInit/generate_memberwise.swift new file mode 100644 index 0000000000000..f63e7294dc914 --- /dev/null +++ b/test/refactoring/MemberwiseInit/generate_memberwise.swift @@ -0,0 +1,38 @@ +class Person { + var firstName: String! + var lastName: String! + var age: Int! + var planet = "Earth", solarSystem = "Milky Way" + var avgHeight = 175 + let line = #line, file = #file, handle = #dsohandle + lazy var idea: Idea = { fatalError() }() +} + +struct Place { + let person: Person + let street: String + let apartment: Optional + let city: String + let state: String + let postalCode: Int + let plusFour: Int? +} + +protocol Thing { + var idea: Idea { get } +} + +enum Idea { + var subject: String { fatalError() } +} + +// RUN: %empty-directory(%t.result) +// RUN: %refactor -memberwise-init -source-filename %s -pos=1:8 > %t.result/generate_memberwise.swift +// RUN: diff -u %S/Outputs/generate_memberwise/class_members.swift.expected %t.result/generate_memberwise.swift + +// RUN: %refactor -memberwise-init -source-filename %s -pos=11:8 > %t.result/struct_members.swift +// RUN: diff -u %S/Outputs/generate_memberwise/struct_members.swift.expected %t.result/struct_members.swift + +// RUN: not %refactor -memberwise-init -source-filename %s -pos=21:10 > %t.result/protocol_members.swift +// RUN: not %refactor -memberwise-init -source-filename %s -pos=25:6 > %t.result/enum_members.swift + diff --git a/test/stdlib/POSIX.swift b/test/stdlib/POSIX.swift index 91cec1c2e01bd..ead9a623554b4 100644 --- a/test/stdlib/POSIX.swift +++ b/test/stdlib/POSIX.swift @@ -69,7 +69,7 @@ POSIXTests.test("sem_open success") { let sem = sem_open(semaphoreName, O_CREAT, 0o777, 1) expectNotEqual(SEM_FAILED, sem) - let res = sem_close(sem) + let res = sem_close(sem!) expectEqual(0, res) let res2 = sem_unlink(semaphoreName) @@ -83,7 +83,7 @@ POSIXTests.test("sem_open O_EXCL success") { let sem = sem_open(semaphoreName, O_CREAT | O_EXCL, 0o777, 1) expectNotEqual(SEM_FAILED, sem) - let res = sem_close(sem) + let res = sem_close(sem!) expectEqual(0, res) let res2 = sem_unlink(semaphoreName) @@ -102,7 +102,7 @@ POSIXTests.test("sem_open existing") { // difficult. expectNotEqual(SEM_FAILED, sem2) - let res = sem_close(sem) + let res = sem_close(sem!) expectEqual(0, res) let res2 = sem_unlink(semaphoreName) @@ -120,7 +120,7 @@ POSIXTests.test("sem_open existing O_EXCL fail") { expectEqual(SEM_FAILED, sem2) expectEqual(EEXIST, errno) - let res = sem_close(sem) + let res = sem_close(sem!) expectEqual(0, res) let res2 = sem_unlink(semaphoreName) diff --git a/test/stmt/foreach.swift b/test/stmt/foreach.swift index 59d7b3f9b20e8..a03aa93c5f507 100644 --- a/test/stmt/foreach.swift +++ b/test/stmt/foreach.swift @@ -179,7 +179,7 @@ func testOptionalSequence() { // Crash with (invalid) for each over an existential func testExistentialSequence(s: Sequence) { // expected-error {{protocol 'Sequence' can only be used as a generic constraint because it has Self or associated type requirements}} - for x in s { // expected-error {{protocol type 'Sequence' cannot conform to 'Sequence' because only concrete types can conform to protocols}} + for x in s { // expected-error {{value of protocol type 'Sequence' cannot conform to 'Sequence'; only struct/enum/class types can conform to protocols}} _ = x } } diff --git a/test/stmt/if_while_var.swift b/test/stmt/if_while_var.swift index 750c1903d23ff..bffe794086c42 100644 --- a/test/stmt/if_while_var.swift +++ b/test/stmt/if_while_var.swift @@ -88,7 +88,7 @@ if 1 != 2, case let x? : Int? = 42 {} // expected-warning {{immutable value 'x' // Test error recovery. // Improve error recovery for malformed if statements -if 1 != 2, { // expected-error {{'() -> ()' is not convertible to 'Bool'}} +if 1 != 2, { // expected-error {{cannot convert value of type '() -> ()' to expected condition type 'Bool'}} } // expected-error {{expected '{' after 'if' condition}} if 1 != 2, 4 == 57 {} if 1 != 2, 4 == 57, let x = opt {} // expected-warning {{immutable value 'x' was never used; consider replacing with '_' or removing it}} diff --git a/test/stmt/statements.swift b/test/stmt/statements.swift index fbb9237d2f2a0..a22f4537450eb 100644 --- a/test/stmt/statements.swift +++ b/test/stmt/statements.swift @@ -59,7 +59,7 @@ func funcdecl5(_ a: Int, y: Int) { } // This diagnostic is terrible - rdar://12939553 - if x {} // expected-error {{'Int' is not convertible to 'Bool'}} + if x {} // expected-error {{cannot convert value of type 'Int' to expected condition type 'Bool'}} if true { if (B) { @@ -99,7 +99,7 @@ struct infloopbool { } func infloopbooltest() { - if (infloopbool()) {} // expected-error {{'infloopbool' is not convertible to 'Bool'}} + if (infloopbool()) {} // expected-error {{cannot convert value of type 'infloopbool' to expected condition type 'Bool'}} } // test "builder" API style @@ -566,9 +566,10 @@ func fn(x: Int) { } func bad_if() { - if 1 {} // expected-error {{'Int' is not convertible to 'Bool'}} - if (x: false) {} // expected-error {{'(x: Bool)' is not convertible to 'Bool'}} - if (x: 1) {} // expected-error {{'(x: Int)' is not convertible to 'Bool'}} + if 1 {} // expected-error {{cannot convert value of type 'Int' to expected condition type 'Bool'}} + if (x: false) {} // expected-error {{cannot convert value of type '(x: Bool)' to expected condition type 'Bool'}} + if (x: 1) {} // expected-error {{cannot convert value of type '(x: Int)' to expected condition type 'Bool'}} + if nil {} // expected-error {{'nil' is not compatible with expected condition type 'Bool'}} } // Typo correction for loop labels diff --git a/test/type/opaque.swift b/test/type/opaque.swift index 0e28381369d80..b78bf21108137 100644 --- a/test/type/opaque.swift +++ b/test/type/opaque.swift @@ -376,9 +376,9 @@ protocol P_51641323 { func rdar_51641323() { struct Foo: P_51641323 { - var foo: some P_51641323 { {} } - // expected-error@-1 {{return type of property 'foo' requires that '() -> ()' conform to 'P_51641323'}} - // expected-note@-2 {{opaque return type declared here}} + var foo: some P_51641323 { // expected-note {{required by opaque return type of property 'foo'}} + {} // expected-error {{type '() -> ()' cannot conform to 'P_51641323'; only struct/enum/class types can conform to protocols}} + } } } diff --git a/test/type/subclass_composition.swift b/test/type/subclass_composition.swift index a798961411ff2..749a44cae6109 100644 --- a/test/type/subclass_composition.swift +++ b/test/type/subclass_composition.swift @@ -300,6 +300,7 @@ func dependentMemberTypes( func conformsToAnyObject(_: T) {} func conformsToP1(_: T) {} +// expected-note@-1 {{required by global function 'conformsToP1' where 'T' = 'P1'}} func conformsToP2(_: T) {} func conformsToBaseIntAndP2 & P2>(_: T) {} // expected-note@-1 {{where 'T' = 'FakeDerived'}} @@ -412,7 +413,7 @@ func conformsTo & P2>( // expected-note@-2 {{expected an argument list of type '(T)'}} conformsToP1(p1) - // expected-error@-1 {{protocol type 'P1' cannot conform to 'P1' because only concrete types can conform to protocols}} + // expected-error@-1 {{value of protocol type 'P1' cannot conform to 'P1'; only struct/enum/class types can conform to protocols}} // FIXME: Following diagnostics are not great because when // `conformsTo*` methods are re-typechecked, they loose information diff --git a/tools/SourceKit/lib/SwiftLang/CodeCompletionOrganizer.cpp b/tools/SourceKit/lib/SwiftLang/CodeCompletionOrganizer.cpp index 4a376bf277898..2fc29e21328b1 100644 --- a/tools/SourceKit/lib/SwiftLang/CodeCompletionOrganizer.cpp +++ b/tools/SourceKit/lib/SwiftLang/CodeCompletionOrganizer.cpp @@ -176,7 +176,6 @@ bool SourceKit::CodeCompletion::addCustomCompletions( } break; case CompletionKind::PostfixExprBeginning: - case CompletionKind::AssignmentRHS: case CompletionKind::CallArg: case CompletionKind::ReturnStmtExpr: case CompletionKind::YieldStmtExpr: diff --git a/tools/SourceKit/lib/SwiftLang/SwiftDocSupport.cpp b/tools/SourceKit/lib/SwiftLang/SwiftDocSupport.cpp index fd67233709015..548347424ea98 100644 --- a/tools/SourceKit/lib/SwiftLang/SwiftDocSupport.cpp +++ b/tools/SourceKit/lib/SwiftLang/SwiftDocSupport.cpp @@ -533,10 +533,9 @@ static void reportRelated(ASTContext &Ctx, const Decl *D, } else if (auto *TAD = dyn_cast(D)) { - if (TAD->hasInterfaceType()) { + if (auto Ty = TAD->getDeclaredInterfaceType()) { // If underlying type exists, report the inheritance and conformance of the // underlying type. - auto Ty = TAD->getDeclaredInterfaceType(); if (auto NM = Ty->getAnyNominal()) { passInherits(NM->getInherited(), Consumer); passConforms(NM->getSatisfiedProtocolRequirements(/*Sorted=*/true), diff --git a/tools/SourceKit/lib/SwiftLang/SwiftSourceDocInfo.cpp b/tools/SourceKit/lib/SwiftLang/SwiftSourceDocInfo.cpp index 580eae27e9e4b..7576f7a699895 100644 --- a/tools/SourceKit/lib/SwiftLang/SwiftSourceDocInfo.cpp +++ b/tools/SourceKit/lib/SwiftLang/SwiftSourceDocInfo.cpp @@ -778,11 +778,11 @@ static bool passCursorInfoForDecl(SourceFile* SF, unsigned USREnd = SS.size(); unsigned TypenameBegin = SS.size(); - if (VD->hasInterfaceType()) { + if (auto vdType = VD->getInterfaceType()) { llvm::raw_svector_ostream OS(SS); PrintOptions Options; Options.PrintTypeAliasUnderlyingType = true; - VD->getInterfaceType().print(OS, Options); + vdType.print(OS, Options); } unsigned TypenameEnd = SS.size(); diff --git a/tools/swift-api-digester/ModuleAnalyzerNodes.cpp b/tools/swift-api-digester/ModuleAnalyzerNodes.cpp index 23747b6932ee0..d5adcfff0db0e 100644 --- a/tools/swift-api-digester/ModuleAnalyzerNodes.cpp +++ b/tools/swift-api-digester/ModuleAnalyzerNodes.cpp @@ -1679,7 +1679,7 @@ SwiftDeclCollector::constructVarNode(ValueDecl *VD) { SDKNode *swift::ide::api:: SwiftDeclCollector::constructTypeAliasNode(TypeAliasDecl *TAD) { auto Alias = SDKNodeInitInfo(Ctx, TAD).createSDKNode(SDKNodeKind::DeclTypeAlias); - Alias->addChild(constructTypeNode(TAD->getUnderlyingTypeLoc().getType())); + Alias->addChild(constructTypeNode(TAD->getUnderlyingType())); return Alias; } diff --git a/tools/swift-api-digester/swift-api-digester.cpp b/tools/swift-api-digester/swift-api-digester.cpp index d5969a8540a04..f22e4cd806ee7 100644 --- a/tools/swift-api-digester/swift-api-digester.cpp +++ b/tools/swift-api-digester/swift-api-digester.cpp @@ -130,6 +130,10 @@ static llvm::cl::opt Verbose("v", llvm::cl::desc("Verbose"), llvm::cl::cat(Category)); +static llvm::cl::opt +DebugMapping("debug-mapping", llvm::cl::desc("Dumping information for debug purposes"), + llvm::cl::cat(Category)); + static llvm::cl::opt Abi("abi", llvm::cl::desc("Dumping ABI interface"), llvm::cl::init(false), llvm::cl::cat(Category)); @@ -1090,7 +1094,7 @@ class PrunePass : public MatchedNodeListener, public SDKTreeDiffPass { ProtocolReqWhitelist(std::move(prWhitelist)) {} void foundMatch(NodePtr Left, NodePtr Right, NodeMatchReason Reason) override { - if (options::Verbose) + if (options::DebugMapping) debugMatch(Left, Right, Reason, llvm::errs()); switch (Reason) { case NodeMatchReason::Added: diff --git a/tools/swift-ide-test/ModuleAPIDiff.cpp b/tools/swift-ide-test/ModuleAPIDiff.cpp index dbca719460436..b3a54a75c0ca8 100644 --- a/tools/swift-ide-test/ModuleAPIDiff.cpp +++ b/tools/swift-ide-test/ModuleAPIDiff.cpp @@ -833,7 +833,7 @@ class SMAModelGenerator : public DeclVisitor { void visitTypeAliasDecl(TypeAliasDecl *TAD) { auto ResultTD = std::make_shared(); ResultTD->Name = convertToIdentifier(TAD->getName()); - ResultTD->Type = convertToTypeName(TAD->getUnderlyingTypeLoc().getType()); + ResultTD->Type = convertToTypeName(TAD->getUnderlyingType()); // FIXME // ResultTD->Attributes = ?; Result.Typealiases.emplace_back(std::move(ResultTD)); diff --git a/tools/swift-stdlib-tool/swift-stdlib-tool.mm b/tools/swift-stdlib-tool/swift-stdlib-tool.mm index 70a8bb37189d7..bd25b31b0d488 100644 --- a/tools/swift-stdlib-tool/swift-stdlib-tool.mm +++ b/tools/swift-stdlib-tool/swift-stdlib-tool.mm @@ -985,7 +985,7 @@ int main(int argc, const char *argv[]) src_dir = [[[self_executable stringByDeletingLastPathComponent] stringByDeletingLastPathComponent] sst_stringByAppendingPathComponents: - @[ @"lib", @"swift", platform ]]; + @[ @"lib", @"swift-5.0", platform ]]; } else if (!platform) { // src_dir is set but platform is not. // Pick platform from src_dir's name. diff --git a/unittests/AST/TestContext.h b/unittests/AST/TestContext.h index f39d22307eaa4..428a933b0cd01 100644 --- a/unittests/AST/TestContext.h +++ b/unittests/AST/TestContext.h @@ -13,6 +13,7 @@ #include "swift/AST/ASTContext.h" #include "swift/AST/DiagnosticEngine.h" #include "swift/AST/Module.h" +#include "swift/AST/SourceFile.h" #include "swift/Basic/LangOptions.h" #include "swift/Basic/SourceManager.h" diff --git a/unittests/Syntax/DeclSyntaxTests.cpp b/unittests/Syntax/DeclSyntaxTests.cpp index 5f29d564442fa..bc13978633314 100644 --- a/unittests/Syntax/DeclSyntaxTests.cpp +++ b/unittests/Syntax/DeclSyntaxTests.cpp @@ -550,11 +550,11 @@ GenericWhereClauseSyntax getCannedWhereClause() { auto T = SyntaxFactory::makeTypeIdentifier("T", {}, Trivia::spaces(1)); auto EqualEqual = SyntaxFactory::makeEqualityOperator({}, Trivia::spaces(1)); auto Int = SyntaxFactory::makeTypeIdentifier("Int", {}, Trivia::spaces(1)); - auto SameType = SyntaxFactory::makeSameTypeRequirement(T, EqualEqual, Int, - None); + auto SameType = SyntaxFactory::makeSameTypeRequirement(T, EqualEqual, Int); + auto Req = SyntaxFactory::makeGenericRequirement(SameType, None); auto Requirements = SyntaxFactory::makeBlankGenericRequirementList() - .appending(SameType); + .appending(Req); return SyntaxFactory::makeBlankGenericWhereClause() .withWhereKeyword(WhereKW) diff --git a/unittests/runtime/Stdlib.cpp b/unittests/runtime/Stdlib.cpp index 1d356f20fd5dc..0c257e14bc167 100644 --- a/unittests/runtime/Stdlib.cpp +++ b/unittests/runtime/Stdlib.cpp @@ -204,6 +204,221 @@ const long long $ssSeVMn[1] = {0}; SWIFT_RUNTIME_STDLIB_INTERNAL const long long $sShMn[1] = {0}; +// Bool + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSbMn[1] = {0}; + +// Binary Floating Point + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSBMp[1] = {0}; + +// Double + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSdMn[1] = {0}; + +// RandomNumberGenerator + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSGMp[1] = {0}; + +// Int + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSiMn[1] = {0}; + +// DefaultIndicis + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSIMn[1] = {0}; + +// Character + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSJMn[1] = {0}; + +// Numeric + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSjMp[1] = {0}; + +// RandomAccessCollection + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSkMp[1] = {0}; + +// BidirectionalCollection + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSKMp[1] = {0}; + +// RangeReplacementCollection + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSmMp[1] = {0}; + +// MutationCollection + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSMMp[1] = {0}; + +// Range + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSnMn[1] = {0}; + +// ClosedRange + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSNMn[1] = {0}; + +// ObjectIdentifier + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSOMn[1] = {0}; + +// UnsafeMutablePointer + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSpMn[1] = {0}; + +// Optional + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSqMn[1] = {0}; + +// Equatable + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSQMp[1] = {0}; + +// UnsafeMutableBufferPointer + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSrMn[1] = {0}; + +// UnsafeBufferPointer + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSRMn[1] = {0}; + +// String + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSSMn[1] = {0}; + +// Sequence + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSTMp[1] = {0}; + +// UInt + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSuMn[1] = {0}; + +// UnsignedInteger + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSUMp[1] = {0}; + +// UnsafeMutableRawPointer + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSvMn[1] = {0}; + +// Strideable + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSxMp[1] = {0}; + +// RangeExpression + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSXMp[1] = {0}; + +// StringProtocol + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSyMp[1] = {0}; + +// RawRepresentable + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSYMp[1] = {0}; + +// BinaryInteger + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSzMp[1] = {0}; + +// Decodable + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSeMp[1] = {0}; + +// Encodable + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSEMp[1] = {0}; + +// Float + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSfMn[1] = {0}; + +// FloatingPoint + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSFMp[1] = {0}; + +// Collection + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSlMp[1] = {0}; + +// Comparable + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSLMp[1] = {0}; + +// UnsafePointer + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSPMn[1] = {0}; + +// Substring + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSsMn[1] = {0}; + +// IteratorProtocol + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sStMp[1] = {0}; + +// UnsafeRawPointer + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSVMn[1] = {0}; + +// UnsafeMutableRawBufferPointer + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSwMn[1] = {0}; + +// UnsafeRawBufferPointer + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSWMn[1] = {0}; + +// SignedInteger + +SWIFT_RUNTIME_STDLIB_INTERNAL +const long long $sSZMp[1] = {0}; + // Mirror // protocol witness table for Swift._ClassSuperMirror : Swift._Mirror in Swift diff --git a/utils/build-script-impl b/utils/build-script-impl index bd6f8131c2740..27bccc012475a 100755 --- a/utils/build-script-impl +++ b/utils/build-script-impl @@ -2972,6 +2972,7 @@ for host in "${ALL_HOSTS[@]}"; do -DCMAKE_C_COMPILER:PATH="${LLVM_BIN}/clang" -DCMAKE_CXX_COMPILER:PATH="${LLVM_BIN}/clang++" -DCMAKE_SWIFT_COMPILER:PATH="${SWIFTC_BIN}" + -DCMAKE_Swift_COMPILER:PATH="${SWIFTC_BIN}" -DCMAKE_INSTALL_PREFIX:PATH="$(get_host_install_prefix ${host})" -DCMAKE_INSTALL_LIBDIR:PATH="lib" @@ -3609,6 +3610,10 @@ for host in "${ALL_HOSTS[@]}"; do continue ;; *) + cmake_options=( + ${cmake_options[@]} + -DCMAKE_Swift_COMPILER:PATH="$(build_directory_bin ${LOCAL_HOST} swift)/swiftc" + ) results_targets=( "test" ) executable_target="" ;; diff --git a/utils/cmpcodesize/cmpcodesize/main.py b/utils/cmpcodesize/cmpcodesize/main.py index b9b9aca2392c2..13e10affb97f5 100644 --- a/utils/cmpcodesize/cmpcodesize/main.py +++ b/utils/cmpcodesize/cmpcodesize/main.py @@ -107,6 +107,18 @@ def main(): 'other programs.', action='store_true', default=False) + parser.add_argument('-o', '--old-build-directory', + help='The directory containing the baseline objects ' + + 'against which to compare sizes.', + action='store', + dest='old_build_dir', + default=None) + parser.add_argument('-n', '--new-build-directory', + help='The directory containing the new objects whose' + + 'sizes are to be compared against the baseline.', + action='store', + dest='new_build_dir', + default=None) # Positional arguments. # These can be specified in means beyond what argparse supports, @@ -145,8 +157,12 @@ def main(): else: old_file_args = parsed_arguments.files - old_build_dir = os.environ.get("SWIFT_OLD_BUILDDIR") - new_build_dir = os.environ.get("SWIFT_NEW_BUILDDIR") + old_build_dir = parsed_arguments.old_build_dir + if not old_build_dir: + old_build_dir = os.environ.get("SWIFT_OLD_BUILDDIR") + new_build_dir = parsed_arguments.new_build_dir + if not new_build_dir: + new_build_dir = os.environ.get("SWIFT_NEW_BUILDDIR") if not parsed_arguments.files: assert old_build_dir and new_build_dir, \ diff --git a/utils/gyb_syntax_support/CompletionOnlyNodes.py b/utils/gyb_syntax_support/CompletionOnlyNodes.py new file mode 100644 index 0000000000000..d1bd1b7b32978 --- /dev/null +++ b/utils/gyb_syntax_support/CompletionOnlyNodes.py @@ -0,0 +1,19 @@ +from Child import Child +from Node import Node # noqa: I201 + +# These nodes are used only in code completion. + +COMPLETIONONLY_NODES = [ + # type + Node('CodeCompletionType', kind='Type', + children=[ + Child('Base', kind='Type', is_optional=True), + Child('Period', kind='Token', + token_choices=[ + 'PeriodToken', + 'PrefixPeriodToken', + ], + is_optional=True), + Child('CodeCompletionToken', kind='Token'), + ]), +] diff --git a/utils/gyb_syntax_support/GenericNodes.py b/utils/gyb_syntax_support/GenericNodes.py index e93a80b3bfe05..61fd4cf0723ff 100644 --- a/utils/gyb_syntax_support/GenericNodes.py +++ b/utils/gyb_syntax_support/GenericNodes.py @@ -11,22 +11,39 @@ ]), Node('GenericRequirementList', kind='SyntaxCollection', - element='Syntax', + element='GenericRequirement', element_name='GenericRequirement'), + # generic-requirement -> + # (same-type-requrement|conformance-requirement|layout-requirement) ','? + Node('GenericRequirement', kind='Syntax', + traits=['WithTrailingComma'], + children=[ + Child('Body', kind='Syntax', + node_choices=[ + Child('SameTypeRequirement', + kind='SameTypeRequirement'), + Child('ConformanceRequirement', + kind='ConformanceRequirement'), + Child('LayoutRequirement', + kind='LayoutRequirement'), + ]), + Child('TrailingComma', kind='CommaToken', + is_optional=True), + ]), + # same-type-requirement -> type-identifier == type Node('SameTypeRequirement', kind='Syntax', - traits=['WithTrailingComma'], children=[ Child('LeftTypeIdentifier', kind='Type'), Child('EqualityToken', kind='Token', token_choices=[ 'SpacedBinaryOperatorToken', 'UnspacedBinaryOperatorToken', + 'PrefixOperatorToken', + 'PostfixOperatorToken', ]), Child('RightTypeIdentifier', kind='Type'), - Child('TrailingComma', kind='CommaToken', - is_optional=True), ]), Node('GenericParameterList', kind='SyntaxCollection', @@ -55,17 +72,41 @@ Child('LeftAngleBracket', kind='LeftAngleToken'), Child('GenericParameterList', kind='GenericParameterList', collection_element_name='GenericParameter'), + Child('ObsoletedWhereClause', kind='GenericWhereClause', + is_optional=True), Child('RightAngleBracket', kind='RightAngleToken'), ]), # conformance-requirement -> type-identifier : type-identifier Node('ConformanceRequirement', kind='Syntax', - traits=['WithTrailingComma'], children=[ Child('LeftTypeIdentifier', kind='Type'), Child('Colon', kind='ColonToken'), Child('RightTypeIdentifier', kind='Type'), - Child('TrailingComma', kind='CommaToken', + ]), + + # layout-requirement -> type ':' layout-constraint + Node('LayoutRequirement', kind='Syntax', + children=[ + Child('LeftTypeIdentifier', kind='Type'), + Child('Colon', kind='ColonToken'), + Child('LayoutConstraint', kind='LayoutConstraint'), + ]), + + # layout-constraint -> + # identifier ('(' integer-literal (',' integer-literal)? ')')? + Node('LayoutConstraint', kind='Syntax', + children=[ + Child('Name', kind='IdentifierToken'), + Child('LeftParen', kind='LeftParenToken', + is_optional=True), + Child('Size', kind='IntegerLiteralToken', + is_optional=True), + Child('Comma', kind='CommaToken', + is_optional=True), + Child('Alignment', kind='IntegerLiteralToken', + is_optional=True), + Child('RightParen', kind='RightParenToken', is_optional=True), ]), ] diff --git a/utils/gyb_syntax_support/Node.py b/utils/gyb_syntax_support/Node.py index ab8320dc5765e..e60628837ed7a 100644 --- a/utils/gyb_syntax_support/Node.py +++ b/utils/gyb_syntax_support/Node.py @@ -1,5 +1,7 @@ from __future__ import print_function -import sys # noqa: I201 + +import sys + from kinds import SYNTAX_BASE_KINDS, kind_to_type, lowercase_first_word diff --git a/utils/gyb_syntax_support/NodeSerializationCodes.py b/utils/gyb_syntax_support/NodeSerializationCodes.py index d2c6fd4bdde2e..6ee6ed53b22da 100644 --- a/utils/gyb_syntax_support/NodeSerializationCodes.py +++ b/utils/gyb_syntax_support/NodeSerializationCodes.py @@ -233,18 +233,21 @@ 'PoundAssertStmt': 229, 'SomeType': 230, 'CustomAttribute': 231, + 'GenericRequirement': 232, + 'LayoutRequirement': 233, + 'LayoutConstraint': 234, # SWIFT_ENABLE_TENSORFLOW - 'DifferentiableAttributeArguments': 232, - 'DifferentiationParamsClause': 233, - 'DifferentiationParams': 234, - 'DifferentiationParamList': 235, - 'DifferentiationParam': 236, - 'DifferentiableAttributeFuncSpecifier': 237, - 'FunctionDeclName': 238, - 'DifferentiatingAttributeArguments': 239, - 'TransposingAttributeArguments': 240, - 'QuoteLiteralExpr': 241, - 'UnquoteExpr': 242, + 'DifferentiableAttributeArguments': 235, + 'DifferentiationParamsClause': 236, + 'DifferentiationParams': 237, + 'DifferentiationParamList': 238, + 'DifferentiationParam': 239, + 'DifferentiableAttributeFuncSpecifier': 240, + 'FunctionDeclName': 241, + 'DifferentiatingAttributeArguments': 242, + 'TransposingAttributeArguments': 243, + 'QuoteLiteralExpr': 244, + 'UnquoteExpr': 245, } diff --git a/utils/gyb_syntax_support/SILOnlyNodes.py b/utils/gyb_syntax_support/SILOnlyNodes.py new file mode 100644 index 0000000000000..799ca5c99ee56 --- /dev/null +++ b/utils/gyb_syntax_support/SILOnlyNodes.py @@ -0,0 +1,9 @@ +from Node import Node # noqa: I201 + +# These nodes are used only in SIL parsing. + +SILONLY_NODES = [ + # generic-parameter-clause-list + Node('GenericParameterClauseList', kind='SyntaxCollection', + element='GenericParameterClause'), +] diff --git a/utils/gyb_syntax_support/__init__.py b/utils/gyb_syntax_support/__init__.py index 6f32da7920fa7..0611331faa346 100644 --- a/utils/gyb_syntax_support/__init__.py +++ b/utils/gyb_syntax_support/__init__.py @@ -1,29 +1,57 @@ import textwrap -from AttributeNodes import ATTRIBUTE_NODES # noqa: I201 -from AvailabilityNodes import AVAILABILITY_NODES # noqa: I201 -import Classification # noqa: I201 -from CommonNodes import COMMON_NODES # noqa: I201 -from DeclNodes import DECL_NODES # noqa: I201 -from ExprNodes import EXPR_NODES # noqa: I201 -from GenericNodes import GENERIC_NODES # noqa: I201 -from NodeSerializationCodes import SYNTAX_NODE_SERIALIZATION_CODES, \ + +from . import Token +from .AttributeNodes import ATTRIBUTE_NODES +from .AvailabilityNodes import AVAILABILITY_NODES +from .Classification import SYNTAX_CLASSIFICATIONS +from .CommonNodes import COMMON_NODES +from .CompletionOnlyNodes import COMPLETIONONLY_NODES +from .DeclNodes import DECL_NODES +from .ExprNodes import EXPR_NODES +from .GenericNodes import GENERIC_NODES +from .NodeSerializationCodes import SYNTAX_NODE_SERIALIZATION_CODES, \ get_serialization_code, \ verify_syntax_node_serialization_codes - -from PatternNodes import PATTERN_NODES # noqa: I201 -from StmtNodes import STMT_NODES # noqa: I201 -import Token -from Trivia import TRIVIAS # noqa: I201 -from TypeNodes import TYPE_NODES # noqa: I201 +from .PatternNodes import PATTERN_NODES +from .SILOnlyNodes import SILONLY_NODES +from .StmtNodes import STMT_NODES +from .Token import SYNTAX_TOKENS, SYNTAX_TOKEN_MAP +from .Trivia import TRIVIAS +from .TypeNodes import TYPE_NODES + +__all__ = [ + 'Token', + 'AVAILABILITY_NODES', + 'SYNTAX_CLASSIFICATIONS', + 'COMMON_NODES', + 'DECL_NODES', + 'EXPR_NODES', + 'GENERIC_NODES', + 'SYNTAX_NODE_SERIALIZATION_CODES', + 'PATTERN_NODES', + 'PARSEONLY_NODES', + 'STMT_NODES', + 'SYNTAX_TOKENS', + 'SYNTAX_TOKEN_MAP', + 'TRIVIAS', + 'TYPE_NODES', + 'SYNTAX_NODES', + 'make_missing_child', + 'check_child_condition_raw', + 'check_parsed_child_condition_raw', + 'make_missing_swift_child', + 'create_node_map', + 'is_visitable', + 'dedented_lines', + 'calculate_node_hash', +] -# Re-export global constants SYNTAX_NODES = COMMON_NODES + EXPR_NODES + DECL_NODES + ATTRIBUTE_NODES + \ STMT_NODES + GENERIC_NODES + TYPE_NODES + PATTERN_NODES + \ AVAILABILITY_NODES -SYNTAX_TOKENS = Token.SYNTAX_TOKENS -SYNTAX_TOKEN_MAP = Token.SYNTAX_TOKEN_MAP -SYNTAX_CLASSIFICATIONS = Classification.SYNTAX_CLASSIFICATIONS + +PARSEONLY_NODES = SILONLY_NODES + COMPLETIONONLY_NODES verify_syntax_node_serialization_codes(SYNTAX_NODES, SYNTAX_NODE_SERIALIZATION_CODES) diff --git a/utils/update_checkout/update-checkout-config.json b/utils/update_checkout/update-checkout-config.json index 3e77e157b5a16..60db8f952a087 100644 --- a/utils/update_checkout/update-checkout-config.json +++ b/utils/update_checkout/update-checkout-config.json @@ -83,7 +83,7 @@ "swift-xcode-playground-support": "master", "ninja": "release", "icu": "release-61-1", - "cmake": "v3.15.0", + "cmake": "v3.15.1", "clang-tools-extra": "stable", "libcxx": "stable", "indexstore-db": "master", @@ -108,7 +108,7 @@ "swift-xcode-playground-support": "master", "ninja": "release", "icu": "release-61-1", - "cmake": "v3.15.0", + "cmake": "v3.15.1", "indexstore-db": "master", "sourcekit-lsp": "master" } @@ -135,7 +135,7 @@ "swift-xcode-playground-support": "master", "ninja": "release", "icu": "release-61-1", - "cmake": "v3.15.0", + "cmake": "v3.15.1", "clang-tools-extra": "upstream-with-swift", "libcxx": "upstream-with-swift", "indexstore-db": "master", @@ -159,7 +159,7 @@ "swift-xcode-playground-support": "master", "ninja": "release", "icu": "release-61-1", - "cmake": "v3.15.0", + "cmake": "v3.15.1", "indexstore-db": "master", "sourcekit-lsp": "master" } @@ -431,7 +431,7 @@ "swift-xcode-playground-support": "master", "ninja": "release", "icu": "release-61-1", - "cmake": "v3.15.0", + "cmake": "v3.15.1", "clang-tools-extra": "apple/stable/20190619", "libcxx": "apple/stable/20190619", "indexstore-db": "master", @@ -467,30 +467,30 @@ "tensorflow": { "aliases": ["tensorflow"], "repos": { - "llvm": "swift-DEVELOPMENT-SNAPSHOT-2019-09-16-a", + "llvm": "swift-DEVELOPMENT-SNAPSHOT-2019-09-24-a", "clang": "fcefc0babd0915287ee479d2baee5bb020de014b", "swift": "tensorflow", - "lldb": "1be6bc1723a5e68dd5d304115227d487fa242fdd", - "cmark": "swift-DEVELOPMENT-SNAPSHOT-2019-09-16-a", - "llbuild": "swift-DEVELOPMENT-SNAPSHOT-2019-09-16-a", - "swiftpm": "swift-DEVELOPMENT-SNAPSHOT-2019-09-16-a", + "lldb": "8fc11a104c0930656469442bbc059eb1a2a52955", + "cmark": "swift-DEVELOPMENT-SNAPSHOT-2019-09-24-a", + "llbuild": "swift-DEVELOPMENT-SNAPSHOT-2019-09-24-a", + "swiftpm": "swift-DEVELOPMENT-SNAPSHOT-2019-09-24-a", "swift-syntax": "adc26e4473d53e6b3e1b7945aca495595f07cc41", - "swift-stress-tester": "swift-DEVELOPMENT-SNAPSHOT-2019-09-16-a", - "compiler-rt": "swift-DEVELOPMENT-SNAPSHOT-2019-09-16-a", - "swift-corelibs-xctest": "swift-DEVELOPMENT-SNAPSHOT-2019-09-16-a", - "swift-corelibs-foundation": "swift-DEVELOPMENT-SNAPSHOT-2019-09-16-a", - "swift-corelibs-libdispatch": "swift-DEVELOPMENT-SNAPSHOT-2019-09-16-a", - "swift-integration-tests": "swift-DEVELOPMENT-SNAPSHOT-2019-09-16-a", - "swift-xcode-playground-support": "swift-DEVELOPMENT-SNAPSHOT-2019-09-16-a", + "swift-stress-tester": "swift-DEVELOPMENT-SNAPSHOT-2019-09-24-a", + "compiler-rt": "swift-DEVELOPMENT-SNAPSHOT-2019-09-24-a", + "swift-corelibs-xctest": "swift-DEVELOPMENT-SNAPSHOT-2019-09-24-a", + "swift-corelibs-foundation": "swift-DEVELOPMENT-SNAPSHOT-2019-09-24-a", + "swift-corelibs-libdispatch": "swift-DEVELOPMENT-SNAPSHOT-2019-09-24-a", + "swift-integration-tests": "swift-DEVELOPMENT-SNAPSHOT-2019-09-24-a", + "swift-xcode-playground-support": "swift-DEVELOPMENT-SNAPSHOT-2019-09-24-a", "ninja": "release", "icu": "release-61-1", - "clang-tools-extra": "swift-DEVELOPMENT-SNAPSHOT-2019-09-16-a", - "libcxx": "swift-DEVELOPMENT-SNAPSHOT-2019-09-16-a", + "clang-tools-extra": "swift-DEVELOPMENT-SNAPSHOT-2019-09-24-a", + "libcxx": "swift-DEVELOPMENT-SNAPSHOT-2019-09-24-a", "tensorflow": "7c7d924821a8b1b20433c2f3f484bbd409873a84", "tensorflow-swift-apis": "f4f88d924d71eedb0709e26d0d5e4b7cfe94d830", - "tensorflow-swift-quote": "03a61b10adfff4d08c23ed487b0a0a786932a07d", - "indexstore-db": "swift-DEVELOPMENT-SNAPSHOT-2019-09-16-a", - "sourcekit-lsp": "swift-DEVELOPMENT-SNAPSHOT-2019-09-16-a" + "tensorflow-swift-quote": "62c0a88dc64a201497a66cbbc087c0c7771edabc", + "indexstore-db": "swift-DEVELOPMENT-SNAPSHOT-2019-09-24-a", + "sourcekit-lsp": "swift-DEVELOPMENT-SNAPSHOT-2019-09-24-a" } } } diff --git a/validation-test/Sema/type_checker_crashers_fixed/rdar27830834.swift b/validation-test/Sema/type_checker_crashers_fixed/rdar27830834.swift index 49d441637fd73..1bf2e92ddc8be 100644 --- a/validation-test/Sema/type_checker_crashers_fixed/rdar27830834.swift +++ b/validation-test/Sema/type_checker_crashers_fixed/rdar27830834.swift @@ -1,4 +1,6 @@ // RUN: %target-swift-frontend %s -typecheck -verify var d = [String:String]() -_ = "\(d.map{ [$0 : $0] })" // expected-error {{generic struct 'Dictionary' requires that '(key: String, value: String)' conform to 'Hashable'}} +_ = "\(d.map{ [$0 : $0] })" +// expected-error@-1 {{type '(key: String, value: String)' cannot conform to 'Hashable'; only struct/enum/class types can conform to protocols}} +// expected-note@-2 {{required by generic struct 'Dictionary' where 'Key' = '(key: String, value: String)'}} diff --git a/validation-test/Sema/type_checker_perf/fast/array_of_tuples.swift.gyb b/validation-test/Sema/type_checker_perf/fast/array_of_tuples.swift.gyb index 9fe047a65a78d..c31af8247d186 100644 --- a/validation-test/Sema/type_checker_perf/fast/array_of_tuples.swift.gyb +++ b/validation-test/Sema/type_checker_perf/fast/array_of_tuples.swift.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --begin 1 --end 20 --step 1 --select NumLeafScopes %s -// REQUIRES: OS=macosx // REQUIRES: asserts let a = [ diff --git a/validation-test/Sema/type_checker_perf/fast/more_specialized_generic_func.swift.gyb b/validation-test/Sema/type_checker_perf/fast/more_specialized_generic_func.swift.gyb index 1b9d3284119ec..7e758774daf08 100644 --- a/validation-test/Sema/type_checker_perf/fast/more_specialized_generic_func.swift.gyb +++ b/validation-test/Sema/type_checker_perf/fast/more_specialized_generic_func.swift.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --begin 8 --end 40 --step 2 --select NumLeafScopes %s --expected-exit-code 0 -// REQUIRES: OS=macosx // REQUIRES: asserts protocol P { } diff --git a/validation-test/Sema/type_checker_perf/fast/rdar18360240.swift.gyb b/validation-test/Sema/type_checker_perf/fast/rdar18360240.swift.gyb index 421324d06cb46..48bd229c1b3e9 100644 --- a/validation-test/Sema/type_checker_perf/fast/rdar18360240.swift.gyb +++ b/validation-test/Sema/type_checker_perf/fast/rdar18360240.swift.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --begin 2 --end 10 --step 2 --select NumConstraintScopes --polynomial-threshold 1.5 %s -// REQUIRES: OS=macosx // REQUIRES: asserts let empty: [Int] = [] diff --git a/validation-test/Sema/type_checker_perf/fast/rdar18699199.swift.gyb b/validation-test/Sema/type_checker_perf/fast/rdar18699199.swift.gyb index 84870ae40e0b8..a180c0a87482b 100644 --- a/validation-test/Sema/type_checker_perf/fast/rdar18699199.swift.gyb +++ b/validation-test/Sema/type_checker_perf/fast/rdar18699199.swift.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --begin 1 --end 10 --step 1 --select NumLeafScopes %s -// REQUIRES: OS=macosx // REQUIRES: asserts public enum E { diff --git a/validation-test/Sema/type_checker_perf/fast/rdar18724501.swift.gyb b/validation-test/Sema/type_checker_perf/fast/rdar18724501.swift.gyb index 9f619473296db..65e43aece7d41 100644 --- a/validation-test/Sema/type_checker_perf/fast/rdar18724501.swift.gyb +++ b/validation-test/Sema/type_checker_perf/fast/rdar18724501.swift.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --begin 1 --end 5 --step 1 --select NumLeafScopes %s -// REQUIRES: OS=macosx // REQUIRES: asserts typealias X = (Range, [Range]) diff --git a/validation-test/Sema/type_checker_perf/fast/rdar19181998.swift.gyb b/validation-test/Sema/type_checker_perf/fast/rdar19181998.swift.gyb index 02e4f130c6507..7c23540f8ecff 100644 --- a/validation-test/Sema/type_checker_perf/fast/rdar19181998.swift.gyb +++ b/validation-test/Sema/type_checker_perf/fast/rdar19181998.swift.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --begin 1 --end 30 --step 1 --select NumLeafScopes %s -// REQUIRES: OS=macosx // REQUIRES: asserts public func test(_ fn: @escaping () -> Void) {} diff --git a/validation-test/Sema/type_checker_perf/fast/rdar19181998_nominals.swift.gyb b/validation-test/Sema/type_checker_perf/fast/rdar19181998_nominals.swift.gyb index 2b776131439b8..dd996ad7e71bf 100644 --- a/validation-test/Sema/type_checker_perf/fast/rdar19181998_nominals.swift.gyb +++ b/validation-test/Sema/type_checker_perf/fast/rdar19181998_nominals.swift.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --begin 1 --end 30 --step 1 --select NumLeafScopes %s -// REQUIRES: OS=macosx // REQUIRES: asserts struct A { diff --git a/validation-test/Sema/type_checker_perf/fast/rdar19394804.swift.gyb b/validation-test/Sema/type_checker_perf/fast/rdar19394804.swift.gyb index bb5bed290df89..1c48071767c4a 100644 --- a/validation-test/Sema/type_checker_perf/fast/rdar19394804.swift.gyb +++ b/validation-test/Sema/type_checker_perf/fast/rdar19394804.swift.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --begin 1 --end 10 --step 1 --select NumLeafScopes %s -// REQUIRES: OS=macosx // REQUIRES: asserts class rdar19394804 { diff --git a/validation-test/Sema/type_checker_perf/fast/rdar19738292.swift.gyb b/validation-test/Sema/type_checker_perf/fast/rdar19738292.swift.gyb index 7a22deabc17b8..102d3f524114b 100644 --- a/validation-test/Sema/type_checker_perf/fast/rdar19738292.swift.gyb +++ b/validation-test/Sema/type_checker_perf/fast/rdar19738292.swift.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --begin 7 --end 12 --step 1 --select NumLeafScopes %s -// REQUIRES: OS=macosx // REQUIRES: asserts // REQUIRES: rdar42650365 diff --git a/validation-test/Sema/type_checker_perf/fast/rdar19777895.swift.gyb b/validation-test/Sema/type_checker_perf/fast/rdar19777895.swift.gyb index e5d2400121f7e..cc500050b1d38 100644 --- a/validation-test/Sema/type_checker_perf/fast/rdar19777895.swift.gyb +++ b/validation-test/Sema/type_checker_perf/fast/rdar19777895.swift.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --begin 3 --end 7 --step 1 --select NumLeafScopes %s -// REQUIRES: OS=macosx // REQUIRES: asserts let _ = [ diff --git a/validation-test/Sema/type_checker_perf/fast/rdar20233198_any.swift.gyb b/validation-test/Sema/type_checker_perf/fast/rdar20233198_any.swift.gyb index 04472f4778b64..7ec93bf0406bd 100644 --- a/validation-test/Sema/type_checker_perf/fast/rdar20233198_any.swift.gyb +++ b/validation-test/Sema/type_checker_perf/fast/rdar20233198_any.swift.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --begin 2 --end 6 --step 1 --select NumLeafScopes %s -// REQUIRES: OS=macosx // REQUIRES: asserts let _ = (UInt8(0) diff --git a/validation-test/Sema/type_checker_perf/fast/rdar20233198_explicit_overloads.swift.gyb b/validation-test/Sema/type_checker_perf/fast/rdar20233198_explicit_overloads.swift.gyb index 61f4779dfa8bd..3699c5b161880 100644 --- a/validation-test/Sema/type_checker_perf/fast/rdar20233198_explicit_overloads.swift.gyb +++ b/validation-test/Sema/type_checker_perf/fast/rdar20233198_explicit_overloads.swift.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --begin 2 --end 6 --step 1 --select NumLeafScopes %s -// REQUIRES: OS=macosx // REQUIRES: asserts func overload(_ x: Int) -> Int { return x } diff --git a/validation-test/Sema/type_checker_perf/fast/rdar20233198_named.swift.gyb b/validation-test/Sema/type_checker_perf/fast/rdar20233198_named.swift.gyb index 97f6a608707a5..2fe9fc07164ae 100644 --- a/validation-test/Sema/type_checker_perf/fast/rdar20233198_named.swift.gyb +++ b/validation-test/Sema/type_checker_perf/fast/rdar20233198_named.swift.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --begin 2 --end 6 --step 1 --select NumLeafScopes %s -// REQUIRES: OS=macosx // REQUIRES: asserts let tuple = (UInt8(0) diff --git a/validation-test/Sema/type_checker_perf/fast/rdar20233198_typed.swift.gyb b/validation-test/Sema/type_checker_perf/fast/rdar20233198_typed.swift.gyb index 9590ecbc84fd7..587a19993d326 100644 --- a/validation-test/Sema/type_checker_perf/fast/rdar20233198_typed.swift.gyb +++ b/validation-test/Sema/type_checker_perf/fast/rdar20233198_typed.swift.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --begin 2 --end 6 --step 1 --select NumLeafScopes %s -// REQUIRES: OS=macosx // REQUIRES: asserts let tuple: (UInt8 diff --git a/validation-test/Sema/type_checker_perf/fast/rdar20233198_weak.swift.gyb b/validation-test/Sema/type_checker_perf/fast/rdar20233198_weak.swift.gyb index e4e5b0d9fc883..91cfd66605da9 100644 --- a/validation-test/Sema/type_checker_perf/fast/rdar20233198_weak.swift.gyb +++ b/validation-test/Sema/type_checker_perf/fast/rdar20233198_weak.swift.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --begin 2 --end 6 --step 1 --select NumLeafScopes %s -Xfrontend=-verify -// REQUIRES: OS=macosx // REQUIRES: asserts weak var tuple = (UInt8(0) // expected-error {{'weak' may only be applied to}} diff --git a/validation-test/Sema/type_checker_perf/fast/rdar20818064.swift.gyb b/validation-test/Sema/type_checker_perf/fast/rdar20818064.swift.gyb index ad2ee15ad57b2..a8384cf12eecf 100644 --- a/validation-test/Sema/type_checker_perf/fast/rdar20818064.swift.gyb +++ b/validation-test/Sema/type_checker_perf/fast/rdar20818064.swift.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --begin 1 --end 20 --step 1 --select NumLeafScopes %s -// REQUIRES: OS=macosx // REQUIRES: asserts typealias D = [String: Any] diff --git a/validation-test/Sema/type_checker_perf/fast/rdar21070413.swift.gyb b/validation-test/Sema/type_checker_perf/fast/rdar21070413.swift.gyb index 28a70a5f0eab7..15bcf460ab30a 100644 --- a/validation-test/Sema/type_checker_perf/fast/rdar21070413.swift.gyb +++ b/validation-test/Sema/type_checker_perf/fast/rdar21070413.swift.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --begin 1 --end 5 --step 1 --select NumLeafScopes %s -// REQUIRES: OS=macosx // REQUIRES: asserts enum E: UInt { diff --git a/validation-test/Sema/type_checker_perf/fast/rdar21328584.swift.gyb b/validation-test/Sema/type_checker_perf/fast/rdar21328584.swift.gyb index af07f9989aa8c..b2f38b6a691c4 100644 --- a/validation-test/Sema/type_checker_perf/fast/rdar21328584.swift.gyb +++ b/validation-test/Sema/type_checker_perf/fast/rdar21328584.swift.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --begin 1 --end 5 --step 1 --select NumLeafScopes %s -// REQUIRES: OS=macosx // REQUIRES: asserts struct S { diff --git a/validation-test/Sema/type_checker_perf/fast/rdar21720888.swift.gyb b/validation-test/Sema/type_checker_perf/fast/rdar21720888.swift.gyb index 5c6d542cb3ecf..04e7a3f8c2767 100644 --- a/validation-test/Sema/type_checker_perf/fast/rdar21720888.swift.gyb +++ b/validation-test/Sema/type_checker_perf/fast/rdar21720888.swift.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --begin 1 --end 10 --step 1 --select NumLeafScopes %s -// REQUIRES: OS=macosx // REQUIRES: asserts _ = [ diff --git a/validation-test/Sema/type_checker_perf/fast/rdar21930551.swift.gyb b/validation-test/Sema/type_checker_perf/fast/rdar21930551.swift.gyb index 23d0c00dc5bfb..95dc1cbbb589b 100644 --- a/validation-test/Sema/type_checker_perf/fast/rdar21930551.swift.gyb +++ b/validation-test/Sema/type_checker_perf/fast/rdar21930551.swift.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --begin 2 --end 6 --step 1 --select NumLeafScopes %s -// REQUIRES: OS=macosx // REQUIRES: asserts let _ = [ diff --git a/validation-test/Sema/type_checker_perf/fast/rdar22532650.swift.gyb b/validation-test/Sema/type_checker_perf/fast/rdar22532650.swift.gyb index 34d12f51a9d65..bf66800181a76 100644 --- a/validation-test/Sema/type_checker_perf/fast/rdar22532650.swift.gyb +++ b/validation-test/Sema/type_checker_perf/fast/rdar22532650.swift.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --begin 10 --end 15 --step 1 --select NumLeafScopes %s -// REQUIRES: OS=macosx // REQUIRES: asserts _ = [ diff --git a/validation-test/Sema/type_checker_perf/fast/rdar22626740.swift.gyb b/validation-test/Sema/type_checker_perf/fast/rdar22626740.swift.gyb index f30f317432b78..326a56eefa4c9 100644 --- a/validation-test/Sema/type_checker_perf/fast/rdar22626740.swift.gyb +++ b/validation-test/Sema/type_checker_perf/fast/rdar22626740.swift.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --begin 2 --end 7 --step 1 --select NumLeafScopes %s -// REQUIRES: OS=macosx // REQUIRES: asserts var a: [UInt32] diff --git a/validation-test/Sema/type_checker_perf/fast/rdar22810685.swift.gyb b/validation-test/Sema/type_checker_perf/fast/rdar22810685.swift.gyb index 7b930593549f2..5a2ce6c27b68f 100644 --- a/validation-test/Sema/type_checker_perf/fast/rdar22810685.swift.gyb +++ b/validation-test/Sema/type_checker_perf/fast/rdar22810685.swift.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --begin 1 --end 5 --step 1 --select NumLeafScopes %s -// REQUIRES: OS=macosx // REQUIRES: asserts let _: [String : (Int, Int) -> Bool] = [ diff --git a/validation-test/Sema/type_checker_perf/fast/rdar22836718.swift.gyb b/validation-test/Sema/type_checker_perf/fast/rdar22836718.swift.gyb index bd6df51b63e91..02f62caa94f33 100644 --- a/validation-test/Sema/type_checker_perf/fast/rdar22836718.swift.gyb +++ b/validation-test/Sema/type_checker_perf/fast/rdar22836718.swift.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --begin 5 --end 10 --step 1 --select NumLeafScopes %s -// REQUIRES: OS=macosx // REQUIRES: asserts let _ = [ diff --git a/validation-test/Sema/type_checker_perf/fast/rdar23327871.swift.gyb b/validation-test/Sema/type_checker_perf/fast/rdar23327871.swift.gyb index 44c40916872d5..4367249d4ee0b 100644 --- a/validation-test/Sema/type_checker_perf/fast/rdar23327871.swift.gyb +++ b/validation-test/Sema/type_checker_perf/fast/rdar23327871.swift.gyb @@ -1,7 +1,6 @@ // SWIFT_ENABLE_TENSORFLOW // UNSUPPORTED: macosx // RUN: %scale-test --begin 8 --end 16 --step 1 --select NumLeafScopes %s -// REQUIRES: OS=macosx // REQUIRES: asserts let i = 1 diff --git a/validation-test/Sema/type_checker_perf/fast/rdar24543332.swift.gyb b/validation-test/Sema/type_checker_perf/fast/rdar24543332.swift.gyb index bfb508c61ccf1..f00b13adb87a2 100644 --- a/validation-test/Sema/type_checker_perf/fast/rdar24543332.swift.gyb +++ b/validation-test/Sema/type_checker_perf/fast/rdar24543332.swift.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --begin 5 --end 20 --step 1 --select NumLeafScopes %s -// REQUIRES: OS=macosx // REQUIRES: asserts _ = [ diff --git a/validation-test/Sema/type_checker_perf/fast/rdar25866240.swift.gyb b/validation-test/Sema/type_checker_perf/fast/rdar25866240.swift.gyb index 116a4e5c14c3e..3fd0109eb5f51 100644 --- a/validation-test/Sema/type_checker_perf/fast/rdar25866240.swift.gyb +++ b/validation-test/Sema/type_checker_perf/fast/rdar25866240.swift.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --begin 2 --end 10 --step 1 --select NumConstraintScopes %s -Xfrontend=-solver-disable-shrink -Xfrontend=-disable-constraint-solver-performance-hacks -Xfrontend=-solver-enable-operator-designated-types -// REQUIRES: OS=macosx // REQUIRES: asserts func f( diff --git a/validation-test/Sema/type_checker_perf/fast/rdar26939465.swift.gyb b/validation-test/Sema/type_checker_perf/fast/rdar26939465.swift.gyb index 9d59f05d62b33..59a016b41df4a 100644 --- a/validation-test/Sema/type_checker_perf/fast/rdar26939465.swift.gyb +++ b/validation-test/Sema/type_checker_perf/fast/rdar26939465.swift.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --begin 2 --end 7 --step 1 --select NumLeafScopes %s -// REQUIRES: OS=macosx // REQUIRES: asserts class NSNumber { diff --git a/validation-test/Sema/type_checker_perf/fast/rdar29025667.swift.gyb b/validation-test/Sema/type_checker_perf/fast/rdar29025667.swift.gyb index 824a894e643cf..8fe1f3be07175 100644 --- a/validation-test/Sema/type_checker_perf/fast/rdar29025667.swift.gyb +++ b/validation-test/Sema/type_checker_perf/fast/rdar29025667.swift.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --begin 2 --end 7 --step 1 --select NumLeafScopes %s -// REQUIRES: OS=macosx // REQUIRES: asserts let s: String? = nil diff --git a/validation-test/Sema/type_checker_perf/fast/rdar29358447.swift.gyb b/validation-test/Sema/type_checker_perf/fast/rdar29358447.swift.gyb index a5d262ec37907..057403e1d69e4 100644 --- a/validation-test/Sema/type_checker_perf/fast/rdar29358447.swift.gyb +++ b/validation-test/Sema/type_checker_perf/fast/rdar29358447.swift.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --begin 0 --end 10000 --step 1000 --typecheck --select incrementConstraintsPerContractionCounter %s -// REQUIRES: OS=macosx // REQUIRES: asserts let _: [Int] = [ diff --git a/validation-test/Sema/type_checker_perf/fast/rdar30213053.swift.gyb b/validation-test/Sema/type_checker_perf/fast/rdar30213053.swift.gyb index 094690423a9c8..81e53ce17b588 100644 --- a/validation-test/Sema/type_checker_perf/fast/rdar30213053.swift.gyb +++ b/validation-test/Sema/type_checker_perf/fast/rdar30213053.swift.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --begin 3 --end 7 --step 1 --select NumLeafScopes %s -// REQUIRES: OS=macosx // REQUIRES: asserts let _: [Int: (Int, Int) -> Bool] = diff --git a/validation-test/Sema/type_checker_perf/fast/rdar30389602.swift.gyb b/validation-test/Sema/type_checker_perf/fast/rdar30389602.swift.gyb index fb2c4ac6fe951..1e41ed86f63d6 100644 --- a/validation-test/Sema/type_checker_perf/fast/rdar30389602.swift.gyb +++ b/validation-test/Sema/type_checker_perf/fast/rdar30389602.swift.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --begin 2 --end 7 --step 1 --select NumLeafScopes %s -// REQUIRES: OS=macosx // REQUIRES: asserts class C { diff --git a/validation-test/Sema/type_checker_perf/fast/rdar30729643.swift.gyb b/validation-test/Sema/type_checker_perf/fast/rdar30729643.swift.gyb index ace10b9396395..c21fa6625bc19 100644 --- a/validation-test/Sema/type_checker_perf/fast/rdar30729643.swift.gyb +++ b/validation-test/Sema/type_checker_perf/fast/rdar30729643.swift.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --begin 1 --end 15 --step 1 --select NumLeafScopes %s -// REQUIRES: OS=macosx // REQUIRES: asserts enum X : String { diff --git a/validation-test/Sema/type_checker_perf/fast/rdar31563957.swift.gyb b/validation-test/Sema/type_checker_perf/fast/rdar31563957.swift.gyb index fd9e67549224c..ee08646858f02 100644 --- a/validation-test/Sema/type_checker_perf/fast/rdar31563957.swift.gyb +++ b/validation-test/Sema/type_checker_perf/fast/rdar31563957.swift.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --begin 1 --end 5 --step 1 --select NumLeafScopes %s -// REQUIRES: OS=macosx // REQUIRES: asserts struct rdar33511986 { diff --git a/validation-test/Sema/type_checker_perf/fast/rdar32999041.swift.gyb b/validation-test/Sema/type_checker_perf/fast/rdar32999041.swift.gyb index 3c564b351f1b9..86031343e2336 100644 --- a/validation-test/Sema/type_checker_perf/fast/rdar32999041.swift.gyb +++ b/validation-test/Sema/type_checker_perf/fast/rdar32999041.swift.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --begin 3 --end 8 --step 1 --select NumLeafScopes %s -// REQUIRES: OS=macosx // REQUIRES: asserts // FIXME: https://bugs.swift.org/browse/SR-6997 // REQUIRES: SR6997 diff --git a/validation-test/Sema/type_checker_perf/fast/rdar33292740.swift.gyb b/validation-test/Sema/type_checker_perf/fast/rdar33292740.swift.gyb index 14e6245f6bc6a..259fa08e212b2 100644 --- a/validation-test/Sema/type_checker_perf/fast/rdar33292740.swift.gyb +++ b/validation-test/Sema/type_checker_perf/fast/rdar33292740.swift.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --begin 2 --end 10 --step 1 --select NumLeafScopes %s -// REQUIRES: OS=macosx // REQUIRES: asserts struct V3 { diff --git a/validation-test/Sema/type_checker_perf/fast/rdar40344044.swift.gyb b/validation-test/Sema/type_checker_perf/fast/rdar40344044.swift.gyb index 30bf0d34e0159..0fbfba34390bf 100644 --- a/validation-test/Sema/type_checker_perf/fast/rdar40344044.swift.gyb +++ b/validation-test/Sema/type_checker_perf/fast/rdar40344044.swift.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --begin 3 --end 20 --step 1 --select NumLeafScopes %s -// REQUIRES: OS=macosx // REQUIRES: asserts protocol P {} diff --git a/validation-test/Sema/type_checker_perf/fast/simd_add.gyb b/validation-test/Sema/type_checker_perf/fast/simd_add.gyb index 8bd1cf83e43ff..7b0f8ec1d1a38 100644 --- a/validation-test/Sema/type_checker_perf/fast/simd_add.gyb +++ b/validation-test/Sema/type_checker_perf/fast/simd_add.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --begin 3 --end 7 --step 1 --select NumLeafScopes %s -// REQUIRES: OS=macosx // REQUIRES: asserts func test(_ s: SIMD4, diff --git a/validation-test/Sema/type_checker_perf/slow/nil_coalescing.swift.gyb b/validation-test/Sema/type_checker_perf/slow/nil_coalescing.swift.gyb index 515a2c8a16c40..e3acfa907b095 100644 --- a/validation-test/Sema/type_checker_perf/slow/nil_coalescing.swift.gyb +++ b/validation-test/Sema/type_checker_perf/slow/nil_coalescing.swift.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --invert-result --begin 1 --end 5 --step 1 --select NumLeafScopes %s -// REQUIRES: OS=macosx // REQUIRES: asserts // REQUIRES: rdar38963783 diff --git a/validation-test/Sema/type_checker_perf/slow/rdar20959612.swift.gyb b/validation-test/Sema/type_checker_perf/slow/rdar20959612.swift.gyb index 669ebd69f7386..ad87ec01da757 100644 --- a/validation-test/Sema/type_checker_perf/slow/rdar20959612.swift.gyb +++ b/validation-test/Sema/type_checker_perf/slow/rdar20959612.swift.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --invert-result --begin 3 --end 7 --step 1 --select NumLeafScopes %s -// REQUIRES: OS=macosx // REQUIRES: asserts func curry: TypedParserResultTransferType { + public typealias Result = P + // Remove property + public let result: P +} + +public protocol ParserResult {} +public protocol StaticParser: ParserResult {} + +// Change comformance to ParserResult +public protocol TypedStaticParser: StaticParser { + // Remove type constraint + associatedtype ResultTransferType: TypedParserResultTransferType +} + +// Remove where clause +public protocol MutableSelfStaticParser: TypedStaticParser where ResultTransferType == AnyTypedParserResultTransferType { + func parseTypeVar() -> AnyTypedParserResultTransferType +} + +extension MutableSelfStaticParser { + + public func anyFunction() -> () { + let t = self.parseTypeVar + // Remove this and below + _ = t() + _ = self.parseTypeVar() + } +} diff --git a/validation-test/compiler_crashers_2/0208-sr8751.swift b/validation-test/compiler_crashers_2/0208-sr8751.swift new file mode 100644 index 0000000000000..e0018a74d0235 --- /dev/null +++ b/validation-test/compiler_crashers_2/0208-sr8751.swift @@ -0,0 +1,58 @@ +// RUN: not --crash %target-swift-frontend -emit-ir %s + +protocol TreeProtocol { + + typealias NodeProtocol = _TreeNodeProtocol + associatedtype Node : NodeProtocol where Node.Tree == Self + associatedtype NValuesTraversedBreadthFirst : Sequence = FooVals where NValuesTraversedBreadthFirst.Iterator.Element == Node.Val + + var root: Node? { get } + +} + +protocol _TreeNodeProtocol { + + associatedtype Tree : TreeProtocol where Tree.Node == Self + associatedtype Val + + var value: Val { get } + var children: [Tree.Node] { get } + +} + +struct Foo : TreeProtocol { + + struct Node : _TreeNodeProtocol { + typealias Tree = Foo + typealias Val = V + + var value: Val { + fatalError() + } + var children: [Tree.Node] { + fatalError() + } + } + + var root: Foo.Node? { + fatalError() + } + +} + +struct FooVals : Sequence { + + struct Iterator : IteratorProtocol { + + typealias Element = F.Node.Val + + mutating func next() -> F.Node.Val? { + fatalError() + } + } + + func makeIterator() -> FooVals.Iterator { + fatalError() + } + +} diff --git a/validation-test/compiler_crashers_2_fixed/0196-rdar48937223.swift b/validation-test/compiler_crashers_2_fixed/0196-rdar48937223.swift index a9a1f563ae693..c8e9979569714 100644 --- a/validation-test/compiler_crashers_2_fixed/0196-rdar48937223.swift +++ b/validation-test/compiler_crashers_2_fixed/0196-rdar48937223.swift @@ -2,10 +2,11 @@ protocol P {} -func fn(_ arg1: T, arg2: (T) -> U) {} // expected-note {{where 'U' = '()'}} +func fn(_ arg1: T, arg2: (T) -> U) {} +// expected-note@-1 {{required by global function 'fn(_:arg2:)' where 'U' = '()'}} func test(str: String) { - fn(str) { arg in // expected-error {{global function 'fn(_:arg2:)' requires that '()' conform to 'P'}} + fn(str) { arg in // expected-error {{type '()' cannot conform to 'P'; only struct/enum/class types can conform to protocols}} <#FOO#> // expected-error {{editor placeholder in source file}} } } diff --git a/validation-test/compiler_crashers_2_fixed/0206-rdar54952911.swift b/validation-test/compiler_crashers_2_fixed/0206-rdar54952911.swift new file mode 100644 index 0000000000000..7859f338b3c12 --- /dev/null +++ b/validation-test/compiler_crashers_2_fixed/0206-rdar54952911.swift @@ -0,0 +1,49 @@ +// RUN: %target-swift-frontend -emit-silgen %s +// FIXME: Get the above to pass with -emit-ir too. + +public protocol P1 { + associatedtype A1: P3 where A1.A4.A3: P6 +} + +public protocol P12 : P1 where A1: P2 {} + +public protocol P2 : P3 where A3 == S3, A4: P4 {} + +public protocol P4 : P3 where A3 == S2, A4: P5 {} + +public protocol P5: P9 where A3 == S1 {} + +public protocol P6: P11 where A2: P7 {} + +public protocol P7: P8 {} + +public protocol P8 {} + +public protocol P11 { + associatedtype A2 : P8 +} + +public struct S1 : P11 {} + +public struct S2 : P11 {} + +extension S2: P6 where A2: P7 {} + +public struct S3 : P11 {} + +public protocol P9 { + associatedtype A2: P7 + associatedtype A3: P11 where A3.A2 == A2 +} + +public protocol P3 : P9 { + associatedtype A4: P9 where A4.A2 == A2 +} + +public protocol P10 { + associatedtype A3: P11 where A3.A2: P7 +} + +public struct S4 : P10 { + public typealias A3 = T.A1.A4.A3 +} diff --git a/validation-test/compiler_crashers_fixed/00017-llvm-foldingset-llvm-attributesetnode-nodeequals.swift b/validation-test/compiler_crashers_fixed/00017-llvm-foldingset-llvm-attributesetnode-nodeequals.swift index 522e701e659fb..d58f6e86f203e 100644 --- a/validation-test/compiler_crashers_fixed/00017-llvm-foldingset-llvm-attributesetnode-nodeequals.swift +++ b/validation-test/compiler_crashers_fixed/00017-llvm-foldingset-llvm-attributesetnode-nodeequals.swift @@ -17,6 +17,7 @@ protocol BooleanProtocol { extension Bool : BooleanProtocol { var boolValue: Bool { return self } } -func f(_ b: T) { -} -f(true as BooleanProtocol) // expected-error {{protocol type 'BooleanProtocol' cannot conform to 'BooleanProtocol' because only concrete types can conform to protocols}} +func f(_ b: T) {} +// expected-note@-1 {{required by global function 'f' where 'T' = 'BooleanProtocol'}} + +f(true as BooleanProtocol) // expected-error {{value of protocol type 'BooleanProtocol' cannot conform to 'BooleanProtocol'; only struct/enum/class types can conform to protocols}} diff --git a/validation-test/compiler_scale/array_init.swift.gyb b/validation-test/compiler_scale/array_init.swift.gyb index 18d20963fbc51..5a83b378d2829 100644 --- a/validation-test/compiler_scale/array_init.swift.gyb +++ b/validation-test/compiler_scale/array_init.swift.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test -Onone --begin 0 --end 10 --step 1 --select transferNodesFromList %s -// REQUIRES: OS=macosx // REQUIRES: asserts // Test that mandatory inlining is linear on a long series of integer diff --git a/validation-test/compiler_scale/bind_extension_decl.gyb b/validation-test/compiler_scale/bind_extension_decl.gyb index d2f57412ed9d5..30c27d7ff5bd3 100644 --- a/validation-test/compiler_scale/bind_extension_decl.gyb +++ b/validation-test/compiler_scale/bind_extension_decl.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --sum-multi --begin 5 --end 16 --step 5 --select NumDeclsValidated %s -// REQUIRES: OS=macosx // REQUIRES: asserts struct Struct${N} {} diff --git a/validation-test/compiler_scale/bind_nested_extension_decl.gyb b/validation-test/compiler_scale/bind_nested_extension_decl.gyb index 2fc56a6986beb..bd1c45f7dbe9c 100644 --- a/validation-test/compiler_scale/bind_nested_extension_decl.gyb +++ b/validation-test/compiler_scale/bind_nested_extension_decl.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --sum-multi --begin 5 --end 16 --step 5 --select NumDeclsValidated %s -// REQUIRES: OS=macosx // REQUIRES: asserts struct Outer${N} { diff --git a/validation-test/compiler_scale/callee_analysis_invalidation.gyb b/validation-test/compiler_scale/callee_analysis_invalidation.gyb index dadcd4a7750d1..6bfe854f3f005 100644 --- a/validation-test/compiler_scale/callee_analysis_invalidation.gyb +++ b/validation-test/compiler_scale/callee_analysis_invalidation.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test -O --polynomial-threshold 0.2 --begin 20 --end 25 --step 1 --select computeMethodCallees %s -// REQUIRES: OS=macosx // REQUIRES: asserts class C0 { diff --git a/validation-test/compiler_scale/class_members.gyb b/validation-test/compiler_scale/class_members.gyb index 266834d2c4c1a..0c51b88398f3a 100644 --- a/validation-test/compiler_scale/class_members.gyb +++ b/validation-test/compiler_scale/class_members.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --sum-multi --begin 5 --end 16 --step 5 --select NumDeclsValidated %s -// REQUIRES: OS=macosx // REQUIRES: asserts class Class${N} { diff --git a/validation-test/compiler_scale/dynamic_lookup.gyb b/validation-test/compiler_scale/dynamic_lookup.gyb index 07bcfc3409f03..64529f676bbce 100644 --- a/validation-test/compiler_scale/dynamic_lookup.gyb +++ b/validation-test/compiler_scale/dynamic_lookup.gyb @@ -1,5 +1,4 @@ -// RUN: %scale-test --sum-multi --begin 5 --end 16 --step 5 --select Sema.IsObjCRequest -Xfrontend=-disable-objc-attr-requires-foundation-module %s -// REQUIRES: OS=macosx +// RUN: %scale-test --sum-multi --begin 5 --end 16 --step 5 --select Sema.IsObjCRequest -Xfrontend=-enable-objc-interop -Xfrontend=-disable-objc-attr-requires-foundation-module %s // REQUIRES: asserts class C${N} { diff --git a/validation-test/compiler_scale/dynamic_lookup_2.swift b/validation-test/compiler_scale/dynamic_lookup_2.swift index f34acbd597efa..5c578cf71eee8 100644 --- a/validation-test/compiler_scale/dynamic_lookup_2.swift +++ b/validation-test/compiler_scale/dynamic_lookup_2.swift @@ -1,5 +1,4 @@ -// RUN: %scale-test --sum-multi --begin 5 --end 16 --step 5 --select NumIterableDeclContextParsed -Xfrontend=-disable-objc-attr-requires-foundation-module %s -// REQUIRES: OS=macosx +// RUN: %scale-test --sum-multi --begin 5 --end 16 --step 5 --select NumIterableDeclContextParsed -Xfrontend=-enable-objc-interop -Xfrontend=-disable-objc-attr-requires-foundation-module %s // REQUIRES: asserts // Dynamic member lookup should not force delayed parsing of structs, enums or protocol @@ -16,4 +15,4 @@ class C { func f${N}(a: AnyObject) { a.isObjCMember!() -} \ No newline at end of file +} diff --git a/validation-test/compiler_scale/enum_indirect.gyb b/validation-test/compiler_scale/enum_indirect.gyb index 49990d6099bb7..7e6a8b0ae01e4 100644 --- a/validation-test/compiler_scale/enum_indirect.gyb +++ b/validation-test/compiler_scale/enum_indirect.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --sum-multi --begin 5 --end 16 --step 5 --select NumDeclsValidated %s -// REQUIRES: OS=macosx // REQUIRES: asserts indirect enum Enum${N} { diff --git a/validation-test/compiler_scale/enum_members.gyb b/validation-test/compiler_scale/enum_members.gyb index 5848eb34cfaef..9c0fc0020dcc3 100644 --- a/validation-test/compiler_scale/enum_members.gyb +++ b/validation-test/compiler_scale/enum_members.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --sum-multi --begin 5 --end 16 --step 5 --select NumDeclsValidated %s -// REQUIRES: OS=macosx // REQUIRES: asserts enum Enum${N} { diff --git a/validation-test/compiler_scale/function_bodies.gyb b/validation-test/compiler_scale/function_bodies.gyb index 4cccbbbb537fe..4abcd4136c1ee 100644 --- a/validation-test/compiler_scale/function_bodies.gyb +++ b/validation-test/compiler_scale/function_bodies.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --sum-multi --begin 5 --end 16 --step 5 --select NumFunctionsParsed %s -// REQUIRES: OS=macosx // REQUIRES: asserts func method${N}() {} diff --git a/validation-test/compiler_scale/lazy_class_props.gyb b/validation-test/compiler_scale/lazy_class_props.gyb index b16535877eac7..cef23e2eb5b8b 100644 --- a/validation-test/compiler_scale/lazy_class_props.gyb +++ b/validation-test/compiler_scale/lazy_class_props.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test -O --begin 5 --end 21 --step 5 --select StoredPropertiesRequest %s -// REQUIRES: OS=macosx // REQUIRES: asserts // // Single file with many stored properties. diff --git a/validation-test/compiler_scale/nominal_bodies.gyb b/validation-test/compiler_scale/nominal_bodies.gyb index 9cb25a3b65f02..5a0aa10dc1c04 100644 --- a/validation-test/compiler_scale/nominal_bodies.gyb +++ b/validation-test/compiler_scale/nominal_bodies.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --sum-multi --begin 5 --end 16 --step 5 --select NumIterableDeclContextParsed %s -// REQUIRES: OS=macosx // REQUIRES: asserts struct S${N} {} diff --git a/validation-test/compiler_scale/protocol_members.gyb b/validation-test/compiler_scale/protocol_members.gyb index 8553ea03b9047..b7cb34bb736ad 100644 --- a/validation-test/compiler_scale/protocol_members.gyb +++ b/validation-test/compiler_scale/protocol_members.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --sum-multi --begin 5 --end 16 --step 5 --select NumDeclsValidated %s -// REQUIRES: OS=macosx // REQUIRES: asserts protocol Protocol${N} { diff --git a/validation-test/compiler_scale/scale_neighbouring_getset.gyb b/validation-test/compiler_scale/scale_neighbouring_getset.gyb index 5b15ae82ae1de..332016b767156 100644 --- a/validation-test/compiler_scale/scale_neighbouring_getset.gyb +++ b/validation-test/compiler_scale/scale_neighbouring_getset.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --sum-multi --begin 5 --end 16 --step 5 --select NumFunctionsTypechecked %s -// REQUIRES: OS=macosx // REQUIRES: asserts struct Struct${N} { diff --git a/validation-test/compiler_scale/struct_members.gyb b/validation-test/compiler_scale/struct_members.gyb index 1a8e530917fef..cc91e3117d82f 100644 --- a/validation-test/compiler_scale/struct_members.gyb +++ b/validation-test/compiler_scale/struct_members.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --sum-multi --begin 5 --end 16 --step 5 --select NumDeclsValidated %s -// REQUIRES: OS=macosx // REQUIRES: asserts struct Struct${N} { diff --git a/validation-test/compiler_scale/struct_nested.gyb b/validation-test/compiler_scale/struct_nested.gyb index 1ee84d2d98cd9..581560371ab0b 100644 --- a/validation-test/compiler_scale/struct_nested.gyb +++ b/validation-test/compiler_scale/struct_nested.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --sum-multi --begin 5 --end 16 --step 5 --select NumDeclsValidated %s -// REQUIRES: OS=macosx // REQUIRES: asserts struct Struct${N} { diff --git a/validation-test/compiler_scale/used_conformances.gyb b/validation-test/compiler_scale/used_conformances.gyb index 333cb8224f9fe..70a6f2ed46196 100644 --- a/validation-test/compiler_scale/used_conformances.gyb +++ b/validation-test/compiler_scale/used_conformances.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --sum-multi --begin 5 --end 16 --step 5 --select NumDeclsValidated %s -// REQUIRES: OS=macosx // REQUIRES: asserts struct Generic${N} {} diff --git a/validation-test/compiler_scale/var_decl_usage_checker.swift.gyb b/validation-test/compiler_scale/var_decl_usage_checker.swift.gyb index 158eb2f333fd0..2f6d1937470ac 100644 --- a/validation-test/compiler_scale/var_decl_usage_checker.swift.gyb +++ b/validation-test/compiler_scale/var_decl_usage_checker.swift.gyb @@ -1,5 +1,4 @@ // RUN: %scale-test --begin 1 --end 5 --step 1 --select VarDeclUsageCheckerExprVisits %s -// REQUIRES: OS=macosx // REQUIRES: asserts protocol Proto {}