blob: 98ffa63f9a2bbf1931dca6c5fe14f6b63e642228 [file] [log] [blame]
//===--- TypeCheckRequests.cpp - Type Checking Requests ------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
#include "swift/AST/TypeCheckRequests.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/Decl.h"
#include "swift/AST/DiagnosticsCommon.h"
#include "swift/AST/Module.h"
#include "swift/AST/TypeLoc.h"
#include "swift/AST/TypeRepr.h"
#include "swift/AST/Types.h"
using namespace swift;
namespace swift {
// Implement the type checker type zone (zone 10).
#define SWIFT_TYPEID_ZONE SWIFT_TYPE_CHECKER_REQUESTS_TYPEID_ZONE
#define SWIFT_TYPEID_HEADER "swift/AST/TypeCheckerTypeIDZone.def"
#include "swift/Basic/ImplementTypeIDZone.h"
#undef SWIFT_TYPEID_ZONE
#undef SWIFT_TYPEID_HEADER
}
void swift::simple_display(
llvm::raw_ostream &out,
const llvm::PointerUnion<TypeDecl *, ExtensionDecl *> &value) {
if (auto type = value.dyn_cast<TypeDecl *>()) {
type->dumpRef(out);
return;
}
auto ext = value.get<ExtensionDecl *>();
simple_display(out, ext);
}
void swift::simple_display(llvm::raw_ostream &out,
const TypeResolutionStage &value) {
switch (value) {
case TypeResolutionStage::Structural:
out << "structural";
break;
case TypeResolutionStage::Interface:
out << "interface";
break;
case TypeResolutionStage::Contextual:
out << "contextual";
break;
}
}
//----------------------------------------------------------------------------//
// Inherited type computation.
//----------------------------------------------------------------------------//
TypeLoc &InheritedTypeRequest::getTypeLoc(
llvm::PointerUnion<TypeDecl *, ExtensionDecl *> decl,
unsigned index) const {
if (auto typeDecl = decl.dyn_cast<TypeDecl *>())
return typeDecl->getInherited()[index];
return decl.get<ExtensionDecl *>()->getInherited()[index];
}
void InheritedTypeRequest::diagnoseCycle(DiagnosticEngine &diags) const {
const auto &storage = getStorage();
auto &typeLoc = getTypeLoc(std::get<0>(storage), std::get<1>(storage));
diags.diagnose(typeLoc.getLoc(), diag::circular_reference);
}
void InheritedTypeRequest::noteCycleStep(DiagnosticEngine &diags) const {
const auto &storage = getStorage();
auto &typeLoc = getTypeLoc(std::get<0>(storage), std::get<1>(storage));
diags.diagnose(typeLoc.getLoc(), diag::circular_reference_through);
}
bool InheritedTypeRequest::isCached() const {
return std::get<2>(getStorage()) == TypeResolutionStage::Interface;
}
Optional<Type> InheritedTypeRequest::getCachedResult() const {
const auto &storage = getStorage();
auto &typeLoc = getTypeLoc(std::get<0>(storage), std::get<1>(storage));
if (typeLoc.wasValidated())
return typeLoc.getType();
return None;
}
void InheritedTypeRequest::cacheResult(Type value) const {
const auto &storage = getStorage();
auto &typeLoc = getTypeLoc(std::get<0>(storage), std::get<1>(storage));
typeLoc.setType(value);
}
//----------------------------------------------------------------------------//
// Superclass computation.
//----------------------------------------------------------------------------//
void SuperclassTypeRequest::diagnoseCycle(DiagnosticEngine &diags) const {
// FIXME: Improve this diagnostic.
auto nominalDecl = std::get<0>(getStorage());
diags.diagnose(nominalDecl, diag::circular_class_inheritance,
nominalDecl->getName());
}
void SuperclassTypeRequest::noteCycleStep(DiagnosticEngine &diags) const {
auto nominalDecl = std::get<0>(getStorage());
// FIXME: Customize this further.
diags.diagnose(nominalDecl, diag::circular_reference_through);
}
bool SuperclassTypeRequest::isCached() const {
return std::get<1>(getStorage()) == TypeResolutionStage::Interface;
}
Optional<Type> SuperclassTypeRequest::getCachedResult() const {
auto nominalDecl = std::get<0>(getStorage());
if (auto *classDecl = dyn_cast<ClassDecl>(nominalDecl))
if (classDecl->LazySemanticInfo.SuperclassType.getInt())
return classDecl->LazySemanticInfo.SuperclassType.getPointer();
if (auto *protocolDecl = dyn_cast<ProtocolDecl>(nominalDecl))
if (protocolDecl->LazySemanticInfo.SuperclassType.getInt())
return protocolDecl->LazySemanticInfo.SuperclassType.getPointer();
return None;
}
void SuperclassTypeRequest::cacheResult(Type value) const {
auto nominalDecl = std::get<0>(getStorage());
if (auto *classDecl = dyn_cast<ClassDecl>(nominalDecl))
classDecl->LazySemanticInfo.SuperclassType.setPointerAndInt(value, true);
if (auto *protocolDecl = dyn_cast<ProtocolDecl>(nominalDecl))
protocolDecl->LazySemanticInfo.SuperclassType.setPointerAndInt(value, true);
}
//----------------------------------------------------------------------------//
// Enum raw type computation.
//----------------------------------------------------------------------------//
void EnumRawTypeRequest::diagnoseCycle(DiagnosticEngine &diags) const {
// FIXME: Improve this diagnostic.
auto enumDecl = std::get<0>(getStorage());
diags.diagnose(enumDecl, diag::circular_enum_inheritance, enumDecl->getName());
}
void EnumRawTypeRequest::noteCycleStep(DiagnosticEngine &diags) const {
auto enumDecl = std::get<0>(getStorage());
// FIXME: Customize this further.
diags.diagnose(enumDecl, diag::circular_reference_through);
}
bool EnumRawTypeRequest::isCached() const {
return std::get<1>(getStorage()) == TypeResolutionStage::Interface;
}
Optional<Type> EnumRawTypeRequest::getCachedResult() const {
auto enumDecl = std::get<0>(getStorage());
if (enumDecl->LazySemanticInfo.RawType.getInt())
return enumDecl->LazySemanticInfo.RawType.getPointer();
return None;
}
void EnumRawTypeRequest::cacheResult(Type value) const {
auto enumDecl = std::get<0>(getStorage());
enumDecl->LazySemanticInfo.RawType.setPointerAndInt(value, true);
}
//----------------------------------------------------------------------------//
// Overridden decls computation.
//----------------------------------------------------------------------------//
void OverriddenDeclsRequest::diagnoseCycle(DiagnosticEngine &diags) const {
auto decl = std::get<0>(getStorage());
diags.diagnose(decl, diag::circular_reference);
}
void OverriddenDeclsRequest::noteCycleStep(DiagnosticEngine &diags) const {
auto decl = std::get<0>(getStorage());
diags.diagnose(decl, diag::circular_reference_through);
}
//----------------------------------------------------------------------------//
// isObjC computation.
//----------------------------------------------------------------------------//
void IsObjCRequest::diagnoseCycle(DiagnosticEngine &diags) const {
// FIXME: Improve this diagnostic.
auto decl = std::get<0>(getStorage());
diags.diagnose(decl, diag::circular_reference);
}
void IsObjCRequest::noteCycleStep(DiagnosticEngine &diags) const {
auto decl = std::get<0>(getStorage());
// FIXME: Customize this further.
diags.diagnose(decl, diag::circular_reference_through);
}
Optional<bool> IsObjCRequest::getCachedResult() const {
auto decl = std::get<0>(getStorage());
if (decl->LazySemanticInfo.isObjCComputed)
return decl->LazySemanticInfo.isObjC;
return None;
}
void IsObjCRequest::cacheResult(bool value) const {
auto decl = std::get<0>(getStorage());
decl->setIsObjC(value);
}
//----------------------------------------------------------------------------//
// isDynamic computation.
//----------------------------------------------------------------------------//
void IsDynamicRequest::diagnoseCycle(DiagnosticEngine &diags) const {
// FIXME: Improve this diagnostic.
auto decl = std::get<0>(getStorage());
diags.diagnose(decl, diag::circular_reference);
}
void IsDynamicRequest::noteCycleStep(DiagnosticEngine &diags) const {
auto decl = std::get<0>(getStorage());
// FIXME: Customize this further.
diags.diagnose(decl, diag::circular_reference_through);
}
Optional<bool> IsDynamicRequest::getCachedResult() const {
auto decl = std::get<0>(getStorage());
if (decl->LazySemanticInfo.isDynamicComputed)
return decl->LazySemanticInfo.isDynamic;
return None;
}
void IsDynamicRequest::cacheResult(bool value) const {
auto decl = std::get<0>(getStorage());
decl->setIsDynamic(value);
}
//----------------------------------------------------------------------------//
// Requirement computation.
//----------------------------------------------------------------------------//
WhereClauseOwner::WhereClauseOwner(Decl *decl)
: dc(decl->getInnermostDeclContext()), source(decl) { }
SourceLoc WhereClauseOwner::getLoc() const {
if (auto decl = source.dyn_cast<Decl *>())
return decl->getLoc();
if (auto attr = source.dyn_cast<SpecializeAttr *>())
return attr->getLocation();
return source.get<GenericParamList *>()->getWhereLoc();
}
void swift::simple_display(llvm::raw_ostream &out,
const WhereClauseOwner &owner) {
if (auto decl = owner.source.dyn_cast<Decl *>()) {
simple_display(out, decl);
} else if (owner.source.is<SpecializeAttr *>()) {
out << "@_specialize";
} else {
out << "(SIL generic parameter list)";
}
}
void RequirementRequest::diagnoseCycle(DiagnosticEngine &diags) const {
// FIXME: Improve this diagnostic.
auto owner = std::get<0>(getStorage());
diags.diagnose(owner.getLoc(), diag::circular_reference);
}
void RequirementRequest::noteCycleStep(DiagnosticEngine &diags) const {
auto owner = std::get<0>(getStorage());
// FIXME: Customize this further.
diags.diagnose(owner.getLoc(), diag::circular_reference_through);
}
MutableArrayRef<RequirementRepr>
RequirementRequest::getRequirements(WhereClauseOwner owner) {
if (auto genericParams = owner.source.dyn_cast<GenericParamList *>()) {
return genericParams->getRequirements();
}
if (auto attr = owner.source.dyn_cast<SpecializeAttr *>()) {
if (auto whereClause = attr->getTrailingWhereClause())
return whereClause->getRequirements();
return { };
}
auto decl = owner.source.dyn_cast<Decl *>();
if (!decl)
return { };
if (auto proto = dyn_cast<ProtocolDecl>(decl)) {
if (auto whereClause = proto->getTrailingWhereClause())
return whereClause->getRequirements();
return { };
}
if (auto assocType = dyn_cast<AssociatedTypeDecl>(decl)) {
if (auto whereClause = assocType->getTrailingWhereClause())
return whereClause->getRequirements();
}
if (auto genericContext = decl->getAsGenericContext()) {
if (auto genericParams = genericContext->getGenericParams())
return genericParams->getRequirements();
}
return { };
}
bool RequirementRequest::visitRequirements(
WhereClauseOwner owner, TypeResolutionStage stage,
llvm::function_ref<bool(Requirement, RequirementRepr*)> callback) {
auto &evaluator = owner.dc->getASTContext().evaluator;
auto requirements = getRequirements(owner);
for (unsigned index : indices(requirements)) {
// Resolve to a requirement.
auto req = evaluator(RequirementRequest{owner, index, stage});
if (req) {
// Invoke the callback. If it returns true, we're done.
if (callback(*req, &requirements[index]))
return true;
continue;
}
llvm::handleAllErrors(req.takeError(),
[](const CyclicalRequestError<RequirementRequest> &E) {
// cycle detected
});
}
return false;
}
RequirementRepr &RequirementRequest::getRequirement() const {
auto owner = std::get<0>(getStorage());
auto index = std::get<1>(getStorage());
return getRequirements(owner)[index];
}
bool RequirementRequest::isCached() const {
return std::get<2>(getStorage()) == TypeResolutionStage::Interface;
}
Optional<Requirement> RequirementRequest::getCachedResult() const {
auto &reqRepr = getRequirement();
switch (reqRepr.getKind()) {
case RequirementReprKind::TypeConstraint:
if (!reqRepr.getSubjectLoc().wasValidated() ||
!reqRepr.getConstraintLoc().wasValidated())
return None;
return Requirement(reqRepr.getConstraint()->getClassOrBoundGenericClass()
? RequirementKind::Superclass
: RequirementKind::Conformance,
reqRepr.getSubject(),
reqRepr.getConstraint());
case RequirementReprKind::SameType:
if (!reqRepr.getFirstTypeLoc().wasValidated() ||
!reqRepr.getSecondTypeLoc().wasValidated())
return None;
return Requirement(RequirementKind::SameType, reqRepr.getFirstType(),
reqRepr.getSecondType());
case RequirementReprKind::LayoutConstraint:
if (!reqRepr.getSubjectLoc().wasValidated())
return None;
return Requirement(RequirementKind::Layout, reqRepr.getSubject(),
reqRepr.getLayoutConstraint());
}
llvm_unreachable("unhandled kind");
}
void RequirementRequest::cacheResult(Requirement value) const {
auto &reqRepr = getRequirement();
switch (value.getKind()) {
case RequirementKind::Conformance:
case RequirementKind::Superclass:
reqRepr.getSubjectLoc().setType(value.getFirstType());
reqRepr.getConstraintLoc().setType(value.getSecondType());
break;
case RequirementKind::SameType:
reqRepr.getFirstTypeLoc().setType(value.getFirstType());
reqRepr.getSecondTypeLoc().setType(value.getSecondType());
break;
case RequirementKind::Layout:
reqRepr.getSubjectLoc().setType(value.getFirstType());
reqRepr.getLayoutConstraintLoc()
.setLayoutConstraint(value.getLayoutConstraint());
break;
}
}
//----------------------------------------------------------------------------//
// USR computation.
//----------------------------------------------------------------------------//
void USRGenerationRequest::diagnoseCycle(DiagnosticEngine &diags) const {
const auto &storage = getStorage();
auto &d = std::get<0>(storage);
diags.diagnose(d, diag::circular_reference);
}
void USRGenerationRequest::noteCycleStep(DiagnosticEngine &diags) const {
const auto &storage = getStorage();
auto &d = std::get<0>(storage);
diags.diagnose(d, diag::circular_reference);
}
//----------------------------------------------------------------------------//
// Mangled local type name computation.
//----------------------------------------------------------------------------//
void MangleLocalTypeDeclRequest::diagnoseCycle(DiagnosticEngine &diags) const {
const auto &storage = getStorage();
auto &d = std::get<0>(storage);
diags.diagnose(d, diag::circular_reference);
}
void MangleLocalTypeDeclRequest::noteCycleStep(DiagnosticEngine &diags) const {
const auto &storage = getStorage();
auto &d = std::get<0>(storage);
diags.diagnose(d, diag::circular_reference);
}
//----------------------------------------------------------------------------//
// DefaultTypeRequest.
//----------------------------------------------------------------------------//
void swift::simple_display(llvm::raw_ostream &out,
const KnownProtocolKind kind) {
out << getProtocolName(kind);
}
void DefaultTypeRequest::diagnoseCycle(DiagnosticEngine &diags) const {
diags.diagnose(SourceLoc(), diag::circular_reference);
}
void DefaultTypeRequest::noteCycleStep(DiagnosticEngine &diags) const {
diags.diagnose(SourceLoc(), diag::circular_reference_through);
}
//----------------------------------------------------------------------------//
// DefaultTypeRequest caching.
//----------------------------------------------------------------------------//
SourceFile *DefaultTypeRequest::getSourceFile() const {
return getDeclContext()->getParentSourceFile();
}
Type &DefaultTypeRequest::getCache() const {
return getDeclContext()->getASTContext().getDefaultTypeRequestCache(
getSourceFile(), getKnownProtocolKind());
}
Optional<Type> DefaultTypeRequest::getCachedResult() const {
auto const &cachedType = getCache();
return cachedType ? Optional<Type>(cachedType) : None;
}
void DefaultTypeRequest::cacheResult(Type value) const { getCache() = value; }
const char *
DefaultTypeRequest::getTypeName(const KnownProtocolKind knownProtocolKind) {
switch (knownProtocolKind) {
// clang-format off
# define EXPRESSIBLE_BY_LITERAL_PROTOCOL_WITH_NAME(Id, Name, typeName, performLocalLookup) \
case KnownProtocolKind::Id: return typeName;
# include "swift/AST/KnownProtocols.def"
# undef EXPRESSIBLE_BY_LITERAL_PROTOCOL_WITH_NAME
//clang-format on
default: return nullptr;
}
}
bool DefaultTypeRequest::getPerformLocalLookup(const KnownProtocolKind knownProtocolKind) {
switch (knownProtocolKind) {
// clang-format off
# define EXPRESSIBLE_BY_LITERAL_PROTOCOL_WITH_NAME(Id, Name, typeName, performLocalLookup) \
case KnownProtocolKind::Id: return performLocalLookup;
# include "swift/AST/KnownProtocols.def"
# undef EXPRESSIBLE_BY_LITERAL_PROTOCOL_WITH_NAME
//clang-format on
default: return false;
}
}