mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
351 lines
12 KiB
C++
351 lines
12 KiB
C++
//===--- ITCDecl.cpp - Iterative Type Checker for Declarations ------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See http://swift.org/LICENSE.txt for license information
|
|
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file implements the portions of the IterativeTypeChecker
|
|
// class that involve declarations.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
#include "GenericTypeResolver.h"
|
|
#include "TypeChecker.h"
|
|
#include "swift/Sema/IterativeTypeChecker.h"
|
|
#include "swift/AST/ASTContext.h"
|
|
#include "swift/AST/Decl.h"
|
|
#include <tuple>
|
|
using namespace swift;
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Inheritance clause handling
|
|
//===----------------------------------------------------------------------===//
|
|
static std::tuple<TypeResolutionOptions, DeclContext *,
|
|
MutableArrayRef<TypeLoc>>
|
|
decomposeInheritedClauseDecl(
|
|
llvm::PointerUnion<TypeDecl *, ExtensionDecl *> decl) {
|
|
TypeResolutionOptions options;
|
|
DeclContext *dc;
|
|
MutableArrayRef<TypeLoc> inheritanceClause;
|
|
if (auto typeDecl = decl.dyn_cast<TypeDecl *>()) {
|
|
inheritanceClause = typeDecl->getInherited();
|
|
if (auto nominal = dyn_cast<NominalTypeDecl>(typeDecl)) {
|
|
dc = nominal;
|
|
options |= TR_GenericSignature | TR_InheritanceClause;
|
|
} else {
|
|
dc = typeDecl->getDeclContext();
|
|
|
|
if (isa<GenericTypeParamDecl>(typeDecl)) {
|
|
// For generic parameters, we want name lookup to look at just the
|
|
// signature of the enclosing entity.
|
|
if (auto nominal = dyn_cast<NominalTypeDecl>(dc)) {
|
|
dc = nominal;
|
|
options |= TR_GenericSignature;
|
|
} else if (auto ext = dyn_cast<ExtensionDecl>(dc)) {
|
|
dc = ext;
|
|
options |= TR_GenericSignature;
|
|
} else if (auto func = dyn_cast<AbstractFunctionDecl>(dc)) {
|
|
dc = func;
|
|
options |= TR_GenericSignature;
|
|
} else if (!dc->isModuleScopeContext()) {
|
|
// Skip the generic parameter's context entirely.
|
|
dc = dc->getParent();
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
auto ext = decl.get<ExtensionDecl *>();
|
|
inheritanceClause = ext->getInherited();
|
|
dc = ext;
|
|
options |= TR_GenericSignature | TR_InheritanceClause;
|
|
}
|
|
|
|
return std::make_tuple(options, dc, inheritanceClause);
|
|
}
|
|
|
|
static std::tuple<TypeResolutionOptions, DeclContext *, TypeLoc *>
|
|
decomposeInheritedClauseEntry(
|
|
TypeCheckRequest::InheritedClauseEntryPayloadType entry) {
|
|
TypeResolutionOptions options;
|
|
DeclContext *dc;
|
|
MutableArrayRef<TypeLoc> inheritanceClause;
|
|
std::tie(options, dc, inheritanceClause)
|
|
= decomposeInheritedClauseDecl(entry.first);
|
|
return std::make_tuple(options, dc, &inheritanceClause[entry.second]);
|
|
}
|
|
|
|
bool IterativeTypeChecker::isResolveInheritedClauseEntrySatisfied(
|
|
TypeCheckRequest::InheritedClauseEntryPayloadType payload) {
|
|
TypeLoc &inherited = *std::get<2>(decomposeInheritedClauseEntry(payload));
|
|
return !inherited.getType().isNull();
|
|
}
|
|
|
|
void IterativeTypeChecker::processResolveInheritedClauseEntry(
|
|
TypeCheckRequest::InheritedClauseEntryPayloadType payload,
|
|
UnsatisfiedDependency unsatisfiedDependency) {
|
|
TypeResolutionOptions options;
|
|
DeclContext *dc;
|
|
TypeLoc *inherited;
|
|
std::tie(options, dc, inherited) = decomposeInheritedClauseEntry(payload);
|
|
|
|
// FIXME: Declaration validation is overkill. Sink it down into type
|
|
// resolution when it is actually needed.
|
|
if (auto nominal = dyn_cast<NominalTypeDecl>(dc))
|
|
TC.validateDecl(nominal);
|
|
else if (auto ext = dyn_cast<ExtensionDecl>(dc)) {
|
|
TC.validateExtension(ext);
|
|
}
|
|
|
|
// Validate the type of this inherited clause entry.
|
|
// FIXME: Recursion into existing type checker.
|
|
PartialGenericTypeToArchetypeResolver resolver(TC);
|
|
if (TC.validateType(*inherited, dc, options, &resolver)) {
|
|
inherited->setInvalidType(getASTContext());
|
|
}
|
|
}
|
|
|
|
bool IterativeTypeChecker::breakCycleForResolveInheritedClauseEntry(
|
|
TypeCheckRequest::InheritedClauseEntryPayloadType payload) {
|
|
std::get<2>(decomposeInheritedClauseEntry(payload))
|
|
->setInvalidType(getASTContext());
|
|
return true;
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Superclass handling
|
|
//===----------------------------------------------------------------------===//
|
|
bool IterativeTypeChecker::isTypeCheckSuperclassSatisfied(ClassDecl *payload) {
|
|
return payload->LazySemanticInfo.Superclass.getInt();
|
|
}
|
|
|
|
void IterativeTypeChecker::processTypeCheckSuperclass(
|
|
ClassDecl *classDecl,
|
|
UnsatisfiedDependency unsatisfiedDependency) {
|
|
// The superclass should be the first inherited type. However, so
|
|
// long as we see already-resolved types that refer to protocols,
|
|
// skip over them to keep looking for a misplaced superclass. The
|
|
// actual error will be diagnosed when we perform full semantic
|
|
// analysis on the class itself.
|
|
Type superclassType;
|
|
auto inheritedClause = classDecl->getInherited();
|
|
for (unsigned i = 0, n = inheritedClause.size(); i != n; ++i) {
|
|
TypeLoc &inherited = inheritedClause[i];
|
|
|
|
// If this inherited type has not been resolved, we depend on it.
|
|
if (unsatisfiedDependency(
|
|
requestResolveInheritedClauseEntry({ classDecl, i }))) {
|
|
return;
|
|
}
|
|
|
|
// If this resolved inherited type is existential, keep going.
|
|
if (inherited.getType()->isExistentialType()) continue;
|
|
|
|
// If this resolved type is a class, we're done.
|
|
if (inherited.getType()->getClassOrBoundGenericClass()) {
|
|
superclassType = inherited.getType();
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Set the superclass type.
|
|
classDecl->setSuperclass(superclassType);
|
|
}
|
|
|
|
bool IterativeTypeChecker::breakCycleForTypeCheckSuperclass(
|
|
ClassDecl *classDecl) {
|
|
classDecl->setSuperclass(ErrorType::get(getASTContext()));
|
|
return true;
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Raw type handling
|
|
//===----------------------------------------------------------------------===//
|
|
bool IterativeTypeChecker::isTypeCheckRawTypeSatisfied(EnumDecl *payload) {
|
|
return payload->LazySemanticInfo.RawType.getInt();
|
|
}
|
|
|
|
void IterativeTypeChecker::processTypeCheckRawType(
|
|
EnumDecl *enumDecl,
|
|
UnsatisfiedDependency unsatisfiedDependency) {
|
|
// The raw type should be the first inherited type. However, so
|
|
// long as we see already-resolved types that refer to protocols,
|
|
// skip over them to keep looking for a misplaced raw type. The
|
|
// actual error will be diagnosed when we perform full semantic
|
|
// analysis on the enum itself.
|
|
Type rawType;
|
|
auto inheritedClause = enumDecl->getInherited();
|
|
for (unsigned i = 0, n = inheritedClause.size(); i != n; ++i) {
|
|
TypeLoc &inherited = inheritedClause[i];
|
|
|
|
// We depend on having resolved the inherited type.
|
|
if (unsatisfiedDependency(
|
|
requestResolveInheritedClauseEntry({ enumDecl, i }))) {
|
|
return;
|
|
}
|
|
|
|
// If this resolved inherited type is existential, keep going.
|
|
if (inherited.getType()->isExistentialType()) continue;
|
|
|
|
// Record this raw type.
|
|
rawType = inherited.getType();
|
|
break;
|
|
}
|
|
|
|
// Set the raw type.
|
|
enumDecl->setRawType(rawType);
|
|
}
|
|
|
|
bool IterativeTypeChecker::breakCycleForTypeCheckRawType(EnumDecl *enumDecl) {
|
|
enumDecl->setRawType(ErrorType::get(getASTContext()));
|
|
return true;
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Inherited protocols
|
|
//===----------------------------------------------------------------------===//
|
|
bool IterativeTypeChecker::isInheritedProtocolsSatisfied(ProtocolDecl *payload){
|
|
return payload->isInheritedProtocolsValid();
|
|
}
|
|
|
|
void IterativeTypeChecker::processInheritedProtocols(
|
|
ProtocolDecl *protocol,
|
|
UnsatisfiedDependency unsatisfiedDependency) {
|
|
// Computing the set of inherited protocols depends on the complete
|
|
// inheritance clause.
|
|
// FIXME: Technically, we only need very basic name binding.
|
|
auto inheritedClause = protocol->getInherited();
|
|
bool anyDependencies = false;
|
|
llvm::SmallSetVector<ProtocolDecl *, 4> allProtocols;
|
|
for (unsigned i = 0, n = inheritedClause.size(); i != n; ++i) {
|
|
TypeLoc &inherited = inheritedClause[i];
|
|
|
|
// We depend on having resolved the inherited type.
|
|
if (unsatisfiedDependency(
|
|
requestResolveInheritedClauseEntry({ protocol, i }))) {
|
|
anyDependencies = true;
|
|
continue;
|
|
}
|
|
|
|
// Collect existential types.
|
|
// FIXME: We'd prefer to keep what the user wrote here.
|
|
SmallVector<ProtocolDecl *, 4> protocols;
|
|
if (inherited.getType()->isExistentialType(protocols)) {
|
|
allProtocols.insert(protocols.begin(), protocols.end());
|
|
continue;
|
|
}
|
|
}
|
|
|
|
// If we enumerated any dependencies, we can't complete this request.
|
|
if (anyDependencies)
|
|
return;
|
|
|
|
// FIXME: Hack to deal with recursion elsewhere.
|
|
if (protocol->isInheritedProtocolsValid())
|
|
return;
|
|
|
|
// Check for circular inheritance.
|
|
// FIXME: The diagnostics here should be improved... and this should probably
|
|
// be handled by the normal cycle detection.
|
|
bool diagnosedCircularity = false;
|
|
for (unsigned i = 0, n = allProtocols.size(); i != n; /*in loop*/) {
|
|
if (allProtocols[i] == protocol ||
|
|
allProtocols[i]->inheritsFrom(protocol)) {
|
|
if (!diagnosedCircularity) {
|
|
diagnose(protocol,
|
|
diag::circular_protocol_def, protocol->getName().str());
|
|
diagnosedCircularity = true;
|
|
}
|
|
|
|
allProtocols.remove(allProtocols[i]);
|
|
--n;
|
|
continue;
|
|
}
|
|
|
|
++i;
|
|
}
|
|
|
|
protocol->setInheritedProtocols(getASTContext().AllocateCopy(allProtocols));
|
|
}
|
|
|
|
bool IterativeTypeChecker::breakCycleForInheritedProtocols(
|
|
ProtocolDecl *protocol) {
|
|
// FIXME: We'd like to drop just the problematic protocols, not
|
|
// everything.
|
|
protocol->setInheritedProtocols({});
|
|
return true;
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Resolve a type declaration
|
|
//===----------------------------------------------------------------------===//
|
|
bool IterativeTypeChecker::isResolveTypeDeclSatisfied(TypeDecl *typeDecl) {
|
|
if (auto typeAliasDecl = dyn_cast<TypeAliasDecl>(typeDecl)) {
|
|
// If the underlying type was validated, we're done.
|
|
return typeAliasDecl->getUnderlyingTypeLoc().wasValidated();
|
|
}
|
|
|
|
if (auto typeParam = dyn_cast<AbstractTypeParamDecl>(typeDecl)) {
|
|
// FIXME: Deal with these.
|
|
return typeParam->getArchetype();
|
|
}
|
|
|
|
// Module types are always fully resolved.
|
|
if (isa<ModuleDecl>(typeDecl))
|
|
return true;
|
|
|
|
// Nominal types.
|
|
auto nominal = cast<NominalTypeDecl>(typeDecl);
|
|
return !nominal->getDeclaredType().isNull();
|
|
}
|
|
|
|
void IterativeTypeChecker::processResolveTypeDecl(
|
|
TypeDecl *typeDecl,
|
|
UnsatisfiedDependency unsatisfiedDependency) {
|
|
if (auto typeAliasDecl = dyn_cast<TypeAliasDecl>(typeDecl)) {
|
|
if (typeAliasDecl->getDeclContext()->isModuleScopeContext()) {
|
|
// FIXME: This is silly.
|
|
if (!typeAliasDecl->hasType())
|
|
typeAliasDecl->computeType();
|
|
|
|
TypeResolutionOptions options;
|
|
options |= TR_GlobalTypeAlias;
|
|
if (typeAliasDecl->getFormalAccess() == Accessibility::Private)
|
|
options |= TR_KnownNonCascadingDependency;
|
|
|
|
// Note: recursion into old type checker is okay when passing in an
|
|
// unsatisfied-dependency callback.
|
|
if (TC.validateType(typeAliasDecl->getUnderlyingTypeLoc(),
|
|
typeAliasDecl->getDeclContext(),
|
|
options, nullptr, &unsatisfiedDependency)) {
|
|
typeAliasDecl->setInvalid();
|
|
typeAliasDecl->overwriteType(ErrorType::get(getASTContext()));
|
|
typeAliasDecl->getUnderlyingTypeLoc().setInvalidType(getASTContext());
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
// Fall through.
|
|
}
|
|
|
|
// FIXME: Recursion into the old type checker.
|
|
TC.validateDecl(typeDecl);
|
|
}
|
|
|
|
bool IterativeTypeChecker::breakCycleForResolveTypeDecl(TypeDecl *typeDecl) {
|
|
if (auto typeAliasDecl = dyn_cast<TypeAliasDecl>(typeDecl)) {
|
|
typeAliasDecl->setInvalid();
|
|
typeAliasDecl->overwriteType(ErrorType::get(getASTContext()));
|
|
typeAliasDecl->getUnderlyingTypeLoc().setInvalidType(getASTContext());
|
|
return true;
|
|
}
|
|
|
|
// FIXME: Generalize this.
|
|
return false;
|
|
}
|