Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce callables. #23517

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 80 additions & 7 deletions include/swift/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ namespace swift {
struct ASTNode;
class ASTPrinter;
class ASTWalker;
class CallDecl;
class ConstructorDecl;
class DestructorDecl;
class DiagnosticEngine;
Expand Down Expand Up @@ -137,6 +138,7 @@ enum class DescriptiveDeclKind : uint8_t {
GenericStruct,
GenericClass,
GenericType,
Call,
Subscript,
Constructor,
Destructor,
Expand Down Expand Up @@ -3296,6 +3298,21 @@ class NominalTypeDecl : public GenericTypeDecl, public IterableDeclContext {
ToStoredPropertyOrMissingMemberPlaceholder());
}

private:
/// Predicate used to filter CallDeclRange.
struct ToCallDecl {
ToCallDecl() {}
Optional<CallDecl *> operator()(Decl *decl) const;
};

public:
/// A range for iterating the call declarations of a nominal type.
using CallDeclRange = OptionalTransformRange<DeclRange,
ToCallDecl>;

/// 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 &&
Expand Down Expand Up @@ -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<const Decl*>(D));
Expand Down Expand Up @@ -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<const Decl*>(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,
Expand Down Expand Up @@ -6775,6 +6839,13 @@ ::operator()(Decl *decl) const {
return None;
}

inline Optional<CallDecl *>
NominalTypeDecl::ToCallDecl::operator()(Decl *decl) const {
if (auto callDecl = dyn_cast<CallDecl>(decl))
return callDecl;
return None;
}

inline void
AbstractStorageDecl::overwriteSetterAccess(AccessLevel accessLevel) {
Accessors.setInt(accessLevel);
Expand Down Expand Up @@ -6808,6 +6879,7 @@ inline ParamDecl **AbstractFunctionDecl::getImplicitSelfDeclStorage() {
return cast<DestructorDecl>(this)->getImplicitSelfDeclStorage();
case DeclKind::Func:
case DeclKind::Accessor:
case DeclKind::Call:
return cast<FuncDecl>(this)->getImplicitSelfDeclStorage();
}
}
Expand All @@ -6816,11 +6888,12 @@ inline ParamDecl **FuncDecl::getImplicitSelfDeclStorage() {
if (!hasImplicitSelfDecl())
return nullptr;

if (!isa<AccessorDecl>(this)) {
assert(getKind() == DeclKind::Func && "no new kinds of functions");
return reinterpret_cast<ParamDecl **>(this+1);
}
return reinterpret_cast<ParamDecl **>(static_cast<AccessorDecl*>(this)+1);
if (isa<AccessorDecl>(this))
return reinterpret_cast<ParamDecl **>(static_cast<AccessorDecl *>(this)+1);
else if (isa<CallDecl>(this))
return reinterpret_cast<ParamDecl **>(static_cast<CallDecl *>(this)+1);
assert(getKind() == DeclKind::Func && "no new kinds of functions");
return reinterpret_cast<ParamDecl **>(this+1);
}

inline DeclIterator &DeclIterator::operator++() {
Expand Down
3 changes: 2 additions & 1 deletion include/swift/AST/DeclNodes.def
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
10 changes: 10 additions & 0 deletions include/swift/AST/DiagnosticsParse.def
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
7 changes: 5 additions & 2 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -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 "
Expand Down Expand Up @@ -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?",
())
Expand Down
3 changes: 2 additions & 1 deletion include/swift/AST/DiagnosticsSema.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ namespace swift {
Constructor,
Func,
Var,
Subscript
Subscript,
Call
};

// Declare common diagnostics objects with their appropriate types.
Expand Down
4 changes: 2 additions & 2 deletions include/swift/AST/Identifier.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions include/swift/Demangling/DemangleNodes.def
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ NODE(BoundGenericOtherNominalType)
NODE(BoundGenericTypeAlias)
NODE(BoundGenericFunction)
NODE(BuiltinTypeName)
CONTEXT_NODE(CallDeclaration)
NODE(CFunctionPointer)
CONTEXT_NODE(Class)
NODE(ClassMetadataBaseOffset)
Expand Down
1 change: 1 addition & 0 deletions include/swift/IDE/CodeCompletion.h
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,7 @@ enum class CodeCompletionDeclKind {
Constructor,
Destructor,
Subscript,
Call,
StaticMethod,
InstanceMethod,
PrefixOperatorFunction,
Expand Down
1 change: 1 addition & 0 deletions include/swift/IDE/SyntaxModel.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ enum class SyntaxStructureKind : uint8_t {
EnumElement,
TypeAlias,
Subscript,
Call,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fyi will need a simple change to ModelASTWalker::walkToDeclPre() to actually emit this, and I think a possibly less-simple change to SyntaxModelContext::SyntaxModelContext() to classify tok::kw_call as identifer/keyword depending on context (this affects syntax highlighting).

AssociatedType,
GenericTypeParam,

Expand Down
8 changes: 7 additions & 1 deletion include/swift/Parse/Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -1005,6 +1006,8 @@ class Parser {
ParserResult<ProtocolDecl> parseDeclProtocol(ParseDeclOptions Flags,
DeclAttributes &Attributes);

ParserResult<CallDecl>
parseDeclCall(ParseDeclOptions Flags, DeclAttributes &Attributes);
ParserResult<SubscriptDecl>
parseDeclSubscript(ParseDeclOptions Flags, DeclAttributes &Attributes,
SmallVectorImpl<Decl *> &Decls);
Expand Down Expand Up @@ -1160,6 +1163,8 @@ class Parser {
Closure,
/// A subscript.
Subscript,
/// A call declaration.
Call,
/// A curried argument clause.
Curried,
/// An enum element.
Expand Down Expand Up @@ -1198,6 +1203,7 @@ class Parser {
DefaultArgumentInfo &defaultArgs);
ParserStatus parseFunctionSignature(Identifier functionName,
DeclName &fullName,
ParameterContextKind paramContext,
ParameterList *&bodyParams,
DefaultArgumentInfo &defaultArgs,
SourceLoc &throws,
Expand Down
6 changes: 6 additions & 0 deletions lib/AST/ASTDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand Down
16 changes: 16 additions & 0 deletions lib/AST/ASTMangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<CallDecl>(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<AbstractStorageDecl>(decl))
return appendAccessorEntity("p", storageDecl, decl->isStatic());
Expand Down
40 changes: 40 additions & 0 deletions lib/AST/ASTPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<SimpleIdentTypeRepr>(ResultTyLoc.getTypeRepr())) {
if (simId->getIdentifier().str() == "Self")
ResultTyLoc = TypeLoc::withoutLoc(ResultTy);
}
Printer << " -> ";
Printer.callPrintStructurePre(PrintStructureKind::FunctionReturnType);
if (decl->getAttrs().hasAttribute<ImplicitlyUnwrappedOptionalAttr>())
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 << " ";
Expand Down
3 changes: 2 additions & 1 deletion lib/AST/ASTScope.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<AbstractFunctionDecl>(decl);

// If we have a generic function and our parent isn't describing our generic
Expand Down
Loading