| //===--- 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; |
| } |