Skip to content

[Evaluator] Separate formation of a request from evaluation of that request #17643

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

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
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
18 changes: 18 additions & 0 deletions include/swift/AST/DiagnosticsCommon.def
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,24 @@ ERROR(attr_only_on_parameters, none,
ERROR(function_type_no_parens,none,
"single argument function types require parentheses", ())

//------------------------------------------------------------------------------
// MARK: Circular reference diagnostics
//------------------------------------------------------------------------------
ERROR(circular_reference, none,
"circular reference", ())

ERROR(redundant_type_alias_define, none,
"redundant type alias declaration", ())

NOTE(circular_reference_through, none,
"through reference here", ())

ERROR(circular_class_inheritance,none,
"%0 inherits from itself", (Identifier))

ERROR(circular_enum_inheritance,none,
"%0 has a raw type that depends on itself", (Identifier))

#ifndef DIAG_NO_UNDEF
# if defined(DIAG)
# undef DIAG
Expand Down
16 changes: 0 additions & 16 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -2155,8 +2155,6 @@ ERROR(superclass_not_open,none,
NOTE(superclass_here,none,"superclass is declared here", ())
ERROR(superclass_of_open_not_open,none,
"superclass %0 of open class must be open", (Type))
ERROR(circular_class_inheritance,none,
"%0 inherits from itself", (Identifier))
ERROR(inheritance_from_final_class,none,
"inheritance from a final class %0", (Identifier))
ERROR(inheritance_from_unspecialized_objc_generic_class,none,
Expand Down Expand Up @@ -2199,8 +2197,6 @@ ERROR(enum_stored_property,none,
// Enum raw types
ERROR(multiple_enum_raw_types,none,
"multiple enum raw types %0 and %1", (Type, Type))
ERROR(circular_enum_inheritance,none,
"%0 has a raw type that depends on itself", (Identifier))
ERROR(raw_type_not_first,none,
"raw type %0 must appear first in the enum inheritance clause", (Type))
ERROR(raw_type_not_literal_convertible,none,
Expand Down Expand Up @@ -4061,18 +4057,6 @@ WARNING(variable_never_read, none,
"%select{variable|parameter}1 %0 was written to, but never read",
(Identifier, unsigned))

//------------------------------------------------------------------------------
// MARK: Circular reference diagnostics
//------------------------------------------------------------------------------
ERROR(circular_reference, none,
"circular reference", ())

ERROR(redundant_type_alias_define, none,
"redundant type alias declaration", ())

NOTE(circular_reference_through, none,
"through reference here", ())

//------------------------------------------------------------------------------
// MARK: Debug diagnostics
//------------------------------------------------------------------------------
Expand Down
70 changes: 50 additions & 20 deletions include/swift/AST/Evaluator.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,23 @@ class raw_ostream;

namespace swift {

using llvm::ArrayRef;
using llvm::Optional;
using llvm::None;

class DiagnosticEngine;
class Evaluator;
class UnifiedStatsReporter;

/// An "abstract" request function pointer, which is the storage type
/// used for each of the
using AbstractRequestFunction = void(void);

/// Form the specific request function for the given request type.
template<typename Request>
using RequestFunction =
typename Request::OutputType(const Request &, Evaluator &);

/// Pretty stack trace handler for an arbitrary request.
template<typename Request>
class PrettyStackTraceRequest : public llvm::PrettyStackTraceEntry {
Expand All @@ -59,7 +70,7 @@ class PrettyStackTraceRequest : public llvm::PrettyStackTraceEntry {
};

/// Report that a request of the given kind is being evaluated, so it
/// can be recoded by the stats reporter.
/// can be recorded by the stats reporter.
template<typename Request>
void reportEvaluatedRequest(UnifiedStatsReporter &stats,
const Request &request) { }
Expand Down Expand Up @@ -138,6 +149,18 @@ class Evaluator {
/// non-null.
UnifiedStatsReporter *stats = nullptr;

/// A vector containing the abstract request functions that can compute
/// the result of a particular request within a given zone. The
/// \c uint8_t is the zone number of the request, and the array is
/// indexed by the index of the request type within that zone. Each
/// entry is a function pointer that will be reinterpret_cast'd to
///
/// RequestType::OutputType (*)(const RequestType &request,
/// Evaluator &evaluator);
/// and called to satisfy the request.
std::vector<std::pair<uint8_t, ArrayRef<AbstractRequestFunction *>>>
requestFunctionsByZone;

/// A vector containing all of the active evaluation requests, which
/// is treated as a stack and is used to detect cycles.
llvm::SetVector<AnyRequest> activeRequests;
Expand All @@ -156,6 +179,19 @@ class Evaluator {
/// so all clients must cope with cycles.
llvm::DenseMap<AnyRequest, std::vector<AnyRequest>> dependencies;

/// Retrieve the request function for the given zone and request IDs.
AbstractRequestFunction *getAbstractRequestFunction(uint8_t zoneID,
uint8_t requestID) const;

/// Retrieve the request function for the given request type.
template<typename Request>
auto getRequestFunction() const -> RequestFunction<Request> * {
auto abstractFn = getAbstractRequestFunction(TypeID<Request>::zoneID,
TypeID<Request>::localID);
assert(abstractFn && "No request function for request");
return reinterpret_cast<RequestFunction<Request> *>(abstractFn);
}

public:
/// Construct a new evaluator that can emit cyclic-dependency
/// diagnostics through the given diagnostics engine.
Expand All @@ -165,6 +201,13 @@ class Evaluator {
/// statistics will be recorded.
void setStatsReporter(UnifiedStatsReporter *stats) { this->stats = stats; }

/// Register the set of request functions for the given zone.
///
/// These functions will be called to evaluate any requests within that
/// zone.
void registerRequestFunctions(uint8_t zoneID,
ArrayRef<AbstractRequestFunction *> functions);

/// Evaluate the given request and produce its result,
/// consulting/populating the cache as required.
template<typename Request>
Expand Down Expand Up @@ -247,7 +290,7 @@ class Evaluator {
/// Update statistics.
if (stats) reportEvaluatedRequest(*stats, request);

return request(*this);
return getRequestFunction<Request>()(request, *this);
}

/// Get the result of a request, consulting an external cache
Expand All @@ -260,17 +303,8 @@ class Evaluator {
if (auto cached = request.getCachedResult())
return *cached;

// Clear out the dependencies on this request; we're going to recompute
// them now anyway.
dependencies[request].clear();

PrettyStackTraceRequest<Request> prettyStackTrace(request);

/// Update statistics.
if (stats) reportEvaluatedRequest(*stats, request);

// Service the request.
auto result = request(*this);
// Compute the result.
auto result = getResultUncached(request);

// Cache the result.
request.cacheResult(result);
Expand All @@ -293,12 +327,8 @@ class Evaluator {
return known->second.castTo<typename Request::OutputType>();
}

// Clear out the dependencies on this request; we're going to recompute
// them now anyway.
dependencies[request].clear();

// Evaluate the request.
auto result = request(*this);
// Compute the result.
auto result = getResultUncached(request);

// Cache the result.
cache.insert({anyRequest, result});
Expand All @@ -314,7 +344,7 @@ class Evaluator {
llvm::raw_ostream &out,
llvm::DenseSet<AnyRequest> &visitedAnywhere,
llvm::SmallVectorImpl<AnyRequest> &visitedAlongPath,
llvm::ArrayRef<AnyRequest> highlightPath,
ArrayRef<AnyRequest> highlightPath,
std::string &prefixStr,
bool lastChild) const;

Expand Down
14 changes: 0 additions & 14 deletions include/swift/AST/LazyResolver.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,20 +71,6 @@ class LazyResolver {
/// Resolve the "is Objective-C" bit for the given declaration.
virtual void resolveIsObjC(ValueDecl *VD) = 0;

/// Retrieve the superclass of the given class.
virtual Type getSuperclass(const ClassDecl *classDecl) = 0;

/// Retrieve the superclass of the given protocol.
virtual Type getSuperclass(const ProtocolDecl *protocolDecl) = 0;

/// Resolve the raw type of the given enum.
virtual Type getRawType(EnumDecl *enumDecl) = 0;

/// Get a specific inherited type from the given declaration.
virtual Type getInheritedType(
llvm::PointerUnion<TypeDecl *, ExtensionDecl *> decl,
unsigned index) = 0;

/// Resolve the trailing where clause of the given protocol in-place.
virtual void resolveTrailingWhereClause(ProtocolDecl *proto) = 0;

Expand Down
13 changes: 8 additions & 5 deletions include/swift/AST/SimpleRequest.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ enum class CacheKind {
/// important one takes an evaluator and the input values, then computes the
/// final result:
/// \code
/// Output operator()(Evaluator &evaluator, Inputs...) const;
/// Output evaluate(Evaluator &evaluator, Inputs...) const;
/// \endcode
///
/// The \c Derived class will also need to implement an operation to break a
Expand Down Expand Up @@ -105,8 +105,8 @@ class SimpleRequest {
template<size_t ...Indices>
Output callDerived(Evaluator &evaluator,
llvm::index_sequence<Indices...>) const {
static_assert(sizeof...(Indices) > 0, "Subclass must define operator()");
return asDerived()(evaluator, std::get<Indices>(storage)...);
static_assert(sizeof...(Indices) > 0, "Subclass must define evaluate()");
return asDerived().evaluate(evaluator, std::get<Indices>(storage)...);
}

template<size_t ...Indices>
Expand All @@ -130,8 +130,11 @@ class SimpleRequest {
explicit SimpleRequest(const Inputs& ...inputs)
: storage(inputs...) { }

OutputType operator()(Evaluator &evaluator) const {
return callDerived(evaluator, llvm::index_sequence_for<Inputs...>());
/// Request evaluation function that will be registered with the evaluator.
static OutputType evaluateRequest(const Derived &request,
Evaluator &evaluator) {
return request.callDerived(evaluator,
llvm::index_sequence_for<Inputs...>());
}

void diagnoseCycle(DiagnosticEngine &diags) const {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,14 @@ class InheritedTypeRequest :

public:
using SimpleRequest::SimpleRequest;
using SimpleRequest::operator();

private:
friend class SimpleRequest;

// Evaluation.
Type operator()(Evaluator &evaluator,
llvm::PointerUnion<TypeDecl *, ExtensionDecl *> decl,
unsigned index) const;
Type evaluate(Evaluator &evaluator,
llvm::PointerUnion<TypeDecl *, ExtensionDecl *> decl,
unsigned index) const;

public:
// Cycle handling
Expand All @@ -76,13 +75,12 @@ class SuperclassTypeRequest :
NominalTypeDecl *> {
public:
using SimpleRequest::SimpleRequest;
using SimpleRequest::operator();

private:
friend class SimpleRequest;

// Evaluation.
Type operator()(Evaluator &evaluator, NominalTypeDecl *classDecl) const;
Type evaluate(Evaluator &evaluator, NominalTypeDecl *classDecl) const;

public:
// Cycle handling
Expand All @@ -104,13 +102,12 @@ class EnumRawTypeRequest :
EnumDecl *> {
public:
using SimpleRequest::SimpleRequest;
using SimpleRequest::operator();

private:
friend class SimpleRequest;

// Evaluation.
Type operator()(Evaluator &evaluator, EnumDecl *enumDecl) const;
Type evaluate(Evaluator &evaluator, EnumDecl *enumDecl) const;

public:
// Cycle handling
Expand All @@ -124,8 +121,11 @@ class EnumRawTypeRequest :
void cacheResult(Type value) const;
};

#define SWIFT_TYPEID_ZONE 10
#define SWIFT_TYPEID_HEADER "swift/Sema/TypeCheckerTypeIDZone.def"
/// The zone number for the type checker.
#define SWIFT_TYPE_CHECKER_REQUESTS_TYPEID_ZONE 10

#define SWIFT_TYPEID_ZONE SWIFT_TYPE_CHECKER_REQUESTS_TYPEID_ZONE
#define SWIFT_TYPEID_HEADER "swift/AST/TypeCheckerTypeIDZone.def"
#include "swift/Basic/DefineTypeIDZone.h"

// Set up reporting of evaluated requests.
Expand All @@ -135,7 +135,7 @@ inline void reportEvaluatedRequest(UnifiedStatsReporter &stats, \
const RequestType &request) { \
++stats.getFrontendCounters().RequestType; \
}
#include "swift/Sema/TypeCheckerTypeIDZone.def"
#include "swift/AST/TypeCheckerTypeIDZone.def"
#undef SWIFT_TYPEID

} // end namespace swift
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//===--- ArithmeticEvaluatorTypeIDZone.def - --------------------*- C++ -*-===//
//===--- TypeCheckerTypeIDZone.def ------------------------------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
Expand Down
18 changes: 9 additions & 9 deletions include/swift/Basic/DefineTypeIDZone.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,15 @@ template<> struct TypeIDZoneTypes<SWIFT_TYPEID_ZONE> {
};

// Second pass: create specializations of TypeID for these types.
#define SWIFT_TYPEID_NAMED(Type, Name) \
template<> struct TypeID<Type> { \
static const uint64_t value = \
formTypeID(SWIFT_TYPEID_ZONE, \
TypeIDZoneTypes<SWIFT_TYPEID_ZONE>::Name); \
\
static llvm::StringRef getName() { \
return #Name; \
} \
#define SWIFT_TYPEID_NAMED(Type, Name) \
template<> struct TypeID<Type> { \
static const uint8_t zoneID = SWIFT_TYPEID_ZONE; \
static const uint8_t localID = \
TypeIDZoneTypes<SWIFT_TYPEID_ZONE>::Name; \
\
static const uint64_t value = formTypeID(zoneID, localID); \
\
static llvm::StringRef getName() { return #Name; } \
};

#define SWIFT_TYPEID_TEMPLATE1_NAMED(Template, Name, Param1, Arg1) \
Expand Down
2 changes: 1 addition & 1 deletion include/swift/Basic/Statistics.def
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ FRONTEND_STATISTIC(Sema, NumUnloadedLazyIterableDeclContexts)

/// All type check requests go into the Sema area.
#define SWIFT_TYPEID(NAME) FRONTEND_STATISTIC(Sema, NAME)
#include "swift/Sema/TypeCheckerTypeIDZone.def"
#include "swift/AST/TypeCheckerTypeIDZone.def"
#undef SWIFT_TYPEID

/// The next 10 statistics count 5 kinds of SIL entities present
Expand Down
8 changes: 8 additions & 0 deletions include/swift/Subsystems.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ namespace swift {
class DelayedParsingCallbacks;
class DiagnosticConsumer;
class DiagnosticEngine;
class Evaluator;
class FileUnit;
class GenericEnvironment;
class GenericParamList;
Expand Down Expand Up @@ -342,6 +343,13 @@ namespace swift {
struct Implementation;
Implementation &Impl;
};

/// Register the type checker's request functions with the evaluator.
///
/// Clients that form an ASTContext and will perform any semantic
/// queries should call this function after forming the ASTContext.
void registerTypeCheckerRequestFunctions(Evaluator &evaluator);

} // end namespace swift

#endif // SWIFT_SUBSYSTEMS_H
1 change: 1 addition & 0 deletions lib/AST/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ add_swift_library(swiftAST STATIC
SubstitutionMap.cpp
SwiftNameTranslation.cpp
Type.cpp
TypeCheckRequests.cpp
TypeJoinMeet.cpp
TypeRefinementContext.cpp
TypeRepr.cpp
Expand Down
Loading