From 61ee9149f9b5ecb7ecfedd6b2615e034d4b964bd Mon Sep 17 00:00:00 2001 From: Dan Zheng Date: Thu, 14 Mar 2019 18:38:34 -0700 Subject: [PATCH 1/4] Introduce callables. Introduce callables: values that can be "called" like functions. Add a new `call` declaration kind to represent callable methods. --- include/swift/AST/Decl.h | 87 +++- include/swift/AST/DeclNodes.def | 3 +- include/swift/AST/DiagnosticsParse.def | 10 + include/swift/AST/DiagnosticsSema.def | 7 +- include/swift/AST/DiagnosticsSema.h | 3 +- include/swift/AST/Identifier.h | 4 +- include/swift/Demangling/DemangleNodes.def | 1 + include/swift/IDE/CodeCompletion.h | 1 + include/swift/IDE/SyntaxModel.h | 1 + include/swift/Parse/Parser.h | 8 +- lib/AST/ASTDumper.cpp | 6 + lib/AST/ASTMangler.cpp | 16 + lib/AST/ASTPrinter.cpp | 40 ++ lib/AST/ASTScope.cpp | 3 +- lib/AST/Decl.cpp | 45 ++ lib/Demangling/Demangler.cpp | 2 + lib/Demangling/NodePrinter.cpp | 5 + lib/Demangling/OldRemangler.cpp | 6 + lib/Demangling/Remangler.cpp | 5 + lib/FrontendTool/ReferenceDependencies.cpp | 1 + lib/IDE/CodeCompletion.cpp | 6 + lib/IDE/REPLCodeCompletion.cpp | 1 + lib/IRGen/GenClass.cpp | 7 + lib/IRGen/GenDecl.cpp | 4 + lib/IRGen/GenObjC.cpp | 4 + lib/IRGen/GenObjC.h | 3 + lib/Index/IndexSymbol.cpp | 4 + lib/Parse/ParseDecl.cpp | 131 +++++- lib/Parse/ParseExpr.cpp | 5 +- lib/Parse/ParsePattern.cpp | 11 +- lib/SILGen/SILGenDecl.cpp | 3 +- lib/Sema/CSApply.cpp | 34 ++ lib/Sema/CSDiag.cpp | 23 +- lib/Sema/CSSimplify.cpp | 150 +++++- lib/Sema/ConstraintLocator.cpp | 5 + lib/Sema/ConstraintLocator.h | 4 + lib/Sema/ConstraintSystem.h | 3 + lib/Sema/LookupVisibleDecls.cpp | 1 + lib/Sema/TypeCheckDecl.cpp | 59 +++ lib/Sema/TypeCheckProtocol.cpp | 3 + lib/Serialization/Serialization.cpp | 64 +++ lib/TBDGen/TBDGen.cpp | 1 + test/Parse/call_decl.swift | 90 ++++ .../complete_override.swift.response | 9 + test/Syntax/Parser/tree.swift.result | 10 +- test/decl/call/callables.swift | 63 +++ test/decl/call/generic.swift | 27 ++ test/decl/call/protocol.swift | 34 ++ .../lib/SwiftLang/SwiftLangSupport.cpp | 4 + tools/swift-ide-test/swift-ide-test.cpp | 1 + utils/gyb_sourcekit_support/UIDs.py | 2 + utils/gyb_syntax_support/DeclNodes.py | 17 + utils/gyb_syntax_support/ExprNodes.py | 1 + .../NodeSerializationCodes.py | 428 +++++++++--------- utils/gyb_syntax_support/Token.py | 1 + 55 files changed, 1217 insertions(+), 250 deletions(-) create mode 100644 test/Parse/call_decl.swift create mode 100644 test/decl/call/callables.swift create mode 100644 test/decl/call/generic.swift create mode 100644 test/decl/call/protocol.swift diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index 4e79a449fdf1f..995ca22f8d3df 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -54,6 +54,7 @@ namespace swift { struct ASTNode; class ASTPrinter; class ASTWalker; + class CallDecl; class ConstructorDecl; class DestructorDecl; class DiagnosticEngine; @@ -137,6 +138,7 @@ enum class DescriptiveDeclKind : uint8_t { GenericStruct, GenericClass, GenericType, + Call, Subscript, Constructor, Destructor, @@ -3296,6 +3298,21 @@ class NominalTypeDecl : public GenericTypeDecl, public IterableDeclContext { ToStoredPropertyOrMissingMemberPlaceholder()); } +private: + /// Predicate used to filter CallDeclRange. + struct ToCallDecl { + ToCallDecl() {} + Optional operator()(Decl *decl) const; + }; + +public: + /// A range for iterating the call declarations of a nominal type. + using CallDeclRange = OptionalTransformRange; + + /// Return a collection of the call declarations of this nominal type. + CallDeclRange getCallDeclarations() const; + // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return D->getKind() >= DeclKind::First_NominalTypeDecl && @@ -5732,7 +5749,8 @@ class FuncDecl : public AbstractFunctionDecl { static bool classof(const Decl *D) { return D->getKind() == DeclKind::Func || - D->getKind() == DeclKind::Accessor; + D->getKind() == DeclKind::Accessor || + D->getKind() == DeclKind::Call; } static bool classof(const AbstractFunctionDecl *D) { return classof(static_cast(D)); @@ -5885,7 +5903,53 @@ AbstractStorageDecl::AccessorRecord::getAccessor(AccessorKind kind) const { } return nullptr; } - + +/// CallDecl - Declares a callable method for a type. For example: +/// +/// \code +/// struct Adder { +/// var base: Int +/// call(_ x: Int) -> Int { +/// return base + x +/// } +/// } +/// \endcode +class CallDecl final : public FuncDecl { + CallDecl(DeclName fullName, SourceLoc declLoc, bool throws, + SourceLoc throwsLoc, unsigned numParameterLists, + GenericParamList *genericParams, DeclContext *parent) + : FuncDecl(DeclKind::Call, + /*staticLoc*/ SourceLoc(), StaticSpellingKind::None, + /*func loc*/ declLoc, /*name*/ fullName, /*name loc*/ declLoc, + throws, throwsLoc, numParameterLists, genericParams, parent) {} + + static CallDecl *createImpl(ASTContext &ctx, DeclName fullName, + SourceLoc declLoc, bool throws, + SourceLoc throwsLoc, + GenericParamList *genericParams, + DeclContext *parent, ClangNode clangNode); + +public: + static CallDecl *create(ASTContext &ctx, DeclName fullName, SourceLoc declLoc, + bool throws, SourceLoc throwsLoc, + GenericParamList *genericParams, + ParameterList *parameterList, + TypeLoc fnRetType, DeclContext *parent, + ClangNode clangNode = ClangNode()); + + static bool classof(const Decl *D) { + return D->getKind() == DeclKind::Call; + } + static bool classof(const AbstractFunctionDecl *D) { + return classof(static_cast(D)); + } + static bool classof(const DeclContext *DC) { + if (auto D = DC->getAsDecl()) + return classof(D); + return false; + } +}; + /// This represents a 'case' declaration in an 'enum', which may declare /// one or more individual comma-separated EnumElementDecls. class EnumCaseDecl final : public Decl, @@ -6775,6 +6839,13 @@ ::operator()(Decl *decl) const { return None; } +inline Optional +NominalTypeDecl::ToCallDecl::operator()(Decl *decl) const { + if (auto callDecl = dyn_cast(decl)) + return callDecl; + return None; +} + inline void AbstractStorageDecl::overwriteSetterAccess(AccessLevel accessLevel) { Accessors.setInt(accessLevel); @@ -6808,6 +6879,7 @@ inline ParamDecl **AbstractFunctionDecl::getImplicitSelfDeclStorage() { return cast(this)->getImplicitSelfDeclStorage(); case DeclKind::Func: case DeclKind::Accessor: + case DeclKind::Call: return cast(this)->getImplicitSelfDeclStorage(); } } @@ -6816,11 +6888,12 @@ inline ParamDecl **FuncDecl::getImplicitSelfDeclStorage() { if (!hasImplicitSelfDecl()) return nullptr; - if (!isa(this)) { - assert(getKind() == DeclKind::Func && "no new kinds of functions"); - return reinterpret_cast(this+1); - } - return reinterpret_cast(static_cast(this)+1); + if (isa(this)) + return reinterpret_cast(static_cast(this)+1); + else if (isa(this)) + return reinterpret_cast(static_cast(this)+1); + assert(getKind() == DeclKind::Func && "no new kinds of functions"); + return reinterpret_cast(this+1); } inline DeclIterator &DeclIterator::operator++() { diff --git a/include/swift/AST/DeclNodes.def b/include/swift/AST/DeclNodes.def index 5aeef91652096..a743dcd91ecd9 100644 --- a/include/swift/AST/DeclNodes.def +++ b/include/swift/AST/DeclNodes.def @@ -170,7 +170,8 @@ ABSTRACT_DECL(Value, Decl) ABSTRACT_FUNCTION_DECL(Destructor, AbstractFunctionDecl) ABSTRACT_FUNCTION_DECL(Func, AbstractFunctionDecl) ABSTRACT_FUNCTION_DECL(Accessor, FuncDecl) - DECL_RANGE(AbstractFunction, Constructor, Accessor) + ABSTRACT_FUNCTION_DECL(Call, FuncDecl) + DECL_RANGE(AbstractFunction, Constructor, Call) CONTEXT_VALUE_DECL(EnumElement, ValueDecl) DECL_RANGE(Value, Enum, EnumElement) diff --git a/include/swift/AST/DiagnosticsParse.def b/include/swift/AST/DiagnosticsParse.def index fac18957f641b..cef196019dcdb 100644 --- a/include/swift/AST/DiagnosticsParse.def +++ b/include/swift/AST/DiagnosticsParse.def @@ -395,6 +395,16 @@ ERROR(subscript_without_get,none, ERROR(subscript_static,none, "subscript cannot be marked %0", (StaticSpellingKind)) +// `call` member +ERROR(call_decl_static,none, + "'call' member cannot be marked %0", (StaticSpellingKind)) +ERROR(call_decl_wrong_scope,none, + "'call' members may only be declared within a type", ()) +ERROR(expected_lparen_call,PointsToFirstBadToken, + "expected '(' for 'call' member parameters", ()) +ERROR(call_decl_cannot_have_name,PointsToFirstBadToken, + "'call' member cannot have a name", ()) + // initializer ERROR(invalid_nested_init,none, "missing '%select{super.|self.}0' at initializer invocation", (bool)) diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 5c78748ebcc89..ccc7d72958865 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -1051,6 +1051,9 @@ NOTE(archetype_declared_in_type,none, NOTE(unbound_generic_parameter_explicit_fix,none, "explicitly specify the generic arguments to fix this issue", ()) +ERROR(missing_call_decl,none, + "%0 does not define 'call' declaration of type", (Type)) + ERROR(invalid_dynamic_callable_type,none, "@dynamicCallable attribute requires %0 to have either a valid " "'dynamicallyCall(withArguments:)' method or " @@ -1765,8 +1768,8 @@ NOTE(inherited_protocol_does_not_conform,none, "type %0 does not conform to inherited protocol %1", (Type, Type)) NOTE(no_witnesses,none, "protocol requires " - "%select{initializer %1|function %1|property %1|subscript}0 with type %2" - "%select{|; do you want to add a stub?}3", + "%select{initializer %1|function %1|property %1|subscript|'call' member}0 " + "with type %2%select{|; do you want to add a stub?}3", (RequirementKind, DeclName, Type, bool)) NOTE(missing_witnesses_general,none, "do you want to add protocol stubs?", ()) diff --git a/include/swift/AST/DiagnosticsSema.h b/include/swift/AST/DiagnosticsSema.h index 801ff6f387687..98ad9a2371234 100644 --- a/include/swift/AST/DiagnosticsSema.h +++ b/include/swift/AST/DiagnosticsSema.h @@ -29,7 +29,8 @@ namespace swift { Constructor, Func, Var, - Subscript + Subscript, + Call }; // Declare common diagnostics objects with their appropriate types. diff --git a/include/swift/AST/Identifier.h b/include/swift/AST/Identifier.h index b799935cbecbd..4840d45b5872e 100644 --- a/include/swift/AST/Identifier.h +++ b/include/swift/AST/Identifier.h @@ -221,8 +221,8 @@ class DeclBaseName { }; private: - /// In a special DeclName represenenting a subscript, this opaque pointer - /// is used as the data of the base name identifier. + /// In a special DeclName representing a subscript, this opaque pointer is + /// used as the data of the base name identifier. /// This is an implementation detail that should never leak outside of /// DeclName. static void *SubscriptIdentifierData; diff --git a/include/swift/Demangling/DemangleNodes.def b/include/swift/Demangling/DemangleNodes.def index 3c0c6d693bfbe..41335ebe9ae06 100644 --- a/include/swift/Demangling/DemangleNodes.def +++ b/include/swift/Demangling/DemangleNodes.def @@ -43,6 +43,7 @@ NODE(BoundGenericOtherNominalType) NODE(BoundGenericTypeAlias) NODE(BoundGenericFunction) NODE(BuiltinTypeName) +CONTEXT_NODE(CallDeclaration) NODE(CFunctionPointer) CONTEXT_NODE(Class) NODE(ClassMetadataBaseOffset) diff --git a/include/swift/IDE/CodeCompletion.h b/include/swift/IDE/CodeCompletion.h index 5cfa91ebb0af5..5814d00c22ca2 100644 --- a/include/swift/IDE/CodeCompletion.h +++ b/include/swift/IDE/CodeCompletion.h @@ -398,6 +398,7 @@ enum class CodeCompletionDeclKind { Constructor, Destructor, Subscript, + Call, StaticMethod, InstanceMethod, PrefixOperatorFunction, diff --git a/include/swift/IDE/SyntaxModel.h b/include/swift/IDE/SyntaxModel.h index c3049006e1184..7d1cebfb0bbc1 100644 --- a/include/swift/IDE/SyntaxModel.h +++ b/include/swift/IDE/SyntaxModel.h @@ -97,6 +97,7 @@ enum class SyntaxStructureKind : uint8_t { EnumElement, TypeAlias, Subscript, + Call, AssociatedType, GenericTypeParam, diff --git a/include/swift/Parse/Parser.h b/include/swift/Parse/Parser.h index 5eae8ef8ff6f5..f5f77db01c1e3 100644 --- a/include/swift/Parse/Parser.h +++ b/include/swift/Parse/Parser.h @@ -520,7 +520,8 @@ class Parser { } SourceLoc consumeIdentifier(Identifier *Result = nullptr) { - assert(Tok.isAny(tok::identifier, tok::kw_self, tok::kw_Self)); + assert(Tok.isAny(tok::identifier, tok::kw_self, tok::kw_Self, + tok::kw_call)); if (Result) *Result = Context.getIdentifier(Tok.getText()); return consumeToken(); @@ -1005,6 +1006,8 @@ class Parser { ParserResult parseDeclProtocol(ParseDeclOptions Flags, DeclAttributes &Attributes); + ParserResult + parseDeclCall(ParseDeclOptions Flags, DeclAttributes &Attributes); ParserResult parseDeclSubscript(ParseDeclOptions Flags, DeclAttributes &Attributes, SmallVectorImpl &Decls); @@ -1160,6 +1163,8 @@ class Parser { Closure, /// A subscript. Subscript, + /// A call declaration. + Call, /// A curried argument clause. Curried, /// An enum element. @@ -1198,6 +1203,7 @@ class Parser { DefaultArgumentInfo &defaultArgs); ParserStatus parseFunctionSignature(Identifier functionName, DeclName &fullName, + ParameterContextKind paramContext, ParameterList *&bodyParams, DefaultArgumentInfo &defaultArgs, SourceLoc &throws, diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index 7bf103f3dcd78..248e481d94ed6 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -1054,6 +1054,12 @@ namespace { PrintWithColorRAII(OS, ParenthesisColor) << ')'; } + void visitCallDecl(CallDecl *CD) { + printCommonAFD(CD, "call_decl"); + printAbstractFunctionDecl(CD); + PrintWithColorRAII(OS, ParenthesisColor) << ')'; + } + void visitAccessorDecl(AccessorDecl *AD) { printCommonFD(AD, "accessor_decl"); OS << " " << getAccessorKindString(AD->getAccessorKind()); diff --git a/lib/AST/ASTMangler.cpp b/lib/AST/ASTMangler.cpp index 3dba06fab00c3..5c7094dfcf1d7 100644 --- a/lib/AST/ASTMangler.cpp +++ b/lib/AST/ASTMangler.cpp @@ -2361,6 +2361,22 @@ void ASTMangler::appendEntity(const ValueDecl *decl) { getCodeForAccessorKind(accessor->getAccessorKind()), accessor->getStorage(), accessor->isStatic()); } + // Handle call declarations specially, they are mangled as modifiers on the + // accessed declaration. + if (auto callDecl = dyn_cast(decl)) { + appendContextOf(decl); + bindGenericParameters(decl->getDeclContext()); + appendDeclType(decl); + StringRef privateDiscriminator = getPrivateDiscriminatorIfNecessary(decl); + if (!privateDiscriminator.empty()) { + appendIdentifier(privateDiscriminator); + appendOperator("Ll"); + } + appendOperator("fF"); + if (callDecl->isStatic()) + appendOperator("Z"); + return; + } if (auto storageDecl = dyn_cast(decl)) return appendAccessorEntity("p", storageDecl, decl->isStatic()); diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index 208f7c38b5707..ac89aa0269f89 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -2939,6 +2939,46 @@ void PrintAST::visitDestructorDecl(DestructorDecl *decl) { printBodyIfNecessary(decl); } +void PrintAST::visitCallDecl(CallDecl *decl) { + printDocumentationComment(decl); + printAttributes(decl); + printAccess(decl); + printContextIfNeeded(decl); + recordDeclLoc(decl, [&]{ + Printer << "call"; + }, [&] { // Parameters + printGenericDeclGenericParams(decl); + printFunctionParameters(decl); + }); + Printer << " -> "; + + Printer.callPrintStructurePre(PrintStructureKind::FunctionReturnType); + Type ResultTy = decl->getResultInterfaceType(); + if (ResultTy && !ResultTy->isVoid()) { + TypeLoc ResultTyLoc = decl->getBodyResultTypeLoc(); + if (!ResultTyLoc.getTypeRepr()) + ResultTyLoc = TypeLoc::withoutLoc(ResultTy); + // FIXME: Hacky way to workaround the fact that 'Self' as return + // TypeRepr is not getting 'typechecked'. See + // \c resolveTopLevelIdentTypeComponent function in TypeCheckType.cpp. + if (auto *simId = dyn_cast_or_null(ResultTyLoc.getTypeRepr())) { + if (simId->getIdentifier().str() == "Self") + ResultTyLoc = TypeLoc::withoutLoc(ResultTy); + } + Printer << " -> "; + Printer.callPrintStructurePre(PrintStructureKind::FunctionReturnType); + if (decl->getAttrs().hasAttribute()) + printTypeLocForImplicitlyUnwrappedOptional(ResultTyLoc); + else + printTypeLoc(ResultTyLoc); + Printer.printStructurePost(PrintStructureKind::FunctionReturnType); + } + printGenericDeclGenericRequirements(decl); + Printer.printStructurePost(PrintStructureKind::FunctionReturnType); + printGenericDeclGenericRequirements(decl); + printBodyIfNecessary(decl); +} + void PrintAST::visitInfixOperatorDecl(InfixOperatorDecl *decl) { Printer.printKeyword("infix", Options, " "); Printer << tok::kw_operator << " "; diff --git a/lib/AST/ASTScope.cpp b/lib/AST/ASTScope.cpp index 677d1401210a3..7155490d276f6 100644 --- a/lib/AST/ASTScope.cpp +++ b/lib/AST/ASTScope.cpp @@ -918,7 +918,8 @@ ASTScope *ASTScope::createIfNeeded(const ASTScope *parent, Decl *decl) { case DeclKind::Func: case DeclKind::Accessor: case DeclKind::Constructor: - case DeclKind::Destructor: { + case DeclKind::Destructor: + case DeclKind::Call: { auto abstractFunction = cast(decl); // If we have a generic function and our parent isn't describing our generic diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index d2bab37ea331c..ad51923995cb9 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -150,6 +150,7 @@ DescriptiveDeclKind Decl::getDescriptiveKind() const { TRIVIAL_KIND(GenericTypeParam); TRIVIAL_KIND(AssociatedType); TRIVIAL_KIND(Protocol); + TRIVIAL_KIND(Call); TRIVIAL_KIND(Subscript); TRIVIAL_KIND(Constructor); TRIVIAL_KIND(Destructor); @@ -278,6 +279,7 @@ StringRef Decl::getDescriptiveKindName(DescriptiveDeclKind K) { ENTRY(GenericStruct, "generic struct"); ENTRY(GenericClass, "generic class"); ENTRY(GenericType, "generic type"); + ENTRY(Call, "call method"); ENTRY(Subscript, "subscript"); ENTRY(Constructor, "initializer"); ENTRY(Destructor, "deinitializer"); @@ -888,6 +890,7 @@ ImportKind ImportDecl::getBestImportKind(const ValueDecl *VD) { case DeclKind::Constructor: case DeclKind::Destructor: case DeclKind::GenericTypeParam: + case DeclKind::Call: case DeclKind::Subscript: case DeclKind::EnumElement: case DeclKind::Param: @@ -2013,6 +2016,10 @@ bool ValueDecl::isInstanceMember() const { // enum elements and function parameters are not instance members. return false; + case DeclKind::Call: + // Call declarations are always instance members. + return true; + case DeclKind::Subscript: // Subscripts are always instance members. return true; @@ -3209,6 +3216,10 @@ auto NominalTypeDecl::getStoredProperties(bool skipInaccessible) const ToStoredProperty(skipInaccessible)); } +auto NominalTypeDecl::getCallDeclarations() const -> CallDeclRange { + return CallDeclRange(getMembers(), ToCallDecl()); +} + bool NominalTypeDecl::isOptionalDecl() const { return this == getASTContext().getOptionalDecl(); } @@ -6094,6 +6105,40 @@ bool FuncDecl::isBinaryOperator() const { !params->get(1)->isVariadic(); } +CallDecl *CallDecl::createImpl(ASTContext &ctx, DeclName name, + SourceLoc declLoc, bool throws, + SourceLoc throwsLoc, + GenericParamList *genericParams, + DeclContext *parent, ClangNode clangNode) { + bool hasImplicitSelfDecl = parent->isTypeContext(); + size_t size = sizeof(CallDecl) + (hasImplicitSelfDecl + ? sizeof(ParamDecl *) + : 0); + void *buffer = + allocateMemoryForDecl(ctx, size, !clangNode.isNull()); + auto *D = ::new (buffer) + CallDecl(name, declLoc, throws, throwsLoc, hasImplicitSelfDecl, + genericParams, parent); + if (clangNode) + D->setClangNode(clangNode); + if (hasImplicitSelfDecl) + *D->getImplicitSelfDeclStorage() = nullptr; + + return D; +} + +CallDecl *CallDecl::create(ASTContext &ctx, DeclName name, SourceLoc declLoc, + bool throws, SourceLoc throwsLoc, + GenericParamList *genericParams, + ParameterList *bodyParams, TypeLoc fnRetType, + DeclContext *parent, ClangNode clangNode) { + auto *D = CallDecl::createImpl( + ctx, name, declLoc, throws, throwsLoc, genericParams, parent, clangNode); + D->setParameters(bodyParams); + D->getBodyResultTypeLoc() = fnRetType; + return D; +} + ConstructorDecl::ConstructorDecl(DeclName Name, SourceLoc ConstructorLoc, OptionalTypeKind Failability, SourceLoc FailabilityLoc, diff --git a/lib/Demangling/Demangler.cpp b/lib/Demangling/Demangler.cpp index 2280edd665a5c..86397a1705f3e 100644 --- a/lib/Demangling/Demangler.cpp +++ b/lib/Demangling/Demangler.cpp @@ -2829,6 +2829,8 @@ NodePointer Demangler::demangleFunctionEntity() { Args = TypeAndMaybePrivateName; Kind = Node::Kind::Allocator; break; case 'c': Args = TypeAndMaybePrivateName; Kind = Node::Kind::Constructor; break; + case 'F': + Args = TypeAndMaybePrivateName; Kind = Node::Kind::CallDeclaration; break; case 'U': Args = TypeAndIndex; Kind = Node::Kind::ExplicitClosure; break; case 'u': Args = TypeAndIndex; Kind = Node::Kind::ImplicitClosure; break; case 'A': Args = Index; Kind = Node::Kind::DefaultArgumentInitializer; break; diff --git a/lib/Demangling/NodePrinter.cpp b/lib/Demangling/NodePrinter.cpp index 6878925cd079a..597f952443442 100644 --- a/lib/Demangling/NodePrinter.cpp +++ b/lib/Demangling/NodePrinter.cpp @@ -324,6 +324,7 @@ class NodePrinter { case Node::Kind::AutoClosureType: case Node::Kind::BaseConformanceDescriptor: case Node::Kind::BaseWitnessTableAccessor: + case Node::Kind::CallDeclaration: case Node::Kind::ClassMetadataBaseOffset: case Node::Kind::CFunctionPointer: case Node::Kind::Constructor: @@ -1068,6 +1069,10 @@ NodePointer NodePrinter::print(NodePointer Node, bool asPrefixContext) { return printEntity(Node, asPrefixContext, TypePrinting::FunctionStyle, /*hasName*/false, /*ExtraName*/"", /*ExtraIndex*/-1, "subscript"); + case Node::Kind::CallDeclaration: + return printEntity(Node, asPrefixContext, TypePrinting::FunctionStyle, + /*hasName*/false, /*ExtraName*/"", /*ExtraIndex*/-1, + "call"); case Node::Kind::GenericTypeParamDecl: return printEntity(Node, asPrefixContext, TypePrinting::NoType, /*hasName*/true); diff --git a/lib/Demangling/OldRemangler.cpp b/lib/Demangling/OldRemangler.cpp index aca002f21c41a..460b1a857965b 100644 --- a/lib/Demangling/OldRemangler.cpp +++ b/lib/Demangling/OldRemangler.cpp @@ -740,6 +740,12 @@ void Remangler::mangleFunction(Node *node, EntityContext &ctx) { mangleNamedAndTypedEntity(node, 'F', "", ctx); } +void Remangler::mangleCallDeclaration(Node *node, EntityContext &ctx) { + Buffer << 'F'; + mangleEntityContext(node->getChild(0), ctx); + Buffer << 'F'; +} + void Remangler::mangleVariable(Node *node, EntityContext &ctx) { mangleNamedAndTypedEntity(node, 'v', "", ctx); } diff --git a/lib/Demangling/Remangler.cpp b/lib/Demangling/Remangler.cpp index 6f1170976ea09..018836543abd6 100644 --- a/lib/Demangling/Remangler.cpp +++ b/lib/Demangling/Remangler.cpp @@ -779,6 +779,11 @@ void Remangler::mangleConstructor(Node *node) { mangleAnyConstructor(node, 'c'); } +void Remangler::mangleCallDeclaration(Node *node) { + mangleChildNodes(node); + Buffer << "fF"; +} + void Remangler::mangleCoroutineContinuationPrototype(Node *node) { mangleChildNodes(node); Buffer << "TC"; diff --git a/lib/FrontendTool/ReferenceDependencies.cpp b/lib/FrontendTool/ReferenceDependencies.cpp index f4cce1d1d93f2..129f7c70689f2 100644 --- a/lib/FrontendTool/ReferenceDependencies.cpp +++ b/lib/FrontendTool/ReferenceDependencies.cpp @@ -307,6 +307,7 @@ void ProvidesEmitter::emitTopLevelDecl(const Decl *const D, case DeclKind::GenericTypeParam: case DeclKind::AssociatedType: case DeclKind::Param: + case DeclKind::Call: case DeclKind::Subscript: case DeclKind::Constructor: case DeclKind::Destructor: diff --git a/lib/IDE/CodeCompletion.cpp b/lib/IDE/CodeCompletion.cpp index e9ab698da0252..baf0f6faf487f 100644 --- a/lib/IDE/CodeCompletion.cpp +++ b/lib/IDE/CodeCompletion.cpp @@ -557,6 +557,8 @@ CodeCompletionResult::getCodeCompletionDeclKind(const Decl *D) { return CodeCompletionDeclKind::PrecedenceGroup; case DeclKind::EnumElement: return CodeCompletionDeclKind::EnumElement; + case DeclKind::Call: + return CodeCompletionDeclKind::Call; case DeclKind::Subscript: return CodeCompletionDeclKind::Subscript; } @@ -599,6 +601,9 @@ void CodeCompletionResult::print(raw_ostream &OS) const { case CodeCompletionDeclKind::Destructor: Prefix.append("[Destructor]"); break; + case CodeCompletionDeclKind::Call: + Prefix.append("[Call]"); + break; case CodeCompletionDeclKind::Subscript: Prefix.append("[Subscript]"); break; @@ -5398,6 +5403,7 @@ void swift::ide::copyCodeCompletionResults(CodeCompletionResultSink &targetSink, case CodeCompletionDeclKind::Constructor: case CodeCompletionDeclKind::Destructor: case CodeCompletionDeclKind::Subscript: + case CodeCompletionDeclKind::Call: case CodeCompletionDeclKind::StaticMethod: case CodeCompletionDeclKind::InstanceMethod: case CodeCompletionDeclKind::PrefixOperatorFunction: diff --git a/lib/IDE/REPLCodeCompletion.cpp b/lib/IDE/REPLCodeCompletion.cpp index fa971e0c73fd4..4a50f7e4b46ef 100644 --- a/lib/IDE/REPLCodeCompletion.cpp +++ b/lib/IDE/REPLCodeCompletion.cpp @@ -120,6 +120,7 @@ static void toDisplayString(CodeCompletionResult *Result, continue; case CodeCompletionDeclKind::Subscript: + case CodeCompletionDeclKind::Call: case CodeCompletionDeclKind::StaticMethod: case CodeCompletionDeclKind::InstanceMethod: case CodeCompletionDeclKind::PrefixOperatorFunction: diff --git a/lib/IRGen/GenClass.cpp b/lib/IRGen/GenClass.cpp index b18eafd5e3b78..bb598123f68fd 100644 --- a/lib/IRGen/GenClass.cpp +++ b/lib/IRGen/GenClass.cpp @@ -1442,6 +1442,13 @@ namespace { getMethodList(constructor).push_back(constructor); } + /// Call methods need to be collected into the appropriate methods list. + void visitCallDecl(CallDecl *method) { + if (!isBuildingProtocol() && !requiresObjCMethodDescriptor(method)) + return; + getMethodList(method).push_back(method); + } + /// Determine whether the given destructor has an Objective-C /// definition. bool hasObjCDeallocDefinition(DestructorDecl *destructor) { diff --git a/lib/IRGen/GenDecl.cpp b/lib/IRGen/GenDecl.cpp index 0a6b6f59397cf..ffa7394ba77d5 100644 --- a/lib/IRGen/GenDecl.cpp +++ b/lib/IRGen/GenDecl.cpp @@ -1717,6 +1717,9 @@ void IRGenModule::emitGlobalDecl(Decl *D) { case DeclKind::Param: llvm_unreachable("there are no global function parameters"); + case DeclKind::Call: + llvm_unreachable("there are no global callable methods"); + case DeclKind::Subscript: llvm_unreachable("there are no global subscript operations"); @@ -3665,6 +3668,7 @@ void IRGenModule::emitNestedTypeDecls(DeclRange members) { continue; case DeclKind::Var: + case DeclKind::Call: case DeclKind::Subscript: case DeclKind::PatternBinding: case DeclKind::Func: diff --git a/lib/IRGen/GenObjC.cpp b/lib/IRGen/GenObjC.cpp index 1a6f99b36babf..d013f0a2899f6 100644 --- a/lib/IRGen/GenObjC.cpp +++ b/lib/IRGen/GenObjC.cpp @@ -1395,6 +1395,10 @@ bool irgen::requiresObjCMethodDescriptor(ConstructorDecl *constructor) { return constructor->isObjC(); } +bool irgen::requiresObjCMethodDescriptor(CallDecl *method) { + return method->isObjC(); +} + bool irgen::requiresObjCPropertyDescriptor(IRGenModule &IGM, VarDecl *property) { // Don't generate a descriptor for a property without any accessors. diff --git a/lib/IRGen/GenObjC.h b/lib/IRGen/GenObjC.h index aa396df7c7e70..9928689970f02 100644 --- a/lib/IRGen/GenObjC.h +++ b/lib/IRGen/GenObjC.h @@ -199,6 +199,9 @@ namespace irgen { /// True if the FuncDecl requires an ObjC method descriptor. bool requiresObjCMethodDescriptor(FuncDecl *method); + /// True if the CallDecl requires an ObjC method descriptor. + bool requiresObjCMethodDescriptor(CallDecl *method); + /// True if the ConstructorDecl requires an ObjC method descriptor. bool requiresObjCMethodDescriptor(ConstructorDecl *constructor); diff --git a/lib/Index/IndexSymbol.cpp b/lib/Index/IndexSymbol.cpp index bef053624bade..2038561ba12df 100644 --- a/lib/Index/IndexSymbol.cpp +++ b/lib/Index/IndexSymbol.cpp @@ -199,6 +199,10 @@ SymbolInfo index::getSymbolInfoForDecl(const Decl *D) { info.Kind = SymbolKind::InstanceProperty; info.SubKind = SymbolSubKind::SwiftSubscript; break; + case DeclKind::Call: + info.Kind = SymbolKind::InstanceProperty; + info.SubKind = SymbolSubKind::SwiftCall; + break; case DeclKind::Constructor: info.Kind = SymbolKind::Constructor; break; case DeclKind::Destructor: info.Kind = SymbolKind::Destructor; break; case DeclKind::Param: diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 7ac1dc4176989..36d848ff85eee 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -2868,6 +2868,17 @@ Parser::parseDecl(ParseDeclOptions Flags, StaticLoc = SourceLoc(); // we handled static if present. MayNeedOverrideCompletion = true; break; + case tok::kw_call: + // Collect all modifiers into a modifier list. + DeclParsingContext.setCreateSyntax(SyntaxKind::CallDecl); + if (StaticLoc.isValid()) { + diagnose(Tok, diag::call_decl_static, StaticSpelling) + .fixItRemove(SourceRange(StaticLoc)); + StaticLoc = SourceLoc(); + } + DeclResult = parseDeclCall(Flags, Attributes); + MayNeedOverrideCompletion = true; + break; case tok::kw_subscript: { DeclParsingContext.setCreateSyntax(SyntaxKind::SubscriptDecl); if (StaticLoc.isValid()) { @@ -2950,6 +2961,7 @@ Parser::parseDecl(ParseDeclOptions Flags, SourceLoc introducerLoc; switch (OrigTok.getKind()) { case tok::kw_func: + case tok::kw_call: case tok::kw_subscript: case tok::kw_var: case tok::kw_let: @@ -3324,7 +3336,7 @@ parseIdentifierDeclName(Parser &P, Identifier &Result, SourceLoc &Loc, StringRef DeclKindName, tok ResyncT1, tok ResyncT2, tok ResyncT3, tok ResyncT4, TokenProperty ResyncP1) { - if (P.Tok.is(tok::identifier)) { + if (P.Tok.is(tok::identifier) || P.Tok.is(tok::kw_call)) { Loc = P.consumeIdentifier(&Result); // We parsed an identifier for the declaration. If we see another @@ -5519,9 +5531,11 @@ Parser::parseDeclFunc(SourceLoc StaticLoc, StaticSpellingKind StaticSpelling, ParameterList *BodyParams; SourceLoc throwsLoc; bool rethrows; + ParameterContextKind paramContext = SimpleName.isOperator() ? + ParameterContextKind::Operator : ParameterContextKind::Function; ParserStatus SignatureStatus = - parseFunctionSignature(SimpleName, FullName, BodyParams, DefaultArgs, - throwsLoc, rethrows, FuncRetTy); + parseFunctionSignature(SimpleName, FullName, paramContext, BodyParams, + DefaultArgs, throwsLoc, rethrows, FuncRetTy); SignatureHasCodeCompletion |= SignatureStatus.hasCodeCompletion(); if (SignatureStatus.hasCodeCompletion() && !CodeCompletion) { @@ -5592,6 +5606,117 @@ Parser::parseDeclFunc(SourceLoc StaticLoc, StaticSpellingKind StaticSpelling, return DCC.fixupParserResult(FD); } +/// \brief Parse a `call` declaration, returning null on error. The caller +/// handles this case and does recovery as appropriate. +/// +/// \verbatim +/// decl-call: +/// attribute-list? 'mutating'? 'call' +/// generic-params? func-signature where-clause? +/// stmt-brace? +/// \endverbatim +/// +/// \note The caller of this method must ensure that the next token is 'call'. +ParserResult +Parser::parseDeclCall(ParseDeclOptions Flags, DeclAttributes &Attributes) { + assert(Tok.is(tok::kw_call)); + SourceLoc callLoc = consumeToken(tok::kw_call); + + // Reject `call` declarations outside of types. + if (!Flags.contains(PD_HasContainerType)) + diagnose(Tok, diag::call_decl_wrong_scope); + + // Reject named `call` declarations. e.g. `call foo()'. + if (Tok.is(tok::identifier) && + (peekToken().is(tok::l_paren) || startsWithLess(peekToken()))) { + diagnose(Tok, diag::call_decl_cannot_have_name).fixItRemove(Tok.getLoc()); + consumeToken(tok::identifier); + } + + auto simpleName = Context.getIdentifier("call"); + DebuggerContextChange DCC(*this, simpleName, DeclKind::Call); + + // Parse the generic parameters, if present. + Scope genericsScope(this, ScopeKind::Generics); + auto genericParamsResult = maybeParseGenericParams(); + bool signatureHasCodeCompletion = false; + GenericParamList *genericParams = genericParamsResult.getPtrOrNull(); + if (genericParamsResult.hasCodeCompletion()) + return makeParserCodeCompletionStatus(); + + DefaultArgumentInfo defaultArgs; + TypeRepr *funcRetTy = nullptr; + DeclName fullName; + ParameterList *params; + SourceLoc throwsLoc; + bool rethrows; + ParserStatus signatureStatus = + parseFunctionSignature(simpleName, fullName, ParameterContextKind::Call, + params, defaultArgs, throwsLoc, rethrows, + funcRetTy); + + signatureHasCodeCompletion |= signatureStatus.hasCodeCompletion(); + if (signatureStatus.hasCodeCompletion() && !CodeCompletion) { + // Trigger delayed parsing, no need to continue. + return signatureStatus; + } + + diagnoseWhereClauseInGenericParamList(genericParams); + + // Create the 'call` declaration and add it to the parent scope. + auto *CD = CallDecl::create(Context, fullName, callLoc, + /*throws*/ throwsLoc.isValid(), throwsLoc, + /*genericParams*/ nullptr, params, funcRetTy, + CurDeclContext); + + // Parse a 'where' clause if present, adding it to our GenericParamList. + if (Tok.is(tok::kw_where)) { + ContextChange CC(*this, CD); + + auto whereStatus = parseFreestandingGenericWhereClause(genericParams); + signatureHasCodeCompletion |= whereStatus.hasCodeCompletion(); + if (whereStatus.hasCodeCompletion() && !CodeCompletion) { + // Trigger delayed parsing, no need to continue. + return whereStatus; + } + } + + CD->setGenericParams(genericParams); + + // Protocol method arguments may not have default values. + if (Flags.contains(PD_InProtocol) && defaultArgs.HasDefaultArgument) { + diagnose(callLoc, diag::protocol_method_argument_init); + return nullptr; + } + + // Add the 'rethrows' attribute. + if (rethrows) + Attributes.add(new (Context) RethrowsAttr(throwsLoc)); + + // Add the attributes here so if we need them while parsing the body + // they are available. + CD->getAttrs() = Attributes; + + // Pass the function signature to code completion. + if (signatureHasCodeCompletion) + CodeCompletion->setParsedDecl(CD); + + defaultArgs.setFunctionContext(CD, CD->getParameters()); + setLocalDiscriminator(CD); + + if (Flags.contains(PD_InProtocol)) { + if (Tok.is(tok::l_brace)) { + diagnose(Tok, diag::protocol_method_with_body); + skipSingle(); + } + } else { + parseAbstractFunctionBody(CD); + } + + addToScope(CD); + return DCC.fixupParserResult(CD); +} + /// Parse function body into \p AFD. void Parser::parseAbstractFunctionBody(AbstractFunctionDecl *AFD) { Scope S(this, ScopeKind::FunctionBody); diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 02ddea163c14d..1097c77448e04 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -1534,6 +1534,7 @@ ParserResult Parser::parseExprPrimary(Diag<> ID, bool isExprBasic) { case tok::identifier: // foo case tok::kw_self: // self + case tok::kw_call: // call, normally a keyword when parsing declarations // If we are parsing a refutable pattern and are inside a let/var pattern, // the identifiers change to be value bindings instead of decl references. @@ -2131,7 +2132,7 @@ DeclName Parser::parseUnqualifiedDeclName(bool afterDot, // Consume the base name. DeclBaseName baseName; SourceLoc baseNameLoc; - if (Tok.isAny(tok::identifier, tok::kw_Self, tok::kw_self)) { + if (Tok.isAny(tok::identifier, tok::kw_Self, tok::kw_self, tok::kw_call)) { baseName = Context.getIdentifier(Tok.getText()); baseNameLoc = consumeToken(); } else if (allowOperators && Tok.isAnyOperator()) { @@ -2241,7 +2242,7 @@ DeclName Parser::parseUnqualifiedDeclName(bool afterDot, /// expr-identifier: /// unqualified-decl-name generic-args? Expr *Parser::parseExprIdentifier() { - assert(Tok.isAny(tok::identifier, tok::kw_self, tok::kw_Self)); + assert(Tok.isAny(tok::identifier, tok::kw_self, tok::kw_Self, tok::kw_call)); SyntaxParsingContext IDSyntaxContext(SyntaxContext, SyntaxKind::IdentifierExpr); Token IdentTok = Tok; diff --git a/lib/Parse/ParsePattern.cpp b/lib/Parse/ParsePattern.cpp index 677d985371679..450db31fc7c18 100644 --- a/lib/Parse/ParsePattern.cpp +++ b/lib/Parse/ParsePattern.cpp @@ -89,6 +89,7 @@ static ParserStatus parseDefaultArgument( Diag<> diagID = { DiagID() }; switch (paramContext) { case Parser::ParameterContextKind::Function: + case Parser::ParameterContextKind::Call: case Parser::ParameterContextKind::Operator: case Parser::ParameterContextKind::Initializer: case Parser::ParameterContextKind::EnumElement: @@ -545,6 +546,7 @@ mapParsedParameters(Parser &parser, case Parser::ParameterContextKind::Curried: case Parser::ParameterContextKind::Initializer: case Parser::ParameterContextKind::Function: + case Parser::ParameterContextKind::Call: isKeywordArgumentByDefault = true; break; } @@ -609,6 +611,7 @@ mapParsedParameters(Parser &parser, assert((paramContext == Parser::ParameterContextKind::Function || paramContext == Parser::ParameterContextKind::Operator || paramContext == Parser::ParameterContextKind::Initializer || + paramContext == Parser::ParameterContextKind::Call || paramContext == Parser::ParameterContextKind::EnumElement) && "Default arguments are only permitted on the first param clause"); DefaultArgumentKind kind = getDefaultArgKind(param.DefaultArg); @@ -634,6 +637,9 @@ Parser::parseSingleParameterClause(ParameterContextKind paramContext, // If we don't have the leading '(', complain. Diag<> diagID; switch (paramContext) { + case ParameterContextKind::Call: + diagID = diag::expected_lparen_call; + break; case ParameterContextKind::Function: case ParameterContextKind::Operator: diagID = diag::func_decl_without_paren; @@ -720,6 +726,7 @@ Parser::parseFunctionArguments(SmallVectorImpl &NamePieces, ParserStatus Parser::parseFunctionSignature(Identifier SimpleName, DeclName &FullName, + ParameterContextKind paramContext, ParameterList *&bodyParams, DefaultArgumentInfo &defaultArgs, SourceLoc &throwsLoc, @@ -729,12 +736,10 @@ Parser::parseFunctionSignature(Identifier SimpleName, SmallVector NamePieces; ParserStatus Status; - ParameterContextKind paramContext = SimpleName.isOperator() ? - ParameterContextKind::Operator : ParameterContextKind::Function; Status |= parseFunctionArguments(NamePieces, bodyParams, paramContext, defaultArgs); FullName = DeclName(Context, SimpleName, NamePieces); - + // Check for the 'throws' keyword. rethrows = false; if (Tok.is(tok::kw_throws)) { diff --git a/lib/SILGen/SILGenDecl.cpp b/lib/SILGen/SILGenDecl.cpp index 67ea4a84448ce..4c7986e4efb6f 100644 --- a/lib/SILGen/SILGenDecl.cpp +++ b/lib/SILGen/SILGenDecl.cpp @@ -1418,7 +1418,8 @@ void SILGenModule::emitExternalDefinition(Decl *d) { switch (d->getKind()) { case DeclKind::Func: - case DeclKind::Accessor: { + case DeclKind::Accessor: + case DeclKind::Call: { emitFunction(cast(d)); break; } diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index 77e84dd38e1e9..c6f002ed8a021 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -7320,6 +7320,40 @@ Expr *ExprRewriter::finishApply(ApplyExpr *apply, Type openedType, return finishApply(apply, openedType, locator); } + // Handle `call` method applications. + auto &ctx = cs.getASTContext(); + + TupleExpr *arg = dyn_cast(apply->getArg()); + if (auto parenExpr = dyn_cast(apply->getArg())) + arg = TupleExpr::createImplicit(ctx, parenExpr->getSubExpr(), {}); + + // Get resolved `call` method and verify it. + auto loc = locator.withPathElement(ConstraintLocator::ApplyFunction); + auto selected = solution.getOverloadChoice(cs.getConstraintLocator(loc)); + auto choice = selected.choice; + if (auto *method = dyn_cast(selected.choice.getDecl())) { + bool isDynamic = choice.getKind() == OverloadChoiceKind::DeclViaDynamic; + auto callDeclLocator = cs.getConstraintLocator( + locator.withPathElement(ConstraintLocator::ApplyFunction) + .withPathElement(ConstraintLocator::CallMember)); + // Create direct reference to `call` method. + Expr *declRef = buildMemberRef(fn, selected.openedFullType, + /*dotLoc=*/SourceLoc(), choice, + DeclNameLoc(fn->getEndLoc()), + selected.openedType, locator, + callDeclLocator, /*Implicit=*/true, + choice.getFunctionRefKind(), + AccessSemantics::Ordinary, isDynamic); + if (!declRef) + return nullptr; + declRef->setImplicit(apply->isImplicit()); + apply->setFn(declRef) ; + Expr *result = apply; + cs.TC.typeCheckExpression(result, cs.DC); + cs.cacheExprTypes(result); + return result; + } + // Handle @dynamicCallable applications. // At this point, all other ApplyExpr cases have been handled. return finishApplyDynamicCallable(cs, solution, apply, locator); diff --git a/lib/Sema/CSDiag.cpp b/lib/Sema/CSDiag.cpp index e4fa23e4aa999..38982b6b356e2 100644 --- a/lib/Sema/CSDiag.cpp +++ b/lib/Sema/CSDiag.cpp @@ -4847,19 +4847,26 @@ bool FailureDiagnosis::visitApplyExpr(ApplyExpr *callExpr) { // non-function/non-metatype type, then we cannot call it! if (!isUnresolvedOrTypeVarType(fnType) && !fnType->is() && !fnType->is()) { - auto arg = callExpr->getArg(); + auto isDynamicCallable = + CS.DynamicCallableCache[fnType->getCanonicalType()].isValid(); + + auto *nominal = fnType->getAnyNominal(); + auto hasCallDecls = nominal && + llvm::any_of(nominal->getMembers(), [](Decl *member) { + return isa(member); + }); // Diagnose @dynamicCallable errors. - if (CS.DynamicCallableCache[fnType->getCanonicalType()].isValid()) { + if (isDynamicCallable) { auto dynamicCallableMethods = - CS.DynamicCallableCache[fnType->getCanonicalType()]; + CS.DynamicCallableCache[fnType->getCanonicalType()]; // Diagnose dynamic calls with keywords on @dynamicCallable types that // don't define the `withKeywordArguments` method. if (auto tuple = dyn_cast(arg)) { bool hasArgLabel = llvm::any_of( - tuple->getElementNames(), [](Identifier i) { return !i.empty(); }); + tuple->getElementNames(), [](Identifier i) { return !i.empty(); }); if (hasArgLabel && dynamicCallableMethods.keywordArgumentsMethods.empty()) { diagnose(callExpr->getFn()->getStartLoc(), @@ -4894,7 +4901,7 @@ bool FailureDiagnosis::visitApplyExpr(ApplyExpr *callExpr) { // the line after the callee, then it's likely the user forgot to // write "do" before their brace stmt. // Note that line differences of more than 1 are diagnosed during parsing. - if (auto *PE = dyn_cast(arg)) + if (auto *PE = dyn_cast(arg)) { if (PE->hasTrailingClosure() && isa(PE->getSubExpr())) { auto *closure = cast(PE->getSubExpr()); auto &SM = CS.getASTContext().SourceMgr; @@ -4903,11 +4910,13 @@ bool FailureDiagnosis::visitApplyExpr(ApplyExpr *callExpr) { 1 + SM.getLineNumber(callExpr->getFn()->getEndLoc()) == SM.getLineNumber(closure->getStartLoc())) { diagnose(closure->getStartLoc(), diag::brace_stmt_suggest_do) - .fixItInsert(closure->getStartLoc(), "do "); + .fixItInsert(closure->getStartLoc(), "do "); } } + } - return true; + if (!isDynamicCallable && !hasCallDecls) + return true; } bool hasTrailingClosure = callArgHasTrailingClosure(callExpr->getArg()); diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index 32adf083be57c..1fefb2cc71dad 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -5228,6 +5228,107 @@ Type ConstraintSystem::simplifyAppliedOverloads( return fnType; } +/// Returns the `call` declarations (if they exist) implemented or inherited +/// by a type. +/// This function may be slow for deep class hierarchies and multiple protocol +/// conformances, but it is invoked only after other constraint simplification +/// rules fail. +static llvm::DenseSet +getCallDeclarations(Type type, ConstraintSystem &CS, + const ConstraintLocatorBuilder &locator) { + auto canType = type->getCanonicalType(); + auto it = CS.CallDeclCache.find(canType); + if (it != CS.CallDeclCache.end()) return it->second; + + // Calculate `call` declarations for composite types with multiple components + // (protocol composition types and archetypes). + auto calculateForComponentTypes = + [&](ArrayRef componentTypes) -> llvm::DenseSet { + llvm::DenseSet callDecls; + for (auto componentType : componentTypes) { + auto *nominal = componentType->getAnyNominal(); + callDecls.insert(nominal->getCallDeclarations().begin(), + nominal->getCallDeclarations().end()); + } + return callDecls; + }; + + // Calculate `call` declarations. + auto calculate = [&]() -> llvm::DenseSet { + // If this is an archetype type, check if any types it conforms to + // (superclass or protocols) have`call` declarations. + if (auto archetype = dyn_cast(canType)) { + SmallVector componentTypes; + for (auto protocolDecl : archetype->getConformsTo()) + componentTypes.push_back(protocolDecl->getDeclaredType()); + if (auto superclass = archetype->getSuperclass()) + componentTypes.push_back(superclass); + return calculateForComponentTypes(componentTypes); + } + + // If this is a protocol composition, check if any of its members have + // `call` declarations. + if (auto protocolComp = dyn_cast(canType)) + return calculateForComponentTypes(protocolComp->getMembers()); + + // Otherwise, this must be a nominal type. + // Structural types cannot define `call` declarations. + auto nominal = canType->getAnyNominal(); + if (!nominal) return llvm::DenseSet(); + + // If this type conforms to protocols, look up all of their `call` + // declaration requirements. + // FIXME: Fix this to handle overridden requirements, e.g. using + // `OverriddenDeclsRequest`. Mimic logic from or unify logic with + // `lookupQualified`. + llvm::DenseSet callDecls; + for (auto p : nominal->getAllProtocols()) { + if (p->getCallDeclarations().empty()) + continue; + /* + for (auto *callDecl : p->getCallDeclarations()) + if (callDecl->isProtocolRequirement()) + callDecls.insert(callDecl); + */ + callDecls.insert(p->getCallDeclarations().begin(), + p->getCallDeclarations().end()); + } + // Hack: if any are found, return them directly. See FIXME above. + if (!callDecls.empty()) + return callDecls; + + // Walk superclasses, if present. + llvm::SmallPtrSet visitedDecls; + while (1) { + // If we found a circular parent class chain, reject this. + if (!visitedDecls.insert(nominal).second) + return llvm::DenseSet(); + + // If this type has the attribute on it, then look up the methods. + if (!nominal->getCallDeclarations().empty()) { + callDecls.insert(nominal->getCallDeclarations().begin(), + nominal->getCallDeclarations().end()); + } + + // If this type is a class with a superclass, check superclasses. + if (auto *cd = dyn_cast(nominal)) { + if (auto superClass = cd->getSuperclassDecl()) { + nominal = superClass; + continue; + } + } + + return callDecls; + } + }; + + auto result = calculate(); + // Cache the result if the type does not contain type variables. + if (!type->hasTypeVariable()) + CS.CallDeclCache[canType] = result; + return result; +} + ConstraintSystem::SolutionKind ConstraintSystem::simplifyApplicableFnConstraint( Type type1, @@ -5389,6 +5490,51 @@ ConstraintSystem::simplifyApplicableFnConstraint( return simplified; } + // TODO: WIP! + // Handle `call` declaration application. + if (auto nominal = desugar2->getAnyNominal()) { + auto callDecls = getCallDeclarations(desugar2, *this, locator); + + // Handle `call` method calls. + if (!callDecls.empty()) { + // Create a type variable for the `call` method. + auto loc = getConstraintLocator(locator); + auto tv = createTypeVariable(loc, TVO_CanBindToLValue); + + // Record the `call` method overload set. + SmallVector choices; + for (auto candidate : callDecls) { + TC.validateDecl(candidate); + if (candidate->isInvalid()) continue; + choices.push_back( + OverloadChoice(type2, candidate, FunctionRefKind::SingleApply)); + } + if (choices.empty()) return SolutionKind::Error; + addOverloadSet(tv, choices, DC, loc); + + // Create type variables for each parameter type. + SmallVector tvParams; + for (unsigned i : range(func1->getNumParams())) { + auto param = func1->getParams()[i]; + auto paramType = param.getPlainType(); + + auto *tvParam = createTypeVariable(loc); + auto locatorBuilder = + locator.withPathElement(LocatorPathElt::getTupleElement(i)); + addConstraint(ConstraintKind::ArgumentConversion, paramType, + tvParam, locatorBuilder); + tvParams.push_back(AnyFunctionType::Param(tvParam)); + } + // Create target function type and applicable function constraint. + AnyFunctionType *funcType = + FunctionType::get(tvParams, func1->getResult()); + addConstraint(ConstraintKind::ApplicableFunction, + funcType, tv, locator); + + return SolutionKind::Solved; + } + } + // Handle applications of @dynamicCallable types. return simplifyDynamicCallableApplicableFnConstraint(type1, origType2, subflags, locator); @@ -5495,6 +5641,8 @@ getDynamicCallableMethods(Type type, ConstraintSystem &CS, // If this type conforms to a protocol which has the attribute, then // look up the methods. + // TODO: Fix this to return all `@dynamicCallable` required methods defined + // in all conforming `@dynamicCallable` protocols, not just the first one. for (auto p : nominal->getAllProtocols()) if (p->getAttrs().hasAttribute()) return lookupDynamicCallableMethods(type, CS, locator); @@ -5664,7 +5812,7 @@ ConstraintSystem::simplifyDynamicCallableApplicableFnConstraint( auto param = func1->getParams()[i]; auto paramType = param.getPlainType(); auto locatorBuilder = - locator.withPathElement(LocatorPathElt::getTupleElement(i)); + locator.withPathElement(LocatorPathElt::getTupleElement(i)); addConstraint(ConstraintKind::ArgumentConversion, paramType, argumentType, locatorBuilder); } diff --git a/lib/Sema/ConstraintLocator.cpp b/lib/Sema/ConstraintLocator.cpp index 9a1199cdbeb2b..b77146a4813c6 100644 --- a/lib/Sema/ConstraintLocator.cpp +++ b/lib/Sema/ConstraintLocator.cpp @@ -54,6 +54,7 @@ void ConstraintLocator::Profile(llvm::FoldingSetNodeID &id, Expr *anchor, case MemberRefBase: case UnresolvedMember: case SubscriptMember: + case CallMember: case ConstructorMember: case LValueConversion: case RValueAdjustment: @@ -218,6 +219,10 @@ void ConstraintLocator::dump(SourceManager *sm, raw_ostream &out) { out << "subscript member"; break; + case CallMember: + out << "call member"; + break; + case TupleElement: out << "tuple element #" << llvm::utostr(elt.getValue()); break; diff --git a/lib/Sema/ConstraintLocator.h b/lib/Sema/ConstraintLocator.h index 95bbb8b6f3106..081ca24a11367 100644 --- a/lib/Sema/ConstraintLocator.h +++ b/lib/Sema/ConstraintLocator.h @@ -85,6 +85,8 @@ class ConstraintLocator : public llvm::FoldingSetNode { MemberRefBase, /// The lookup for a subscript member. SubscriptMember, + /// The lookup for a call member. + CallMember, /// The lookup for a constructor member. ConstructorMember, /// An implicit @lvalue-to-inout conversion; only valid for operator @@ -143,6 +145,7 @@ class ConstraintLocator : public llvm::FoldingSetNode { case MemberRefBase: case UnresolvedMember: case SubscriptMember: + case CallMember: case ConstructorMember: case LValueConversion: case RValueAdjustment: @@ -207,6 +210,7 @@ class ConstraintLocator : public llvm::FoldingSetNode { case LValueConversion: case RValueAdjustment: case SubscriptMember: + case CallMember: case OpenedGeneric: case GenericParameter: case GenericArgument: diff --git a/lib/Sema/ConstraintSystem.h b/lib/Sema/ConstraintSystem.h index 1c59765a652a7..5637a8e1debf9 100644 --- a/lib/Sema/ConstraintSystem.h +++ b/lib/Sema/ConstraintSystem.h @@ -1080,6 +1080,9 @@ class ConstraintSystem { /// The locators of \c Defaultable constraints whose defaults were used. SmallVector DefaultedConstraints; + /// A cache that stores the `call` declarations of a type. + llvm::DenseMap> CallDeclCache; + /// A cache that stores the @dynamicCallable required methods implemented by /// types. llvm::DenseMap DynamicCallableCache; diff --git a/lib/Sema/LookupVisibleDecls.cpp b/lib/Sema/LookupVisibleDecls.cpp index b86daa1eebad8..036517f5275da 100644 --- a/lib/Sema/LookupVisibleDecls.cpp +++ b/lib/Sema/LookupVisibleDecls.cpp @@ -314,6 +314,7 @@ static void doDynamicLookup(VisibleDeclConsumer &Consumer, // with the same signature. case DeclKind::Accessor: + case DeclKind::Call: case DeclKind::Func: { auto FD = cast(D); assert(FD->hasImplicitSelfDecl() && "should not find free functions"); diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index 9981686ff985a..cc07817718826 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -2966,6 +2966,41 @@ class DeclChecker : public DeclVisitor { } } + void visitCallDecl(CallDecl *CD) { + TC.validateDecl(CD); + + if (!CD->isInvalid()) { + checkGenericParams(CD->getGenericParams(), CD, TC); + TC.checkReferencedGenericParams(CD); + TC.checkProtocolSelfRequirements(CD); + } + + checkAccessControl(TC, CD); + + if (!checkOverrides(CD)) { + // If a method has an 'override' keyword but does not + // override anything, complain. + if (auto *OA = CD->getAttrs().getAttribute()) { + if (!CD->getOverriddenDecl()) { + TC.diagnose(CD, diag::method_does_not_override) + .highlight(OA->getLocation()); + OA->setInvalid(); + } + } + } + + if (requiresDefinition(CD) && !CD->hasBody()) { + // Complain if we should have a body. + TC.diagnose(CD->getLoc(), diag::func_decl_without_brace); + } else { + // Record the body. + TC.definedFunctions.push_back(CD); + } + + if (CD->getAttrs().hasAttribute()) + TC.checkDynamicReplacementAttribute(CD); + } + void visitModuleDecl(ModuleDecl *) { } void visitEnumCaseDecl(EnumCaseDecl *ECD) { @@ -4121,6 +4156,30 @@ void TypeChecker::validateDecl(ValueDecl *D) { break; } + case DeclKind::Call: { + auto *CD = cast(D); + DeclValidationRAII IBV(CD); + validateGenericFuncSignature(CD); + CD->setSignatureIsValidated(); + checkDeclAttributesEarly(CD); + validateAttributes(*this, CD); + + auto *TyR = CD->getBodyResultTypeLoc().getTypeRepr(); + if (TyR && TyR->getKind() == TypeReprKind::ImplicitlyUnwrappedOptional) { + auto &C = CD->getASTContext(); + CD->getAttrs().add( + new (C) ImplicitlyUnwrappedOptionalAttr(/* implicit= */ true)); + } + + // Member subscripts need some special validation logic. + if (CD->getDeclContext()->isTypeContext()) { + // If this is a class member, mark it final if the class is final. + inferFinalAndDiagnoseIfNeeded(*this, CD, StaticSpellingKind::None); + } + + break; + } + case DeclKind::EnumElement: { auto *EED = cast(D); EnumDecl *ED = EED->getParentEnum(); diff --git a/lib/Sema/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp index 15ae94b3d3293..0b71df6f50ab9 100644 --- a/lib/Sema/TypeCheckProtocol.cpp +++ b/lib/Sema/TypeCheckProtocol.cpp @@ -1931,6 +1931,9 @@ static diag::RequirementKind getRequirementKind(ValueDecl *VD) { if (isa(VD)) return diag::RequirementKind::Constructor; + if (isa(VD)) + return diag::RequirementKind::Call; + if (isa(VD)) return diag::RequirementKind::Func; diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index 7f21057684bc5..5345aa4fd3b7e 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -1767,6 +1767,7 @@ static bool shouldSerializeMember(Decl *D) { case DeclKind::Var: case DeclKind::Param: case DeclKind::Func: + case DeclKind::Call: case DeclKind::Accessor: return true; } @@ -3409,6 +3410,69 @@ void Serializer::writeDecl(const Decl *D) { break; } + // TODO: Revisit serialization. + // Create `CallLayout`? Not all fields from `FuncLayout` are necessary: + // `call` declarations cannot be static. + case DeclKind::Call: { + auto fn = cast(D); + verifyAttrSerializable(fn); + + auto contextID = addDeclContextRef(fn->getDeclContext()); + + unsigned abbrCode = DeclTypeAbbrCodes[FuncLayout::Code]; + SmallVector nameComponentsAndDependencies; + nameComponentsAndDependencies.push_back( + addDeclBaseNameRef(fn->getFullName().getBaseName())); + for (auto argName : fn->getFullName().getArgumentNames()) + nameComponentsAndDependencies.push_back(addDeclBaseNameRef(argName)); + + uint8_t rawAccessLevel = getRawStableAccessLevel(fn->getFormalAccess()); + uint8_t rawDefaultArgumentResilienceExpansion = + getRawStableResilienceExpansion( + fn->getDefaultArgumentResilienceExpansion()); + + Type ty = fn->getInterfaceType(); + for (auto dependency : collectDependenciesFromType(ty->getCanonicalType())) + nameComponentsAndDependencies.push_back(addTypeRef(dependency)); + + FuncLayout::emitRecord(Out, ScratchRecord, abbrCode, + contextID, + fn->isImplicit(), + fn->isStatic(), + uint8_t( + getStableStaticSpelling(fn->getStaticSpelling())), + fn->isObjC(), + uint8_t( + getStableSelfAccessKind(fn->getSelfAccessKind())), + fn->hasDynamicSelf(), + fn->hasForcedStaticDispatch(), + fn->hasThrows(), + addGenericEnvironmentRef( + fn->getGenericEnvironment()), + addTypeRef(fn->getResultInterfaceType()), + addDeclRef(fn->getOperatorDecl()), + addDeclRef(fn->getOverriddenDecl()), + fn->getFullName().getArgumentNames().size() + + fn->getFullName().isCompoundName(), + rawAccessLevel, + fn->needsNewVTableEntry(), + rawDefaultArgumentResilienceExpansion, + nameComponentsAndDependencies); + + writeGenericParams(fn->getGenericParams()); + + // Write the body parameters. + writeParameterList(fn->getParameters()); + + if (auto errorConvention = fn->getForeignErrorConvention()) + writeForeignErrorConvention(*errorConvention); + + writeInlinableBodyTextIfNeeded(fn); + + break; + } + + case DeclKind::EnumElement: { auto elem = cast(D); auto contextID = addDeclContextRef(elem->getDeclContext()); diff --git a/lib/TBDGen/TBDGen.cpp b/lib/TBDGen/TBDGen.cpp index c649d0add6259..c1754a04d4a05 100644 --- a/lib/TBDGen/TBDGen.cpp +++ b/lib/TBDGen/TBDGen.cpp @@ -460,6 +460,7 @@ static bool isValidProtocolMemberForTBDGen(const Decl *D) { case DeclKind::PatternBinding: case DeclKind::Func: case DeclKind::Accessor: + case DeclKind::Call: case DeclKind::Constructor: case DeclKind::Destructor: case DeclKind::IfConfig: diff --git a/test/Parse/call_decl.swift b/test/Parse/call_decl.swift new file mode 100644 index 0000000000000..563442d0bf9c0 --- /dev/null +++ b/test/Parse/call_decl.swift @@ -0,0 +1,90 @@ +// RUN: %target-typecheck-verify-swift + +struct SimpleCallable { + call(_ x: Int) -> Int { + return x + } +} + +struct NoRedefinitionErrors { + call(_ x: Int) -> Int { + return x + } + call(x: Int) -> Int { + return x + } + call(_ x: Int, y: Int) -> Int { + return x + } +} + +struct RedefinitionErrors { + // expected-note @+1 2 {{'call' previously declared here}} + call(_ x: Int) -> Int { + return x + } + // expected-error @+1 {{invalid redeclaration of 'call'}} + call(_ y: Int) -> Int { + return y + } + // expected-error @+1 {{invalid redeclaration of 'call'}} + func call(_ x: Int) -> Int { + return x + } +} + +struct ParseErrors { + // expected-error @+1 {{expected '->' after function parameter tuple}} {{22-23= ->}} + func call(_ x: Int): Int { + return x + } + + // expected-error @+1 {{expected type for function result}} + func call(_ x: Int) -> {} +} + +class StaticSpellingErrors { + // expected-error @+1 {{'call' member cannot be marked 'static'}} + static call(_ x: Int) {} + // expected-error @+1 {{expected '{' in class}} + class call(_ x: Int) {} +} + +class StaticSpellingOkay_Static { + static func call(_ x: Int) {} +} +class StaticSpellingOkay_Class { + class func call(_ x: Int) {} +} + +protocol ParseErrorsProtocol { + // expected-error @+1 {{default argument not permitted in a protocol method}} + func call(_ x: Int = 1) -> Int +} + +// Test context sensitive parsing. +// "call" can appear in declaration or expression contexts. +struct ContextSensitiveParsing { + // declaration + call(_ fn: () -> Void) { + // expression + call() {} + // expression + call {} + + struct U { + // declaration + call(x: Int) {} + + // error + // expected-error @+1 {{expected '(' for 'call' member parameters}} {{11-11=()}} + call {} + } + } +} + +// Global function. Used below. +func call(_ fn: () -> Void) {} + +// expression +call() {} diff --git a/test/SourceKit/CodeComplete/complete_override.swift.response b/test/SourceKit/CodeComplete/complete_override.swift.response index 4ec04873a57b3..903819202678a 100644 --- a/test/SourceKit/CodeComplete/complete_override.swift.response +++ b/test/SourceKit/CodeComplete/complete_override.swift.response @@ -9,6 +9,15 @@ key.context: source.codecompletion.context.none, key.num_bytes_to_erase: 0 }, + { + key.kind: source.lang.swift.keyword, + key.name: "call", + key.sourcetext: "call", + key.description: "call", + key.typename: "", + key.context: source.codecompletion.context.none, + key.num_bytes_to_erase: 0 + }, { key.kind: source.lang.swift.keyword, key.name: "class", diff --git a/test/Syntax/Parser/tree.swift.result b/test/Syntax/Parser/tree.swift.result index 08e3380b5607c..6b0e6e9d5c7df 100644 --- a/test/Syntax/Parser/tree.swift.result +++ b/test/Syntax/Parser/tree.swift.result @@ -1,8 +1,8 @@ -// REQUIRES: syntax_parser_lib +// REQUIRES: syntax_parser_lib // RUN: %swift-syntax-parser-test %s -dump-tree > %t.result // RUN: diff -u %s.result %t.result -|func| |test||(||)| |{| - |"||a||\||(||b||)||c||"| -|}| -|| \ No newline at end of file +|func| |test||(||)| |{| + |"||a||\||(||b||)||c||"| +|}| +|| \ No newline at end of file diff --git a/test/decl/call/callables.swift b/test/decl/call/callables.swift new file mode 100644 index 0000000000000..e06e1a8fd0534 --- /dev/null +++ b/test/decl/call/callables.swift @@ -0,0 +1,63 @@ +// RUN: %target-typecheck-verify-swift + +struct SimpleCallable { + call(_ x: Float) -> Float { + return x + } +} + +// Simple test. + +let foo = SimpleCallable() +_ = foo(1) +_ = foo(foo(1)) + +// Test direct `call` method references. + +_ = foo.call(1) +_ = [1, 2, 3].map(foo.call) +_ = foo.call(foo(1)) +_ = foo(foo.call(1)) +let _: (Float) -> Float = foo.call + +func callable() -> SimpleCallable { + return SimpleCallable() +} +extension SimpleCallable { + var foo: SimpleCallable { + return self + } + func bar() -> SimpleCallable { + return self + } +} + +_ = foo.foo(1) +_ = foo.bar()(1) +_ = callable()(1) +_ = [1, 2, 3].map(foo.foo.call) +_ = [1, 2, 3].map(foo.bar().call) +_ = [1, 2, 3].map(callable().call) + +struct MultipleArgsCallable { + call(x: Int, y: Float) -> [Int] { + return [x] + } +} + +let bar = MultipleArgsCallable() + +_ = bar(x: 1, y: 1) +_ = bar.call(x: 1, y: 1) +_ = bar(x: bar.call(x: 1, y: 1)[0], y: 1) +_ = bar.call(x: bar(x: 1, y: 1)[0], y: 1) + +// Errors. + +// TODO: Fix this error. Ideally, it should be "extra argument in call". +// expected-error @+2 {{cannot call value of non-function type 'SimpleCallable'}} +// expected-error @+1 {{cannot invoke 'foo' with an argument list of type '(Int, Int)'}} +_ = foo(1, 1) + +_ = bar(1, 1) // expected-error {{missing argument labels 'x:y:' in call}} +let _: (Float) -> Float = foo // expected-error {{cannot convert value of type 'SimpleCallable' to specified type '(Float) -> Float'}} diff --git a/test/decl/call/generic.swift b/test/decl/call/generic.swift new file mode 100644 index 0000000000000..f95a4ab2a7bb2 --- /dev/null +++ b/test/decl/call/generic.swift @@ -0,0 +1,27 @@ +// RUN: %target-typecheck-verify-swift + +protocol P { + call(x: Self) +} + +struct ConcreteType { + call(_ x: T, _ y: U) -> (T, U) { + return (x, y) + } + + call(_ fn: @escaping (T) -> U) -> (T) -> U { + return fn + } +} + +struct GenericType { +} + +let concrete = ConcreteType() +_ = concrete(1, 3.0) +_ = concrete(concrete, concrete.call as ([Int], Float) -> ([Int], Float)) + +func genericContext(_ x: T, _ y: U) { + _ = concrete(x, x) + _ = concrete(x, y) +} diff --git a/test/decl/call/protocol.swift b/test/decl/call/protocol.swift new file mode 100644 index 0000000000000..99760d29ee01b --- /dev/null +++ b/test/decl/call/protocol.swift @@ -0,0 +1,34 @@ +// RUN: %target-typecheck-verify-swift + +protocol P1 { + call() -> Self +} +extension P1 { + call() -> Self { + return self + } +} + +struct Missing : P1 {} + +struct S1 : P1 { + call() -> S1 { + return self + } +} + +let s1 = S1() +_ = s1()()() + +protocol P2 {} +extension P2 { + call() -> Self { + return self + } +} +struct S2 : P2 {} + +let s2 = S2() +// TODO: Fix this by fixing `getCallDeclarations` logic in CSSimplify.cpp. +// Need to handle overriding declarations; mimic/unify code with `lookupQualified`. +// _ = s2()()() diff --git a/tools/SourceKit/lib/SwiftLang/SwiftLangSupport.cpp b/tools/SourceKit/lib/SwiftLang/SwiftLangSupport.cpp index 1d50d59aee7e4..dae7c151b96a6 100644 --- a/tools/SourceKit/lib/SwiftLang/SwiftLangSupport.cpp +++ b/tools/SourceKit/lib/SwiftLang/SwiftLangSupport.cpp @@ -314,6 +314,7 @@ UIdent SwiftLangSupport::getUIDForCodeCompletionDeclKind( case CodeCompletionDeclKind::Constructor: return KindRefConstructor; case CodeCompletionDeclKind::Destructor: return KindRefDestructor; case CodeCompletionDeclKind::Subscript: return KindRefSubscript; + case CodeCompletionDeclKind::Call: return KindRefCall; case CodeCompletionDeclKind::StaticMethod: return KindRefMethodClass; case CodeCompletionDeclKind::InstanceMethod: return KindRefMethodInstance; case CodeCompletionDeclKind::PrefixOperatorFunction: return KindRefFunctionPrefixOperator; @@ -341,6 +342,7 @@ UIdent SwiftLangSupport::getUIDForCodeCompletionDeclKind( case CodeCompletionDeclKind::Constructor: return KindDeclConstructor; case CodeCompletionDeclKind::Destructor: return KindDeclDestructor; case CodeCompletionDeclKind::Subscript: return KindDeclSubscript; + case CodeCompletionDeclKind::Call: return KindDeclCall; case CodeCompletionDeclKind::StaticMethod: return KindDeclMethodClass; case CodeCompletionDeclKind::InstanceMethod: return KindDeclMethodInstance; case CodeCompletionDeclKind::PrefixOperatorFunction: return KindDeclFunctionPrefixOperator; @@ -443,6 +445,8 @@ UIdent SwiftLangSupport::getUIDForSyntaxStructureKind( return KindDeclTypeAlias; case SyntaxStructureKind::Subscript: return KindDeclSubscript; + case SyntaxStructureKind::Call: + return KindDeclCall; case SyntaxStructureKind::AssociatedType: return KindDeclAssociatedType; case SyntaxStructureKind::GenericTypeParam: diff --git a/tools/swift-ide-test/swift-ide-test.cpp b/tools/swift-ide-test/swift-ide-test.cpp index 4571c27a62944..a99b85e5c7348 100644 --- a/tools/swift-ide-test/swift-ide-test.cpp +++ b/tools/swift-ide-test/swift-ide-test.cpp @@ -1257,6 +1257,7 @@ class StructureAnnotator : public ide::SyntaxModelWalker { case SyntaxStructureKind::EnumElement: return "enum-elem"; case SyntaxStructureKind::TypeAlias: return "typealias"; case SyntaxStructureKind::Subscript: return "subscript"; + case SyntaxStructureKind::Call: return "call"; case SyntaxStructureKind::AssociatedType: return "associatedtype"; case SyntaxStructureKind::GenericTypeParam: return "generic-param"; case SyntaxStructureKind::Parameter: return "param"; diff --git a/utils/gyb_sourcekit_support/UIDs.py b/utils/gyb_sourcekit_support/UIDs.py index 6c0596a7397ce..d560439990e23 100644 --- a/utils/gyb_sourcekit_support/UIDs.py +++ b/utils/gyb_sourcekit_support/UIDs.py @@ -292,6 +292,8 @@ def __init__(self, internal_name, external_name): KIND('RefPrecedenceGroup', 'source.lang.swift.ref.precedencegroup'), KIND('DeclSubscript', 'source.lang.swift.decl.function.subscript'), KIND('RefSubscript', 'source.lang.swift.ref.function.subscript'), + KIND('DeclCall', 'source.lang.swift.decl.function.call'), + KIND('RefCall', 'source.lang.swift.ref.function.call'), KIND('DeclVarGlobal', 'source.lang.swift.decl.var.global'), KIND('RefVarGlobal', 'source.lang.swift.ref.var.global'), KIND('DeclVarInstance', 'source.lang.swift.decl.var.instance'), diff --git a/utils/gyb_syntax_support/DeclNodes.py b/utils/gyb_syntax_support/DeclNodes.py index 2df32728c3fd4..333ee7a2e7edd 100644 --- a/utils/gyb_syntax_support/DeclNodes.py +++ b/utils/gyb_syntax_support/DeclNodes.py @@ -380,6 +380,7 @@ 'SpacedBinaryOperatorToken', 'PrefixOperatorToken', 'PostfixOperatorToken', + 'CallToken', ]), Child('GenericParameterClause', kind='GenericParameterClause', is_optional=True), @@ -449,6 +450,22 @@ Child('Getter', kind='CodeBlock')]), ]), + Node('CallDecl', kind='Decl', + children=[ + Child('Attributes', kind='AttributeList', + is_optional=True), + Child('Modifiers', kind='ModifierList', + is_optional=True), + Child('CallKeyword', kind='CallToken'), + Child('GenericParameterClause', kind='GenericParameterClause', + is_optional=True), + Child('Signature', kind='FunctionSignature'), + Child('GenericWhereClause', kind='GenericWhereClause', + is_optional=True), + # the body is not necessary inside a protocol definition + Child('Body', kind='CodeBlock', is_optional=True), + ]), + # access-level-modifier -> 'private' | 'private' '(' 'set' ')' # | 'fileprivate' | 'fileprivate' '(' 'set' ')' # | 'internal' | 'internal' '(' 'set' ')' diff --git a/utils/gyb_syntax_support/ExprNodes.py b/utils/gyb_syntax_support/ExprNodes.py index 57e7422085c2e..1e64c2e51f968 100644 --- a/utils/gyb_syntax_support/ExprNodes.py +++ b/utils/gyb_syntax_support/ExprNodes.py @@ -74,6 +74,7 @@ 'IdentifierToken', 'SelfToken', 'CapitalSelfToken', + 'CallToken', 'DollarIdentifierToken', 'SpacedBinaryOperatorToken', ]), diff --git a/utils/gyb_syntax_support/NodeSerializationCodes.py b/utils/gyb_syntax_support/NodeSerializationCodes.py index eb46221003fda..c858dad1e08ad 100644 --- a/utils/gyb_syntax_support/NodeSerializationCodes.py +++ b/utils/gyb_syntax_support/NodeSerializationCodes.py @@ -19,219 +19,221 @@ 'InitializerDecl': 14, 'DeinitializerDecl': 15, 'SubscriptDecl': 16, - 'ImportDecl': 17, - 'AccessorDecl': 18, - 'VariableDecl': 19, - 'EnumCaseDecl': 20, - 'EnumDecl': 21, - 'OperatorDecl': 22, - 'PrecedenceGroupDecl': 23, - 'UnknownExpr': 24, - 'InOutExpr': 25, - 'PoundColumnExpr': 26, - 'TryExpr': 27, - 'IdentifierExpr': 28, - 'SuperRefExpr': 29, - 'NilLiteralExpr': 30, - 'DiscardAssignmentExpr': 31, - 'AssignmentExpr': 32, - 'SequenceExpr': 33, - 'PoundLineExpr': 34, - 'PoundFileExpr': 35, - 'PoundFunctionExpr': 36, - 'PoundDsohandleExpr': 37, - 'SymbolicReferenceExpr': 38, - 'PrefixOperatorExpr': 39, - 'BinaryOperatorExpr': 40, - 'ArrowExpr': 41, - 'FloatLiteralExpr': 42, - 'TupleExpr': 43, - 'ArrayExpr': 44, - 'DictionaryExpr': 45, - 'ImplicitMemberExpr': 46, - 'IntegerLiteralExpr': 47, - 'StringLiteralExpr': 48, - 'BooleanLiteralExpr': 49, - 'TernaryExpr': 50, - 'MemberAccessExpr': 51, - 'DotSelfExpr': 52, - 'IsExpr': 53, - 'AsExpr': 54, - 'TypeExpr': 55, - 'ClosureExpr': 56, - 'UnresolvedPatternExpr': 57, - 'FunctionCallExpr': 58, - 'SubscriptExpr': 59, - 'OptionalChainingExpr': 60, - 'ForcedValueExpr': 61, - 'PostfixUnaryExpr': 62, - 'SpecializeExpr': 63, - 'StringInterpolationExpr': 64, - 'KeyPathExpr': 65, - 'KeyPathBaseExpr': 66, - 'ObjcKeyPathExpr': 67, - 'ObjcSelectorExpr': 68, - 'EditorPlaceholderExpr': 69, - 'ObjectLiteralExpr': 70, - 'UnknownStmt': 71, - 'ContinueStmt': 72, - 'WhileStmt': 73, - 'DeferStmt': 74, - 'ExpressionStmt': 75, - 'RepeatWhileStmt': 76, - 'GuardStmt': 77, - 'ForInStmt': 78, - 'SwitchStmt': 79, - 'DoStmt': 80, - 'ReturnStmt': 81, - 'FallthroughStmt': 82, - 'BreakStmt': 83, - 'DeclarationStmt': 84, - 'ThrowStmt': 85, - 'IfStmt': 86, - 'Decl': 87, - 'Expr': 88, - 'Stmt': 89, - 'Type': 90, - 'Pattern': 91, - 'CodeBlockItem': 92, - 'CodeBlock': 93, - 'DeclNameArgument': 94, - 'DeclNameArguments': 95, - 'FunctionCallArgument': 96, - 'TupleElement': 97, - 'ArrayElement': 98, - 'DictionaryElement': 99, - 'ClosureCaptureItem': 100, - 'ClosureCaptureSignature': 101, - 'ClosureParam': 102, - 'ClosureSignature': 103, - 'StringSegment': 104, - 'ExpressionSegment': 105, - 'ObjcNamePiece': 106, - 'TypeInitializerClause': 107, - 'ParameterClause': 108, - 'ReturnClause': 109, - 'FunctionSignature': 110, - 'IfConfigClause': 111, - 'PoundSourceLocationArgs': 112, - 'DeclModifier': 113, - 'InheritedType': 114, - 'TypeInheritanceClause': 115, - 'MemberDeclBlock': 116, - 'MemberDeclListItem': 117, - 'SourceFile': 118, - 'InitializerClause': 119, - 'FunctionParameter': 120, - 'AccessLevelModifier': 121, - 'AccessPathComponent': 122, - 'AccessorParameter': 123, - 'AccessorBlock': 124, - 'PatternBinding': 125, - 'EnumCaseElement': 126, - 'OperatorPrecedenceAndTypes': 127, - 'PrecedenceGroupRelation': 128, - 'PrecedenceGroupNameElement': 129, - 'PrecedenceGroupAssignment': 130, - 'PrecedenceGroupAssociativity': 131, - 'Attribute': 132, - 'LabeledSpecializeEntry': 133, - 'ImplementsAttributeArguments': 134, - 'ObjCSelectorPiece': 135, - 'WhereClause': 136, - 'ConditionElement': 137, - 'AvailabilityCondition': 138, - 'MatchingPatternCondition': 139, - 'OptionalBindingCondition': 140, - 'ElseIfContinuation': 141, - 'ElseBlock': 142, - 'SwitchCase': 143, - 'SwitchDefaultLabel': 144, - 'CaseItem': 145, - 'SwitchCaseLabel': 146, - 'CatchClause': 147, - 'GenericWhereClause': 148, - 'SameTypeRequirement': 149, - 'GenericParameter': 150, - 'GenericParameterClause': 151, - 'ConformanceRequirement': 152, - 'CompositionTypeElement': 153, - 'TupleTypeElement': 154, - 'GenericArgument': 155, - 'GenericArgumentClause': 156, - 'TypeAnnotation': 157, - 'TuplePatternElement': 158, - 'AvailabilityArgument': 159, - 'AvailabilityLabeledArgument': 160, - 'AvailabilityVersionRestriction': 161, - 'VersionTuple': 162, - 'CodeBlockItemList': 163, - 'FunctionCallArgumentList': 164, - 'TupleElementList': 165, - 'ArrayElementList': 166, - 'DictionaryElementList': 167, - 'StringInterpolationSegments': 168, - 'DeclNameArgumentList': 169, - 'ExprList': 170, - 'ClosureCaptureItemList': 171, - 'ClosureParamList': 172, - 'ObjcName': 173, - 'FunctionParameterList': 174, - 'IfConfigClauseList': 175, - 'InheritedTypeList': 176, - 'MemberDeclList': 177, - 'ModifierList': 178, - 'AccessPath': 179, - 'AccessorList': 180, - 'PatternBindingList': 181, - 'EnumCaseElementList': 182, - 'PrecedenceGroupAttributeList': 183, - 'PrecedenceGroupNameList': 184, - 'TokenList': 185, - 'NonEmptyTokenList': 186, - 'AttributeList': 187, - 'SpecializeAttributeSpecList': 188, - 'ObjCSelector': 189, - 'SwitchCaseList': 190, - 'CatchClauseList': 191, - 'CaseItemList': 192, - 'ConditionElementList': 193, - 'GenericRequirementList': 194, - 'GenericParameterList': 195, - 'CompositionTypeElementList': 196, - 'TupleTypeElementList': 197, - 'GenericArgumentList': 198, - 'TuplePatternElementList': 199, - 'AvailabilitySpecList': 200, - 'UnknownPattern': 201, - 'EnumCasePattern': 202, - 'IsTypePattern': 203, - 'OptionalPattern': 204, - 'IdentifierPattern': 205, - 'AsTypePattern': 206, - 'TuplePattern': 207, - 'WildcardPattern': 208, - 'ExpressionPattern': 209, - 'ValueBindingPattern': 210, - 'UnknownType': 211, - 'SimpleTypeIdentifier': 212, - 'MemberTypeIdentifier': 213, - 'ClassRestrictionType': 214, - 'ArrayType': 215, - 'DictionaryType': 216, - 'MetatypeType': 217, - 'OptionalType': 218, - 'ImplicitlyUnwrappedOptionalType': 219, - 'CompositionType': 220, - 'TupleType': 221, - 'FunctionType': 222, - 'AttributedType': 223, - 'YieldStmt': 224, - 'YieldList': 225, - 'IdentifierList': 226, - 'NamedAttributeStringArgument': 227, - 'DeclName': 228, - 'PoundAssertStmt': 229, + 'CallDecl': 17, + 'ImportDecl': 18, + 'AccessorDecl': 19, + 'VariableDecl': 20, + 'EnumCaseDecl': 21, + 'EnumDecl': 22, + 'OperatorDecl': 23, + 'PrecedenceGroupDecl': 24, + 'UnknownExpr': 25, + 'InOutExpr': 26, + 'PoundColumnExpr': 27, + 'TryExpr': 28, + 'IdentifierExpr': 29, + 'SuperRefExpr': 30, + 'NilLiteralExpr': 31, + 'DiscardAssignmentExpr': 32, + 'AssignmentExpr': 33, + 'SequenceExpr': 34, + 'PoundLineExpr': 35, + 'PoundFileExpr': 36, + 'PoundFunctionExpr': 37, + 'PoundDsohandleExpr': 38, + 'SymbolicReferenceExpr': 39, + 'PrefixOperatorExpr': 40, + 'BinaryOperatorExpr': 41, + 'ArrowExpr': 42, + 'FloatLiteralExpr': 43, + 'TupleExpr': 44, + 'ArrayExpr': 45, + 'DictionaryExpr': 46, + 'ImplicitMemberExpr': 47, + 'IntegerLiteralExpr': 48, + 'StringLiteralExpr': 49, + 'BooleanLiteralExpr': 50, + 'TernaryExpr': 51, + 'MemberAccessExpr': 52, + 'DotSelfExpr': 53, + 'IsExpr': 54, + 'AsExpr': 55, + 'TypeExpr': 56, + 'ClosureExpr': 57, + 'UnresolvedPatternExpr': 58, + 'FunctionCallExpr': 59, + 'SubscriptExpr': 60, + 'OptionalChainingExpr': 61, + 'ForcedValueExpr': 62, + 'PostfixUnaryExpr': 63, + 'SpecializeExpr': 64, + 'StringInterpolationExpr': 65, + 'KeyPathExpr': 66, + 'KeyPathBaseExpr': 67, + 'ObjcKeyPathExpr': 68, + 'ObjcSelectorExpr': 69, + 'EditorPlaceholderExpr': 70, + 'ObjectLiteralExpr': 71, + 'UnknownStmt': 72, + 'ContinueStmt': 73, + 'WhileStmt': 74, + 'DeferStmt': 75, + 'ExpressionStmt': 76, + 'RepeatWhileStmt': 77, + 'GuardStmt': 78, + 'ForInStmt': 79, + 'SwitchStmt': 80, + 'DoStmt': 81, + 'ReturnStmt': 82, + 'FallthroughStmt': 83, + 'BreakStmt': 84, + 'DeclarationStmt': 85, + 'ThrowStmt': 86, + 'IfStmt': 87, + 'Decl': 88, + 'Expr': 89, + 'Stmt': 90, + 'Type': 91, + 'Pattern': 92, + 'CodeBlockItem': 93, + 'CodeBlock': 94, + 'DeclNameArgument': 95, + 'DeclNameArguments': 96, + 'FunctionCallArgument': 97, + 'TupleElement': 98, + 'ArrayElement': 99, + 'DictionaryElement': 100, + 'ClosureCaptureItem': 101, + 'ClosureCaptureSignature': 102, + 'ClosureParam': 103, + 'ClosureSignature': 104, + 'StringSegment': 105, + 'ExpressionSegment': 106, + 'ObjcNamePiece': 107, + 'TypeInitializerClause': 108, + 'ParameterClause': 109, + 'ReturnClause': 110, + 'FunctionSignature': 111, + 'IfConfigClause': 112, + 'PoundSourceLocationArgs': 113, + 'DeclModifier': 114, + 'InheritedType': 115, + 'TypeInheritanceClause': 116, + 'MemberDeclBlock': 117, + 'MemberDeclListItem': 118, + 'SourceFile': 119, + 'InitializerClause': 120, + 'FunctionParameter': 121, + 'AccessLevelModifier': 122, + 'AccessPathComponent': 123, + 'AccessorParameter': 124, + 'AccessorBlock': 125, + 'PatternBinding': 126, + 'EnumCaseElement': 127, + 'OperatorPrecedenceAndTypes': 128, + 'PrecedenceGroupRelation': 129, + 'PrecedenceGroupNameElement': 130, + 'PrecedenceGroupAssignment': 131, + 'PrecedenceGroupAssociativity': 132, + 'Attribute': 133, + 'LabeledSpecializeEntry': 134, + 'ImplementsAttributeArguments': 135, + 'ObjCSelectorPiece': 136, + 'WhereClause': 137, + 'ConditionElement': 138, + 'AvailabilityCondition': 139, + 'MatchingPatternCondition': 140, + 'OptionalBindingCondition': 141, + 'ElseIfContinuation': 142, + 'ElseBlock': 143, + 'SwitchCase': 144, + 'SwitchDefaultLabel': 145, + 'CaseItem': 146, + 'SwitchCaseLabel': 147, + 'CatchClause': 148, + 'GenericWhereClause': 149, + 'SameTypeRequirement': 150, + 'GenericParameter': 151, + 'GenericParameterClause': 152, + 'ConformanceRequirement': 153, + 'CompositionTypeElement': 154, + 'TupleTypeElement': 155, + 'GenericArgument': 156, + 'GenericArgumentClause': 157, + 'TypeAnnotation': 158, + 'TuplePatternElement': 159, + 'AvailabilityArgument': 160, + 'AvailabilityLabeledArgument': 161, + 'AvailabilityVersionRestriction': 162, + 'VersionTuple': 163, + 'CodeBlockItemList': 164, + 'FunctionCallArgumentList': 165, + 'TupleElementList': 166, + 'ArrayElementList': 167, + 'DictionaryElementList': 168, + 'StringInterpolationSegments': 169, + 'DeclNameArgumentList': 170, + 'ExprList': 171, + 'ClosureCaptureItemList': 172, + 'ClosureParamList': 173, + 'ObjcName': 174, + 'FunctionParameterList': 175, + 'IfConfigClauseList': 176, + 'InheritedTypeList': 177, + 'MemberDeclList': 178, + 'ModifierList': 179, + 'AccessPath': 180, + 'AccessorList': 181, + 'PatternBindingList': 182, + 'EnumCaseElementList': 183, + 'PrecedenceGroupAttributeList': 184, + 'PrecedenceGroupNameList': 185, + 'TokenList': 186, + 'NonEmptyTokenList': 187, + 'AttributeList': 188, + 'SpecializeAttributeSpecList': 189, + 'ObjCSelector': 190, + 'SwitchCaseList': 191, + 'CatchClauseList': 192, + 'CaseItemList': 193, + 'ConditionElementList': 194, + 'GenericRequirementList': 195, + 'GenericParameterList': 196, + 'CompositionTypeElementList': 197, + 'TupleTypeElementList': 198, + 'GenericArgumentList': 199, + 'TuplePatternElementList': 200, + 'AvailabilitySpecList': 201, + 'UnknownPattern': 202, + 'EnumCasePattern': 203, + 'IsTypePattern': 204, + 'OptionalPattern': 205, + 'IdentifierPattern': 206, + 'AsTypePattern': 207, + 'TuplePattern': 208, + 'WildcardPattern': 209, + 'ExpressionPattern': 210, + 'ValueBindingPattern': 211, + 'UnknownType': 212, + 'SimpleTypeIdentifier': 213, + 'MemberTypeIdentifier': 214, + 'ClassRestrictionType': 215, + 'ArrayType': 216, + 'DictionaryType': 217, + 'MetatypeType': 218, + 'OptionalType': 219, + 'ImplicitlyUnwrappedOptionalType': 220, + 'CompositionType': 221, + 'TupleType': 222, + 'FunctionType': 223, + 'AttributedType': 224, + 'YieldStmt': 225, + 'YieldList': 226, + 'IdentifierList': 227, + 'NamedAttributeStringArgument': 228, + 'DeclName': 229, + 'PoundAssertStmt': 230, + 'CallDecl': 231, } diff --git a/utils/gyb_syntax_support/Token.py b/utils/gyb_syntax_support/Token.py index c6e331491634f..f819591b71600 100644 --- a/utils/gyb_syntax_support/Token.py +++ b/utils/gyb_syntax_support/Token.py @@ -139,6 +139,7 @@ def macro_name(self): SYNTAX_TOKENS = [ # Keywords that start decls DeclKeyword('Associatedtype', 'associatedtype', serialization_code=1), + DeclKeyword('Call', 'call', serialization_code=119), DeclKeyword('Class', 'class', serialization_code=2), DeclKeyword('Deinit', 'deinit', serialization_code=3), DeclKeyword('Enum', 'enum', serialization_code=4), From 2456a6e63eba487cc7ce7ab39376c84b7cd28a19 Mon Sep 17 00:00:00 2001 From: Dan Zheng Date: Tue, 26 Mar 2019 21:51:07 -0700 Subject: [PATCH 2/4] Finish main callable functionality. - Use uniform naming: either "`call` member" or "`call` declaration". - Fix `call` member resolution during type-checking. - Enable more `func` attributes on `call` declarations. - Add tests. --- include/swift/AST/Attr.def | 43 ++++----- include/swift/AST/Decl.h | 22 ----- include/swift/AST/DiagnosticsSema.def | 14 +-- lib/AST/Decl.cpp | 4 - lib/Sema/CSApply.cpp | 25 ++++-- lib/Sema/CSSimplify.cpp | 124 ++++---------------------- lib/Sema/ConstraintSystem.h | 3 - lib/Sema/TypeCheckAttr.cpp | 2 +- lib/Sema/TypeCheckDecl.cpp | 27 +----- lib/Serialization/Serialization.cpp | 3 - test/Parse/call_decl.swift | 1 + test/decl/call/callables.swift | 86 +++++++++++++++++- test/decl/call/generic.swift | 26 ++++-- test/decl/call/protocol.swift | 51 +++++++---- 14 files changed, 212 insertions(+), 219 deletions(-) diff --git a/include/swift/AST/Attr.def b/include/swift/AST/Attr.def index b36a01dcb4e87..88491a927a32d 100644 --- a/include/swift/AST/Attr.def +++ b/include/swift/AST/Attr.def @@ -117,7 +117,7 @@ DECL_ATTR(available, Available, AllowMultipleAttributes | LongAttribute, 1) CONTEXTUAL_SIMPLE_DECL_ATTR(final, Final, - OnClass | OnFunc | OnAccessor | OnVar | OnSubscript | + OnClass | OnFunc | OnAccessor | OnCall | OnVar | OnSubscript | DeclModifier, 2) DECL_ATTR(objc, ObjC, @@ -129,7 +129,7 @@ CONTEXTUAL_SIMPLE_DECL_ATTR(required, Required, DeclModifier, 4) CONTEXTUAL_SIMPLE_DECL_ATTR(optional, Optional, - OnConstructor | OnFunc | OnAccessor | OnVar | OnSubscript | + OnConstructor | OnFunc | OnAccessor | OnCall | OnVar | OnSubscript | DeclModifier, 5) SIMPLE_DECL_ATTR(dynamicCallable, DynamicCallable, @@ -183,7 +183,7 @@ DECL_ATTR(_semantics, Semantics, AllowMultipleAttributes | UserInaccessible, 21) CONTEXTUAL_SIMPLE_DECL_ATTR(dynamic, Dynamic, - OnFunc | OnAccessor | OnVar | OnSubscript | OnConstructor | + OnFunc | OnAccessor | OnCall | OnVar | OnSubscript | OnConstructor | DeclModifier, 22) CONTEXTUAL_SIMPLE_DECL_ATTR(infix, Infix, @@ -199,13 +199,14 @@ CONTEXTUAL_SIMPLE_DECL_ATTR(postfix, Postfix, DeclModifier, 25) SIMPLE_DECL_ATTR(_transparent, Transparent, - OnFunc | OnAccessor | OnConstructor | OnVar | UserInaccessible, + OnFunc | OnAccessor | OnCall | OnConstructor | OnVar | UserInaccessible, 26) SIMPLE_DECL_ATTR(requires_stored_property_inits, RequiresStoredPropertyInits, OnClass, 27) SIMPLE_DECL_ATTR(nonobjc, NonObjC, - OnExtension | OnFunc | OnAccessor | OnVar | OnSubscript | OnConstructor, + OnExtension | OnFunc | OnAccessor | OnCall | OnVar | OnSubscript | + OnConstructor, 30) SIMPLE_DECL_ATTR(_fixed_layout, FixedLayout, OnVar | OnClass | OnStruct | @@ -215,23 +216,23 @@ SIMPLE_DECL_ATTR(inlinable, Inlinable, OnVar | OnSubscript | OnAbstractFunction, 32) DECL_ATTR(_specialize, Specialize, - OnConstructor | OnFunc | OnAccessor | + OnConstructor | OnFunc | OnAccessor | OnCall | AllowMultipleAttributes | LongAttribute | UserInaccessible, 33) SIMPLE_DECL_ATTR(objcMembers, ObjCMembers, OnClass, 34) CONTEXTUAL_SIMPLE_DECL_ATTR(__consuming, Consuming, - OnFunc | OnAccessor | + OnFunc | OnAccessor | OnCall | DeclModifier | UserInaccessible | NotSerialized, 40) CONTEXTUAL_SIMPLE_DECL_ATTR(mutating, Mutating, - OnFunc | OnAccessor | + OnFunc | OnAccessor | OnCall | DeclModifier | NotSerialized, 41) CONTEXTUAL_SIMPLE_DECL_ATTR(nonmutating, NonMutating, - OnFunc | OnAccessor | + OnFunc | OnAccessor | OnCall | DeclModifier | NotSerialized, 42) CONTEXTUAL_SIMPLE_DECL_ATTR(convenience, Convenience, @@ -239,7 +240,8 @@ CONTEXTUAL_SIMPLE_DECL_ATTR(convenience, Convenience, DeclModifier | NotSerialized, 43) CONTEXTUAL_SIMPLE_DECL_ATTR(override, Override, - OnFunc | OnAccessor | OnVar | OnSubscript | OnConstructor | OnAssociatedType | + OnFunc | OnAccessor | OnCall | OnVar | OnSubscript | OnConstructor | + OnAssociatedType | DeclModifier | NotSerialized, 44) SIMPLE_DECL_ATTR(_hasStorage, HasStorage, @@ -247,8 +249,8 @@ SIMPLE_DECL_ATTR(_hasStorage, HasStorage, UserInaccessible | NotSerialized, 45) DECL_ATTR(private, AccessControl, - OnFunc | OnAccessor | OnExtension | OnGenericType | OnVar | OnSubscript | - OnConstructor | + OnFunc | OnAccessor | OnCall | OnExtension | OnGenericType | OnVar | + OnSubscript | OnConstructor | DeclModifier | NotSerialized, 46) DECL_ATTR_ALIAS(fileprivate, AccessControl) @@ -296,7 +298,7 @@ DECL_ATTR(_alignment, Alignment, UserInaccessible, 56) SIMPLE_DECL_ATTR(rethrows, Rethrows, - OnFunc | OnAccessor | OnConstructor | + OnFunc | OnAccessor | OnCall | OnConstructor | RejectByParser, 57) DECL_ATTR(_swift_native_objc_runtime_base, SwiftNativeObjCRuntimeBase, @@ -307,7 +309,7 @@ CONTEXTUAL_SIMPLE_DECL_ATTR(indirect, Indirect, DeclModifier | OnEnum | OnEnumElement, 60) SIMPLE_DECL_ATTR(warn_unqualified_access, WarnUnqualifiedAccess, - OnFunc | OnAccessor /*| OnVar*/ | + OnFunc | OnAccessor | OnCall | /*OnVar |*/ LongAttribute, 61) SIMPLE_DECL_ATTR(_show_in_interface, ShowInInterface, @@ -315,7 +317,7 @@ SIMPLE_DECL_ATTR(_show_in_interface, ShowInInterface, UserInaccessible, 62) DECL_ATTR(_cdecl, CDecl, - OnFunc | OnAccessor | + OnFunc | OnAccessor | OnCall | LongAttribute | UserInaccessible, 63) SIMPLE_DECL_ATTR(usableFromInline, UsableFromInline, @@ -323,14 +325,14 @@ SIMPLE_DECL_ATTR(usableFromInline, UsableFromInline, LongAttribute, 64) SIMPLE_DECL_ATTR(discardableResult, DiscardableResult, - OnFunc | OnAccessor | OnConstructor | + OnFunc | OnAccessor | OnCall | OnConstructor | LongAttribute, 65) SIMPLE_DECL_ATTR(GKInspectable, GKInspectable, OnVar, 66) DECL_ATTR(_implements, Implements, - OnFunc | OnAccessor | OnVar | OnSubscript | OnTypeAlias | + OnFunc | OnAccessor | OnCall | OnVar | OnSubscript | OnTypeAlias | UserInaccessible | NotSerialized, 67) DECL_ATTR(_objcRuntimeName, ObjCRuntimeName, @@ -346,7 +348,7 @@ DECL_ATTR(_restatedObjCConformance, RestatedObjCConformance, NotSerialized, 70) // NOTE: 71 is unused SIMPLE_DECL_ATTR(_implicitly_unwrapped_optional, ImplicitlyUnwrappedOptional, - OnFunc | OnAccessor | OnVar | OnParam | OnSubscript | OnConstructor | + OnFunc | OnAccessor | OnCall | OnVar | OnParam | OnSubscript | OnConstructor | RejectByParser, 72) DECL_ATTR(_optimize, Optimize, @@ -358,7 +360,7 @@ DECL_ATTR(_clangImporterSynthesizedType, ClangImporterSynthesizedType, LongAttribute | RejectByParser | UserInaccessible | NotSerialized, 74) SIMPLE_DECL_ATTR(_weakLinked, WeakLinked, - OnNominalType | OnAssociatedType | OnFunc | OnAccessor | OnVar | + OnNominalType | OnAssociatedType | OnFunc | OnAccessor | OnCall | OnVar | OnSubscript | OnConstructor | OnEnumElement | OnExtension | UserInaccessible, 75) SIMPLE_DECL_ATTR(_frozen, Frozen, @@ -374,7 +376,8 @@ SIMPLE_DECL_ATTR(_hasInitialValue, HasInitialValue, UserInaccessible, 78) SIMPLE_DECL_ATTR(_nonoverride, NonOverride, - OnFunc | OnAccessor | OnVar | OnSubscript | OnConstructor | OnAssociatedType | + OnFunc | OnAccessor | OnCall | OnVar | OnSubscript | OnConstructor | + OnAssociatedType | UserInaccessible | NotSerialized, 79) DECL_ATTR(_dynamicReplacement, DynamicReplacement, diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index 995ca22f8d3df..6cfb78ad2b25a 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -3298,21 +3298,6 @@ class NominalTypeDecl : public GenericTypeDecl, public IterableDeclContext { ToStoredPropertyOrMissingMemberPlaceholder()); } -private: - /// Predicate used to filter CallDeclRange. - struct ToCallDecl { - ToCallDecl() {} - Optional operator()(Decl *decl) const; - }; - -public: - /// A range for iterating the call declarations of a nominal type. - using CallDeclRange = OptionalTransformRange; - - /// Return a collection of the call declarations of this nominal type. - CallDeclRange getCallDeclarations() const; - // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return D->getKind() >= DeclKind::First_NominalTypeDecl && @@ -6839,13 +6824,6 @@ ::operator()(Decl *decl) const { return None; } -inline Optional -NominalTypeDecl::ToCallDecl::operator()(Decl *decl) const { - if (auto callDecl = dyn_cast(decl)) - return callDecl; - return None; -} - inline void AbstractStorageDecl::overwriteSetterAccess(AccessLevel accessLevel) { Accessors.setInt(accessLevel); diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index ccc7d72958865..730b5b220e268 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -1692,15 +1692,15 @@ ERROR(witness_requires_class_implementation,none, (DeclName, Type)) ERROR(witness_not_accessible_proto,none, "%select{initializer %1|method %1|%select{|setter for }2property %1" - "|subscript%select{| setter}2}0 must be declared " + "|subscript%select{| setter}2|'call' member}0 must be declared " "%select{%error|fileprivate|internal|public|%error}3 because it matches a " "requirement in %select{private|fileprivate|internal|public|%error}4 protocol " "%5", (RequirementKind, DeclName, bool, AccessLevel, AccessLevel, DeclName)) ERROR(witness_not_accessible_type,none, "%select{initializer %1|method %1|%select{|setter for }2property %1" - "|subscript%select{| setter}2}0 must be as accessible as its enclosing " - "type because it matches a requirement in protocol %5", + "|subscript%select{| setter}2|'call' member}0 must be as accessible as " + "its enclosing type because it matches a requirement in protocol %5", (RequirementKind, DeclName, bool, AccessLevel, AccessLevel, DeclName)) ERROR(type_witness_not_accessible_proto,none, "%0 %1 must be declared %select{%error|fileprivate|internal|public|%error}2 " @@ -1776,11 +1776,13 @@ NOTE(missing_witnesses_general,none, "do you want to add protocol stubs?", NOTE(ambiguous_witnesses,none, "multiple matching " "%select{initializers named %1|functions named %1|properties named %1|" - "subscript operators}0 with type %2", (RequirementKind, DeclName, Type)) + "subscript operators|'call' member}0 with type %2", + (RequirementKind, DeclName, Type)) NOTE(ambiguous_witnesses_wrong_name,none, "multiple matching " "%select{initializers named %1|functions named %1|properties named %1|" - "subscript operators}0 with type %2", (RequirementKind, DeclName, Type)) + "subscript operators|'call' member}0 with type %2", + (RequirementKind, DeclName, Type)) NOTE(no_witnesses_type,none, "protocol requires nested type %0; do you want to add it?", (Identifier)) NOTE(default_associated_type_req_fail,none, @@ -1844,7 +1846,7 @@ NOTE(protocol_witness_renamed,none, "rename to %0 to satisfy this requirement%1", (DeclName, StringRef)) NOTE(protocol_witness_kind_conflict,none, "candidate is not %select{an initializer|a function|a variable|" - "a subscript}0", (RequirementKind)) + "a subscript|a 'call' member}0", (RequirementKind)) NOTE(protocol_witness_type_conflict,none, "candidate has non-matching type %0%1", (Type, StringRef)) NOTE(protocol_witness_missing_requirement,none, diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index ad51923995cb9..4b7f7023009c6 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -3216,10 +3216,6 @@ auto NominalTypeDecl::getStoredProperties(bool skipInaccessible) const ToStoredProperty(skipInaccessible)); } -auto NominalTypeDecl::getCallDeclarations() const -> CallDeclRange { - return CallDeclRange(getMembers(), ToCallDecl()); -} - bool NominalTypeDecl::isOptionalDecl() const { return this == getASTContext().getOptionalDecl(); } diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index c6f002ed8a021..823eab8f16594 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -7134,6 +7134,9 @@ Expr *ExprRewriter::finishApply(ApplyExpr *apply, Type openedType, }; // The function is always an rvalue. + // Save the original potentially lvalue function for rewriting `call` member + // applications. + auto *originalFn = fn; fn = cs.coerceToRValue(fn); // Resolve applications of decls with special semantics. @@ -7320,24 +7323,36 @@ Expr *ExprRewriter::finishApply(ApplyExpr *apply, Type openedType, return finishApply(apply, openedType, locator); } - // Handle `call` method applications. + // Handle `call` member applications. auto &ctx = cs.getASTContext(); TupleExpr *arg = dyn_cast(apply->getArg()); if (auto parenExpr = dyn_cast(apply->getArg())) arg = TupleExpr::createImplicit(ctx, parenExpr->getSubExpr(), {}); - // Get resolved `call` method and verify it. + // Get resolved `call` member and verify it. auto loc = locator.withPathElement(ConstraintLocator::ApplyFunction); auto selected = solution.getOverloadChoice(cs.getConstraintLocator(loc)); auto choice = selected.choice; if (auto *method = dyn_cast(selected.choice.getDecl())) { + auto methodType = selected.openedFullType->castTo(); bool isDynamic = choice.getKind() == OverloadChoiceKind::DeclViaDynamic; auto callDeclLocator = cs.getConstraintLocator( locator.withPathElement(ConstraintLocator::ApplyFunction) .withPathElement(ConstraintLocator::CallMember)); - // Create direct reference to `call` method. - Expr *declRef = buildMemberRef(fn, selected.openedFullType, + assert(methodType->getNumParams() == 1); + auto selfParam = methodType->getParams().front(); + // Diagnose `mutating` method call on immutable value. + if (!cs.getType(originalFn)->hasLValueType() && selfParam.isInOut()) { + AssignmentFailure failure( + originalFn, cs, originalFn->getLoc(), + diag::cannot_pass_rvalue_mutating_subelement, + diag::cannot_pass_rvalue_mutating); + failure.diagnose(); + return nullptr; + } + // Create direct reference to `call` member. + Expr *declRef = buildMemberRef(originalFn, selected.openedFullType, /*dotLoc=*/SourceLoc(), choice, DeclNameLoc(fn->getEndLoc()), selected.openedType, locator, @@ -7347,7 +7362,7 @@ Expr *ExprRewriter::finishApply(ApplyExpr *apply, Type openedType, if (!declRef) return nullptr; declRef->setImplicit(apply->isImplicit()); - apply->setFn(declRef) ; + apply->setFn(declRef); Expr *result = apply; cs.TC.typeCheckExpression(result, cs.DC); cs.cacheExprTypes(result); diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index 1fefb2cc71dad..8f1f735b1543f 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -5228,107 +5228,6 @@ Type ConstraintSystem::simplifyAppliedOverloads( return fnType; } -/// Returns the `call` declarations (if they exist) implemented or inherited -/// by a type. -/// This function may be slow for deep class hierarchies and multiple protocol -/// conformances, but it is invoked only after other constraint simplification -/// rules fail. -static llvm::DenseSet -getCallDeclarations(Type type, ConstraintSystem &CS, - const ConstraintLocatorBuilder &locator) { - auto canType = type->getCanonicalType(); - auto it = CS.CallDeclCache.find(canType); - if (it != CS.CallDeclCache.end()) return it->second; - - // Calculate `call` declarations for composite types with multiple components - // (protocol composition types and archetypes). - auto calculateForComponentTypes = - [&](ArrayRef componentTypes) -> llvm::DenseSet { - llvm::DenseSet callDecls; - for (auto componentType : componentTypes) { - auto *nominal = componentType->getAnyNominal(); - callDecls.insert(nominal->getCallDeclarations().begin(), - nominal->getCallDeclarations().end()); - } - return callDecls; - }; - - // Calculate `call` declarations. - auto calculate = [&]() -> llvm::DenseSet { - // If this is an archetype type, check if any types it conforms to - // (superclass or protocols) have`call` declarations. - if (auto archetype = dyn_cast(canType)) { - SmallVector componentTypes; - for (auto protocolDecl : archetype->getConformsTo()) - componentTypes.push_back(protocolDecl->getDeclaredType()); - if (auto superclass = archetype->getSuperclass()) - componentTypes.push_back(superclass); - return calculateForComponentTypes(componentTypes); - } - - // If this is a protocol composition, check if any of its members have - // `call` declarations. - if (auto protocolComp = dyn_cast(canType)) - return calculateForComponentTypes(protocolComp->getMembers()); - - // Otherwise, this must be a nominal type. - // Structural types cannot define `call` declarations. - auto nominal = canType->getAnyNominal(); - if (!nominal) return llvm::DenseSet(); - - // If this type conforms to protocols, look up all of their `call` - // declaration requirements. - // FIXME: Fix this to handle overridden requirements, e.g. using - // `OverriddenDeclsRequest`. Mimic logic from or unify logic with - // `lookupQualified`. - llvm::DenseSet callDecls; - for (auto p : nominal->getAllProtocols()) { - if (p->getCallDeclarations().empty()) - continue; - /* - for (auto *callDecl : p->getCallDeclarations()) - if (callDecl->isProtocolRequirement()) - callDecls.insert(callDecl); - */ - callDecls.insert(p->getCallDeclarations().begin(), - p->getCallDeclarations().end()); - } - // Hack: if any are found, return them directly. See FIXME above. - if (!callDecls.empty()) - return callDecls; - - // Walk superclasses, if present. - llvm::SmallPtrSet visitedDecls; - while (1) { - // If we found a circular parent class chain, reject this. - if (!visitedDecls.insert(nominal).second) - return llvm::DenseSet(); - - // If this type has the attribute on it, then look up the methods. - if (!nominal->getCallDeclarations().empty()) { - callDecls.insert(nominal->getCallDeclarations().begin(), - nominal->getCallDeclarations().end()); - } - - // If this type is a class with a superclass, check superclasses. - if (auto *cd = dyn_cast(nominal)) { - if (auto superClass = cd->getSuperclassDecl()) { - nominal = superClass; - continue; - } - } - - return callDecls; - } - }; - - auto result = calculate(); - // Cache the result if the type does not contain type variables. - if (!type->hasTypeVariable()) - CS.CallDeclCache[canType] = result; - return result; -} - ConstraintSystem::SolutionKind ConstraintSystem::simplifyApplicableFnConstraint( Type type1, @@ -5490,18 +5389,27 @@ ConstraintSystem::simplifyApplicableFnConstraint( return simplified; } - // TODO: WIP! - // Handle `call` declaration application. + // Handle applications of types with `call` members. if (auto nominal = desugar2->getAnyNominal()) { - auto callDecls = getCallDeclarations(desugar2, *this, locator); + auto &ctx = getASTContext(); + // Get all `call` members of the nominal type. + SmallVector callDecls; + auto candidates = TC.lookupMember(DC, nominal->getDeclaredTypeInContext(), + DeclName(ctx.getIdentifier("call"))); + for (auto entry : candidates) { + auto callDecl = dyn_cast(entry.getValueDecl()); + if (!callDecl) + continue; + callDecls.push_back(callDecl); + } - // Handle `call` method calls. + // Handle `call` member calls. if (!callDecls.empty()) { - // Create a type variable for the `call` method. + // Create a type variable for the `call` member. auto loc = getConstraintLocator(locator); auto tv = createTypeVariable(loc, TVO_CanBindToLValue); - // Record the `call` method overload set. + // Record the `call` member overload set. SmallVector choices; for (auto candidate : callDecls) { TC.validateDecl(candidate); @@ -5525,7 +5433,7 @@ ConstraintSystem::simplifyApplicableFnConstraint( tvParam, locatorBuilder); tvParams.push_back(AnyFunctionType::Param(tvParam)); } - // Create target function type and applicable function constraint. + // Create target function type and an applicable function constraint. AnyFunctionType *funcType = FunctionType::get(tvParams, func1->getResult()); addConstraint(ConstraintKind::ApplicableFunction, diff --git a/lib/Sema/ConstraintSystem.h b/lib/Sema/ConstraintSystem.h index 5637a8e1debf9..1c59765a652a7 100644 --- a/lib/Sema/ConstraintSystem.h +++ b/lib/Sema/ConstraintSystem.h @@ -1080,9 +1080,6 @@ class ConstraintSystem { /// The locators of \c Defaultable constraints whose defaults were used. SmallVector DefaultedConstraints; - /// A cache that stores the `call` declarations of a type. - llvm::DenseMap> CallDeclCache; - /// A cache that stores the @dynamicCallable required methods implemented by /// types. llvm::DenseMap DynamicCallableCache; diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp index 532a1631601f6..5a0f6cb2aaac4 100644 --- a/lib/Sema/TypeCheckAttr.cpp +++ b/lib/Sema/TypeCheckAttr.cpp @@ -949,7 +949,7 @@ static bool hasValidDynamicCallableMethod(TypeChecker &TC, }); // If there are no valid candidates, return false. - if (candidates.size() == 0) return false; + if (candidates.empty()) return false; return true; } diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index cc07817718826..4fe23ccc646db 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -3843,7 +3843,8 @@ void TypeChecker::validateDecl(ValueDecl *D) { } case DeclKind::Func: - case DeclKind::Accessor: { + case DeclKind::Accessor: + case DeclKind::Call: { auto *FD = cast(D); assert(!FD->hasInterfaceType()); @@ -4156,30 +4157,6 @@ void TypeChecker::validateDecl(ValueDecl *D) { break; } - case DeclKind::Call: { - auto *CD = cast(D); - DeclValidationRAII IBV(CD); - validateGenericFuncSignature(CD); - CD->setSignatureIsValidated(); - checkDeclAttributesEarly(CD); - validateAttributes(*this, CD); - - auto *TyR = CD->getBodyResultTypeLoc().getTypeRepr(); - if (TyR && TyR->getKind() == TypeReprKind::ImplicitlyUnwrappedOptional) { - auto &C = CD->getASTContext(); - CD->getAttrs().add( - new (C) ImplicitlyUnwrappedOptionalAttr(/* implicit= */ true)); - } - - // Member subscripts need some special validation logic. - if (CD->getDeclContext()->isTypeContext()) { - // If this is a class member, mark it final if the class is final. - inferFinalAndDiagnoseIfNeeded(*this, CD, StaticSpellingKind::None); - } - - break; - } - case DeclKind::EnumElement: { auto *EED = cast(D); EnumDecl *ED = EED->getParentEnum(); diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index 5345aa4fd3b7e..bd97d76818b15 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -3410,9 +3410,6 @@ void Serializer::writeDecl(const Decl *D) { break; } - // TODO: Revisit serialization. - // Create `CallLayout`? Not all fields from `FuncLayout` are necessary: - // `call` declarations cannot be static. case DeclKind::Call: { auto fn = cast(D); verifyAttrSerializable(fn); diff --git a/test/Parse/call_decl.swift b/test/Parse/call_decl.swift index 563442d0bf9c0..f1e1266bbe52d 100644 --- a/test/Parse/call_decl.swift +++ b/test/Parse/call_decl.swift @@ -88,3 +88,4 @@ func call(_ fn: () -> Void) {} // expression call() {} +call {} diff --git a/test/decl/call/callables.swift b/test/decl/call/callables.swift index e06e1a8fd0534..a9ee529ecc94c 100644 --- a/test/decl/call/callables.swift +++ b/test/decl/call/callables.swift @@ -12,7 +12,7 @@ let foo = SimpleCallable() _ = foo(1) _ = foo(foo(1)) -// Test direct `call` method references. +// Test direct `call` member references. _ = foo.call(1) _ = [1, 2, 3].map(foo.call) @@ -46,12 +46,94 @@ struct MultipleArgsCallable { } let bar = MultipleArgsCallable() - _ = bar(x: 1, y: 1) _ = bar.call(x: 1, y: 1) _ = bar(x: bar.call(x: 1, y: 1)[0], y: 1) _ = bar.call(x: bar(x: 1, y: 1)[0], y: 1) +struct Extended {} +extension Extended { + @discardableResult + call() -> Extended { + return self + } +} +var extended = Extended() +extended()().call()() + +struct OptionalCallable { + call() -> OptionalCallable? { + return self + } +} +var optional = OptionalCallable() +_ = optional()?.call()?() + +struct VariadicCallable { + call(_ args: Int...) -> [Int] { + return args + } +} +var variadic = VariadicCallable() +_ = variadic() +_ = variadic(1, 2, 3) + +struct Mutating { + var x: Int + mutating call() { + x += 1 + } +} +func testMutating(_ x: Mutating, _ y: inout Mutating) { + _ = x() // expected-error {{cannot use mutating member on immutable value: 'x' is a 'let' constant}} + _ = x.call() // expected-error {{cannot use mutating member on immutable value: 'x' is a 'let' constant}} + _ = y() + _ = y.call() +} + +struct Throwing { + call() throws -> Throwing { + return self + } +} +var throwing = Throwing() +_ = try throwing() + +enum BinaryOperation { + case add, subtract, multiply, divide +} +extension BinaryOperation { + call(_ lhs: Float, _ rhs: Float) -> Float { + switch self { + case .add: return lhs + rhs + case .subtract: return lhs - rhs + case .multiply: return lhs * rhs + case .divide: return lhs / rhs + } + } +} +_ = BinaryOperation.add(1, 2) + +class BaseClass { + call() -> Self { + return self + } +} +class SubClass : BaseClass { + override call() -> Self { + return self + } +} + +func testIUO(a: SimpleCallable!, b: MultipleArgsCallable!, c: Extended!, + d: OptionalCallable!, e: Throwing!) { + _ = a(1) + _ = b(x: 1, y: 1) + _ = c() + _ = d()?.call()?() + _ = try? e() +} + // Errors. // TODO: Fix this error. Ideally, it should be "extra argument in call". diff --git a/test/decl/call/generic.swift b/test/decl/call/generic.swift index f95a4ab2a7bb2..60abbc843e785 100644 --- a/test/decl/call/generic.swift +++ b/test/decl/call/generic.swift @@ -1,6 +1,6 @@ // RUN: %target-typecheck-verify-swift -protocol P { +protocol P0 { call(x: Self) } @@ -14,14 +14,30 @@ struct ConcreteType { } } -struct GenericType { -} - let concrete = ConcreteType() _ = concrete(1, 3.0) _ = concrete(concrete, concrete.call as ([Int], Float) -> ([Int], Float)) -func genericContext(_ x: T, _ y: U) { +func generic(_ x: T, _ y: U) { _ = concrete(x, x) _ = concrete(x, y) } + +struct GenericType { + let collection: T + call(_ x: U) -> Bool where U == T.Element, U : Equatable { + return collection.contains(x) + } +} + +// Test conditional conformance. +extension GenericType where T.Element : Numeric { + call(initialValue: T.Element) -> T.Element { + return collection.reduce(initialValue, +) + } +} + +let genericString = GenericType<[String]>(collection: ["Hello", "world", "!"]) +_ = genericString("Hello") +let genericInt = GenericType>(collection: [1, 2, 3]) +_ = genericInt(initialValue: 1) diff --git a/test/decl/call/protocol.swift b/test/decl/call/protocol.swift index 99760d29ee01b..55bda8528a463 100644 --- a/test/decl/call/protocol.swift +++ b/test/decl/call/protocol.swift @@ -1,34 +1,55 @@ // RUN: %target-typecheck-verify-swift +protocol P0 { + // expected-note @+1 {{protocol requires 'call' member with type '() -> Missing'; do you want to add a stub?}} + call() -> Self +} + protocol P1 { call() -> Self } extension P1 { + // expected-note @+1 {{found this candidate}} call() -> Self { return self } } +protocol P2 {} +extension P2 { + // expected-note @+1 {{found this candidate}} + call(x: Int, y: Int) -> Int { + return x + y + } +} -struct Missing : P1 {} +// expected-error @+1 {{type 'Missing' does not conform to protocol 'P0'}} +struct Missing : P0 {} +struct S0 : P0 { + @discardableResult + call() -> Self { return self } +} +let s0 = S0() +s0() struct S1 : P1 { - call() -> S1 { - return self - } + call() -> S1 { return self } } let s1 = S1() -_ = s1()()() +_ = s1()() -protocol P2 {} -extension P2 { - call() -> Self { - return self - } +struct Conforming : P0 & P1 & P2 {} +let conforming = Conforming() +_ = conforming(x: 1, y: 2) +_ = conforming().call(x:y:)(1, 2) +_ = conforming.call(x:y:) +_ = conforming.call // expected-error {{ambiguous use of 'call'}} + +protocol P3 {} +extension P3 { + call() -> Self { return self } } -struct S2 : P2 {} +struct S3 : P3 {} -let s2 = S2() -// TODO: Fix this by fixing `getCallDeclarations` logic in CSSimplify.cpp. -// Need to handle overriding declarations; mimic/unify code with `lookupQualified`. -// _ = s2()()() +let s3 = S3() +_ = s3()() From efc864d6b2be27faa097f43eb098bf005fc3ee7a Mon Sep 17 00:00:00 2001 From: Dan Zheng Date: Wed, 27 Mar 2019 11:33:22 -0700 Subject: [PATCH 3/4] Update clang version in update-checkout-config.json. clang requires minor changes to support `call` declarations in Swift. Note: the clang remote should be reverted back to "apple/swift-clang". --- utils/update_checkout/update-checkout-config.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utils/update_checkout/update-checkout-config.json b/utils/update_checkout/update-checkout-config.json index ed9320456f49a..6d02ce90a4267 100644 --- a/utils/update_checkout/update-checkout-config.json +++ b/utils/update_checkout/update-checkout-config.json @@ -5,7 +5,7 @@ "llvm": { "remote": { "id": "apple/swift-llvm" } }, "clang": { - "remote": { "id": "apple/swift-clang" } }, + "remote": { "id": "dan-zheng/swift-clang" } }, "swift": { "remote": { "id": "apple/swift" } }, "lldb": { @@ -53,7 +53,7 @@ "aliases": ["master", "stable"], "repos": { "llvm": "stable", - "clang": "stable", + "clang": "callable", "swift": "master", "lldb": "stable", "cmark": "master", From 3687d07d5bf035e810eca487e9152eefa4cff11f Mon Sep 17 00:00:00 2001 From: Dan Zheng Date: Wed, 27 Mar 2019 12:03:07 -0700 Subject: [PATCH 4/4] Minor edits. - Parse "call" as identifier in patterns and enum case names. Add tests. - Disallow `@warn_unqualified_access` on `call` declarations. - Update failing attribute tests. --- include/swift/AST/Attr.def | 2 +- lib/Parse/ParseDecl.cpp | 2 +- lib/Parse/ParsePattern.cpp | 3 ++- lib/Parse/Parser.cpp | 2 +- lib/Sema/TypeCheckAttr.cpp | 1 + test/Parse/call_decl.swift | 15 +++++++++++++++ test/Sema/immutability.swift | 2 +- test/attr/attr_cdecl.swift | 6 +++--- 8 files changed, 25 insertions(+), 8 deletions(-) diff --git a/include/swift/AST/Attr.def b/include/swift/AST/Attr.def index 88491a927a32d..d6b1f92e30dfe 100644 --- a/include/swift/AST/Attr.def +++ b/include/swift/AST/Attr.def @@ -309,7 +309,7 @@ CONTEXTUAL_SIMPLE_DECL_ATTR(indirect, Indirect, DeclModifier | OnEnum | OnEnumElement, 60) SIMPLE_DECL_ATTR(warn_unqualified_access, WarnUnqualifiedAccess, - OnFunc | OnAccessor | OnCall | /*OnVar |*/ + OnFunc | OnAccessor | /*OnVar |*/ LongAttribute, 61) SIMPLE_DECL_ATTR(_show_in_interface, ShowInInterface, diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 36d848ff85eee..c725594dc6bc5 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -5930,7 +5930,7 @@ Parser::parseDeclEnumCase(ParseDeclOptions Flags, return Status; } - if (Tok.is(tok::identifier)) { + if (Tok.is(tok::identifier) || Tok.is(tok::kw_call)) { Status |= parseIdentifierDeclName(*this, Name, NameLoc, "enum 'case'", tok::l_paren, tok::kw_case, tok::colon, tok::r_brace); diff --git a/lib/Parse/ParsePattern.cpp b/lib/Parse/ParsePattern.cpp index 450db31fc7c18..ddd409c6fd177 100644 --- a/lib/Parse/ParsePattern.cpp +++ b/lib/Parse/ParsePattern.cpp @@ -921,7 +921,8 @@ ParserResult Parser::parsePattern() { PatternCtx.setCreateSyntax(SyntaxKind::WildcardPattern); return makeParserResult(new (Context) AnyPattern(consumeToken(tok::kw__))); - case tok::identifier: { + case tok::identifier: + case tok::kw_call: { PatternCtx.setCreateSyntax(SyntaxKind::IdentifierPattern); Identifier name; SourceLoc loc = consumeIdentifier(&name); diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index 1effd9dc30b03..ba861fe9f4ae2 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -864,7 +864,7 @@ bool Parser::parseSpecificIdentifier(StringRef expected, SourceLoc &loc, /// its name in Result. Otherwise, emit an error and return true. bool Parser::parseAnyIdentifier(Identifier &Result, SourceLoc &Loc, const Diagnostic &D) { - if (Tok.is(tok::identifier) || Tok.isAnyOperator()) { + if (Tok.is(tok::identifier) || Tok.isAnyOperator() || Tok.is(tok::kw_call)) { Result = Context.getIdentifier(Tok.getText()); Loc = Tok.getLoc(); consumeToken(); diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp index 5a0f6cb2aaac4..6eef0fc98c387 100644 --- a/lib/Sema/TypeCheckAttr.cpp +++ b/lib/Sema/TypeCheckAttr.cpp @@ -690,6 +690,7 @@ void TypeChecker::checkDeclAttributesEarly(Decl *D) { StringRef OnlyKind; switch (PossibleDeclKinds) { case DeclAttribute::OnAccessor: OnlyKind = "accessor"; break; + case DeclAttribute::OnCall: OnlyKind = "call"; break; case DeclAttribute::OnClass: OnlyKind = "class"; break; case DeclAttribute::OnConstructor: OnlyKind = "init"; break; case DeclAttribute::OnDestructor: OnlyKind = "deinit"; break; diff --git a/test/Parse/call_decl.swift b/test/Parse/call_decl.swift index f1e1266bbe52d..7a7d2860e0158 100644 --- a/test/Parse/call_decl.swift +++ b/test/Parse/call_decl.swift @@ -6,6 +6,21 @@ struct SimpleCallable { } } +// Test source compatibility with existing usages of "call" as an identifier. + +struct CallFuncMember { + func call() {} +} +struct CallVarMember { + var call: Int +} +enum CallCase { + case call(call: Int) +} +protocol CallRequirement { + func call() +} + struct NoRedefinitionErrors { call(_ x: Int) -> Int { return x diff --git a/test/Sema/immutability.swift b/test/Sema/immutability.swift index 7043fbe1e8dc4..0e71cdeeafa8f 100644 --- a/test/Sema/immutability.swift +++ b/test/Sema/immutability.swift @@ -59,7 +59,7 @@ class FooClass { self = FooClass() // expected-error {{cannot assign to value: 'self' is immutable}} } - mutating init(a : Bool) {} // expected-error {{'mutating' may only be used on 'func' declarations}} {{3-12=}} + mutating init(a : Bool) {} // expected-error {{'mutating' modifier cannot be applied to this declaration}} {{3-12=}} mutating // expected-error {{'mutating' isn't valid on methods in classes or class-bound protocols}} {{3-12=}} func baz() {} diff --git a/test/attr/attr_cdecl.swift b/test/attr/attr_cdecl.swift index 85891cc12be02..f944caf319b20 100644 --- a/test/attr/attr_cdecl.swift +++ b/test/attr/attr_cdecl.swift @@ -8,7 +8,7 @@ func emptyName(x: Int) -> Int { return x } @_cdecl("noBody") func noBody(x: Int) -> Int // expected-error{{expected '{' in body of function}} -@_cdecl("property") // expected-error{{may only be used on 'func' declarations}} +@_cdecl("property") // expected-error{{cannot be applied to this declaration}} var property: Int var computed: Int { @@ -40,10 +40,10 @@ class Foo { @_cdecl("Foo_foo_2") // expected-error{{can only be applied to global functions}} static func foo(x: Int) -> Int { return x } - @_cdecl("Foo_init") // expected-error{{may only be used on 'func'}} + @_cdecl("Foo_init") // expected-error{{cannot be applied to this declaration}} init() {} - @_cdecl("Foo_deinit") // expected-error{{may only be used on 'func'}} + @_cdecl("Foo_deinit") // expected-error{{cannot be applied to this declaration}} deinit {} }