//===--- ITCDecl.cpp - Iterative Type Checker for Declarations ------------===// // // 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 // //===----------------------------------------------------------------------===// // // 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 "swift/AST/ExistentialLayout.h" #include using namespace swift; //===----------------------------------------------------------------------===// // Inheritance clause handling //===----------------------------------------------------------------------===// static std::tuple> decomposeInheritedClauseDecl( llvm::PointerUnion decl) { TypeResolutionOptions options; DeclContext *dc; MutableArrayRef inheritanceClause; if (auto typeDecl = decl.dyn_cast()) { inheritanceClause = typeDecl->getInherited(); if (auto nominal = dyn_cast(typeDecl)) { dc = nominal; options |= (TR_GenericSignature | TR_InheritanceClause | TR_AllowUnavailableProtocol); } else { dc = typeDecl->getDeclContext(); if (isa(typeDecl)) { // For generic parameters, we want name lookup to look at just the // signature of the enclosing entity. if (auto nominal = dyn_cast(dc)) { dc = nominal; options |= TR_GenericSignature; } else if (auto ext = dyn_cast(dc)) { dc = ext; options |= TR_GenericSignature; } else if (auto func = dyn_cast(dc)) { dc = func; options |= TR_GenericSignature; } else if (!dc->isModuleScopeContext()) { // Skip the generic parameter's context entirely. dc = dc->getParent(); } } } if (!isa(typeDecl)) { options |= TR_NonEnumInheritanceClauseOuterLayer; } } else { auto ext = decl.get(); inheritanceClause = ext->getInherited(); dc = ext; options |= (TR_GenericSignature | TR_InheritanceClause | TR_AllowUnavailableProtocol); } return std::make_tuple(options, dc, inheritanceClause); } static std::tuple decomposeInheritedClauseEntry( TypeCheckRequest::InheritedClauseEntryPayloadType entry) { TypeResolutionOptions options; DeclContext *dc; MutableArrayRef 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(dc)) TC.validateDeclForNameLookup(nominal); else if (auto ext = dyn_cast(dc)) { TC.validateExtension(ext); } // Validate the type of this inherited clause entry. // FIXME: Recursion into existing type checker. GenericTypeToArchetypeResolver resolver(dc); if (TC.validateType(*inherited, dc, options, &resolver, &unsatisfiedDependency)) { inherited->setInvalidType(getASTContext()); } auto type = inherited->getType(); if (!type.isNull()) inherited->setType(dc->mapTypeOutOfContext(type)); } 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. if (classDecl->isInvalid()) superclassType = ErrorType::get(getASTContext()); 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){ auto inheritedClause = payload->getInherited(); for (unsigned i = 0, n = inheritedClause.size(); i != n; ++i) { TypeLoc &inherited = inheritedClause[i]; if (!inherited.getType()) return false; } return true; } 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; bool diagnosedCircularity = false; llvm::SmallSetVector 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. if (inherited.getType()->isExistentialType()) { auto layout = inherited.getType()->getExistentialLayout(); assert(!layout.superclass && "Need to redo inheritance clause " "typechecking"); for (auto inheritedProtocolTy: layout.getProtocols()) { auto *inheritedProtocol = inheritedProtocolTy->getDecl(); if (inheritedProtocol == protocol || inheritedProtocol->inheritsFrom(protocol)) { if (!diagnosedCircularity) { diagnose(protocol, diag::circular_protocol_def, protocol->getName().str()) .fixItRemove(inherited.getSourceRange()); diagnosedCircularity = true; } continue; } allProtocols.insert(inheritedProtocol); } } } // If we enumerated any dependencies, we can't complete this request. if (anyDependencies) return; } bool IterativeTypeChecker::breakCycleForInheritedProtocols( ProtocolDecl *protocol) { // FIXME: We'd like to drop just the problematic protocols, not // everything. return true; } //===----------------------------------------------------------------------===// // Resolve a type declaration //===----------------------------------------------------------------------===// bool IterativeTypeChecker::isResolveTypeDeclSatisfied(TypeDecl *typeDecl) { auto *dc = typeDecl->getDeclContext(); if (typeDecl->hasInterfaceType()) return true; if (auto typeAliasDecl = dyn_cast(typeDecl)) { if (typeAliasDecl->getDeclContext()->isModuleScopeContext() && typeAliasDecl->getGenericParams() == nullptr) { return typeAliasDecl->hasInterfaceType(); } } // If this request can *never* be satisfied due to recursion, // return success and fail elsewhere. if (typeDecl->isBeingValidated()) return true; while (dc) { if (auto nominal = dyn_cast(dc)) { if (nominal->isBeingValidated()) return true; if (nominal->hasInterfaceType()) return false; } else if (auto ext = dyn_cast(dc)) { if (ext->isBeingValidated()) return true; if (ext->hasValidationStarted()) return false; } else { break; } dc = dc->getParent(); } // Ok, we can try calling validateDecl(). return false; } void IterativeTypeChecker::processResolveTypeDecl( TypeDecl *typeDecl, UnsatisfiedDependency unsatisfiedDependency) { if (auto typeAliasDecl = dyn_cast(typeDecl)) { if (typeAliasDecl->getDeclContext()->isModuleScopeContext() && typeAliasDecl->getGenericParams() == nullptr) { typeAliasDecl->setValidationStarted(); TypeResolutionOptions options = TR_TypeAliasUnderlyingType; if (typeAliasDecl->getFormalAccess() <= Accessibility::FilePrivate) options |= TR_KnownNonCascadingDependency; // Note: recursion into old type checker is okay when passing in an // unsatisfied-dependency callback. GenericTypeToArchetypeResolver resolver(typeAliasDecl); if (TC.validateType(typeAliasDecl->getUnderlyingTypeLoc(), typeAliasDecl, options, &resolver, &unsatisfiedDependency)) { typeAliasDecl->setInvalid(); typeAliasDecl->getUnderlyingTypeLoc().setInvalidType(getASTContext()); } if (typeAliasDecl->getUnderlyingTypeLoc().wasValidated()) { typeAliasDecl->setUnderlyingType( typeAliasDecl->getUnderlyingTypeLoc().getType()); } return; } // Fall through. } // FIXME: Recursion into the old type checker. TC.validateDecl(typeDecl); } bool IterativeTypeChecker::breakCycleForResolveTypeDecl(TypeDecl *typeDecl) { if (auto typeAliasDecl = dyn_cast(typeDecl)) { typeAliasDecl->setInvalid(); typeAliasDecl->setInterfaceType(ErrorType::get(getASTContext())); typeAliasDecl->getUnderlyingTypeLoc().setInvalidType(getASTContext()); return true; } // FIXME: Generalize this. return false; }