//===--- RequirementMachineRequests.cpp - Request evaluator requests ------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2018 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 main entry points for computing minimized generic // signatures using the requirement machine via the request evaluator. // // There are three requests: // // - RequirementSignatureRequest computes protocol requirement signatures from // user-written requirements. // - AbstractGenericSignatureRequest computes minimal generic signatures from a // set of abstract Requirements. // - InferredGenericSignatureRequest computes minimal generic signatures from a // set of user-written requirements on a parsed generic declaration. // // Each request begins by constructing some desugared requirements using the // entry points in RequirementLowering.cpp. // // The desugared requirements are fed into a new requirement machine instance, // which is then asked to produce a minimal set of rewrite rules. These rules // are converted into minimal canonical Requirements using the entry points in // RuleBuilder.cpp. // // The actual logic for finding a minimal set of rewrite rules is implemented in // HomotopyReduction.cpp and MinimalConformances.cpp. // // Routines for constructing Requirements from Rules are implemented in // RequirementBuilder.cpp. // // This process is actually iterated to implement "concrete equivalence class // splitting", a compatibility behavior to produce the same results as the // GenericSignatureBuilder in certain esoteric edge cases: // // ------------------------ // / Desugared Requirement / // ------------------------ // | // | +---------------------+ // | | | // v v | // +-------------+ | // | RuleBuilder | | // +-------------+ | // | | // v | // +--------------+ | // | Minimization | | // +--------------+ | // | | // v | // +--------------------+ | // | RequirementBuilder | | // +--------------------+ | // | | // v | // -------------- | // / Requirement / | // -------------- | // | | // v | // +------------------------------------+ | // | Split concrete equivalence classes | ----+ // +------------------------------------+ // | // v // -------------- // / Requirement / // -------------- // // This transformation is described in splitConcreteEquivalenceClasses() below. // //===----------------------------------------------------------------------===// #include "RequirementMachine.h" #include "swift/AST/ASTContext.h" #include "swift/AST/Decl.h" #include "swift/AST/DiagnosticsSema.h" #include "swift/AST/GenericSignature.h" #include "swift/AST/LazyResolver.h" #include "swift/AST/Requirement.h" #include "swift/AST/RequirementSignature.h" #include "swift/AST/TypeCheckRequests.h" #include "swift/AST/TypeRepr.h" #include "swift/Basic/Assertions.h" #include "swift/Basic/Defer.h" #include "swift/Basic/Statistic.h" #include #include #include "RequirementLowering.h" using namespace swift; using namespace rewriting; /// Hack for GenericSignatureBuilder compatibility. We might end up with a /// same-type requirement between type parameters where one of them has an /// implied concrete type requirement. In this case, split it up into two /// concrete type requirements. static bool shouldSplitConcreteEquivalenceClass( Requirement req, const ProtocolDecl *proto, const RequirementMachine *machine) { return (req.getKind() == RequirementKind::SameType && req.getSecondType()->isTypeParameter() && machine->isConcreteType(req.getSecondType(), proto)); } /// Returns true if this generic signature contains abstract same-type /// requirements between concrete type parameters. In this case, we split /// the abstract same-type requirements into pairs of concrete type /// requirements, and minimize the signature again. static bool shouldSplitConcreteEquivalenceClasses( ArrayRef requirements, const ProtocolDecl *proto, const RequirementMachine *machine) { for (auto req : requirements) { if (shouldSplitConcreteEquivalenceClass(req, proto, machine)) return true; } return false; } /// Same as the above, but with the requirements of a protocol connected /// component. static bool shouldSplitConcreteEquivalenceClasses( const llvm::DenseMap &protos, const RequirementMachine *machine) { for (const auto &pair : protos) { if (shouldSplitConcreteEquivalenceClasses(pair.second.getRequirements(), pair.first, machine)) return true; } return false; } /// Replace each same-type requirement 'T == U' where 'T' (and therefore 'U') /// is known to equal a concrete type 'C' with a pair of requirements /// 'T == C' and 'U == C'. We build the signature again in this case, since /// one of the two requirements will be redundant, but we don't know which /// ahead of time. static void splitConcreteEquivalenceClasses( ASTContext &ctx, ArrayRef requirements, const ProtocolDecl *proto, const RequirementMachine *machine, ArrayRef genericParams, SmallVectorImpl &splitRequirements, unsigned &attempt) { bool debug = machine->getDebugOptions().contains( DebugFlags::SplitConcreteEquivalenceClass); unsigned maxAttempts = ctx.LangOpts.RequirementMachineMaxSplitConcreteEquivClassAttempts; if (attempt >= maxAttempts) { ABORT([&](auto &out) { out << "Splitting concrete equivalence classes did not " << "reach fixed point after " << attempt << " attempts.\n"; out << "Last attempt produced these requirements:\n"; for (auto req : requirements) { req.dump(out); out << "\n"; } machine->dump(out); }); } splitRequirements.clear(); if (debug) { llvm::dbgs() << "\n# Splitting concrete equivalence classes:\n"; } for (auto req : requirements) { if (shouldSplitConcreteEquivalenceClass(req, proto, machine)) { auto concreteType = machine->getConcreteType( req.getSecondType(), genericParams, proto); Requirement firstReq(RequirementKind::SameType, req.getFirstType(), concreteType); Requirement secondReq(RequirementKind::SameType, req.getSecondType(), concreteType); splitRequirements.push_back({firstReq, SourceLoc()}); splitRequirements.push_back({secondReq, SourceLoc()}); if (debug) { llvm::dbgs() << "- First split: "; firstReq.dump(llvm::dbgs()); llvm::dbgs() << "\n- Second split: "; secondReq.dump(llvm::dbgs()); llvm::dbgs() << "\n"; } continue; } splitRequirements.push_back({req, SourceLoc()}); if (debug) { llvm::dbgs() << "- Not split: "; req.dump(llvm::dbgs()); llvm::dbgs() << "\n"; } } } /// Same as the above, but with the requirements of a protocol connected /// component. static void splitConcreteEquivalenceClasses( ASTContext &ctx, const llvm::DenseMap &protos, const RequirementMachine *machine, llvm::DenseMap> &splitProtos, unsigned &attempt) { for (const auto &pair : protos) { const auto *proto = pair.first; auto genericParams = proto->getGenericSignature().getGenericParams(); splitConcreteEquivalenceClasses(ctx, pair.second.getRequirements(), proto, machine, genericParams, splitProtos[proto], attempt); } } /// Builds the requirement signatures for each protocol in this strongly /// connected component. llvm::DenseMap RequirementMachine::computeMinimalProtocolRequirements() { auto protos = System.getProtocols(); ASSERT(protos.size() > 0 && "Not a protocol connected component rewrite system"); System.minimizeRewriteSystem(Map); if (Dump) { llvm::dbgs() << "Minimized rewrite system:\n"; dump(llvm::dbgs()); } auto rules = System.getMinimizedProtocolRules(); auto &ctx = Context.getASTContext(); // Note that we build 'result' by iterating over 'protos' rather than // 'rules'; this is intentional, so that even if a protocol has no // rules, we still end up creating an entry for it in 'result'. llvm::DenseMap result; for (const auto *proto : protos) { auto genericParams = proto->getGenericSignature().getGenericParams(); const auto &entry = rules[proto]; std::vector reqs; std::vector aliases; buildRequirementsFromRules(entry.Requirements, entry.TypeAliases, genericParams, /*reconstituteSugar=*/true, reqs, aliases); result[proto] = RequirementSignature(ctx.AllocateCopy(reqs), ctx.AllocateCopy(aliases), getErrors()); } return result; } RequirementSignature RequirementSignatureRequest::evaluate(Evaluator &evaluator, ProtocolDecl *proto) const { ASTContext &ctx = proto->getASTContext(); // First check if we have a deserializable requirement signature. if (proto->hasLazyRequirementSignature()) { // FIXME: (transitional) increment the redundant "always-on" counter. if (ctx.Stats) ++ctx.Stats->getFrontendCounters().NumLazyRequirementSignaturesLoaded; auto contextData = static_cast( ctx.getOrCreateLazyContextData(proto, nullptr)); SmallVector requirements; SmallVector typeAliases; contextData->loader->loadRequirementSignature( proto, contextData->requirementSignatureData, requirements, typeAliases); return RequirementSignature(ctx.AllocateCopy(requirements), ctx.AllocateCopy(typeAliases)); } auto &rewriteCtx = ctx.getRewriteContext(); // We build requirement signatures for all protocols in a strongly connected // component at the same time. auto component = rewriteCtx.startComputingRequirementSignatures(proto); SWIFT_DEFER { rewriteCtx.finishComputingRequirementSignatures(proto); }; SmallVector errors; // Collect user-written requirements from the protocols in this connected // component. llvm::DenseMap> protos; for (const auto *proto : component) { auto &requirements = protos[proto]; for (auto req : proto->getStructuralRequirements()) requirements.push_back(req); for (auto req : proto->getTypeAliasRequirements()) requirements.push_back({req, SourceLoc()}); } if (rewriteCtx.getDebugOptions().contains(DebugFlags::Timers)) { rewriteCtx.beginTimer("RequirementSignatureRequest"); llvm::dbgs() << "["; for (auto *proto : component) llvm::dbgs() << " " << proto->getName(); llvm::dbgs() << " ]\n"; } SWIFT_DEFER { if (rewriteCtx.getDebugOptions().contains(DebugFlags::Timers)) { rewriteCtx.endTimer("RequirementSignatureRequest"); llvm::dbgs() << "["; for (auto *proto : component) llvm::dbgs() << " " << proto->getName(); llvm::dbgs() << " ]\n"; } }; unsigned attempt = 0; for (;;) { for (const auto *otherProto : component) { auto &requirements = protos[otherProto]; // Preprocess requirements to eliminate conformances on type parameters // which are made concrete. if (ctx.LangOpts.EnableRequirementMachineConcreteContraction) { SmallVector contractedRequirements; bool debug = rewriteCtx.getDebugOptions() .contains(DebugFlags::ConcreteContraction); if (performConcreteContraction(requirements, contractedRequirements, errors, debug)) { std::swap(contractedRequirements, requirements); } } } // Heap-allocate the requirement machine to save stack space. std::unique_ptr machine(new RequirementMachine( rewriteCtx)); auto status = machine->initWithProtocolWrittenRequirements(component, protos); // If completion failed, diagnose an error and return a dummy signature. if (status.first != CompletionResult::Success) { // All we can do at this point is diagnose and give each protocol an empty // requirement signature. for (const auto *otherProto : component) { ctx.Diags.diagnose(otherProto->getLoc(), diag::requirement_machine_completion_failed, /*protocol=*/1, unsigned(status.first)); auto rule = machine->getRuleAsStringForDiagnostics(status.second); ctx.Diags.diagnose(otherProto->getLoc(), diag::requirement_machine_completion_rule, rule); if (otherProto != proto) { ctx.evaluator.cacheOutput( RequirementSignatureRequest{const_cast(otherProto)}, RequirementSignature::getPlaceholderRequirementSignature( otherProto, GenericSignatureErrorFlags::CompletionFailed)); } } return RequirementSignature::getPlaceholderRequirementSignature( proto, GenericSignatureErrorFlags::CompletionFailed); } auto minimalRequirements = machine->computeMinimalProtocolRequirements(); // Don't bother splitting concrete equivalence classes if there were invalid // requirements, because the signature is not going to be ABI anyway. if (!machine->getErrors().contains( GenericSignatureErrorFlags::HasInvalidRequirements)) { if (shouldSplitConcreteEquivalenceClasses(minimalRequirements, machine.get())) { ++attempt; splitConcreteEquivalenceClasses(ctx, minimalRequirements, machine.get(), protos, attempt); continue; } } bool debug = machine->getDebugOptions().contains(DebugFlags::Minimization); // The requirement signature for the actual protocol that the result // was kicked off with. std::optional result; if (debug) { llvm::dbgs() << "\nRequirement signatures:\n"; } // Cache the requirement signatures for all other protocols in this // connected component. for (const auto &pair : minimalRequirements) { auto *otherProto = pair.first; const auto &reqs = pair.second; // Dump the result if requested. if (debug) { llvm::dbgs() << "- Protocol " << otherProto->getName() << ": "; auto sig = GenericSignature::get( otherProto->getGenericSignature().getGenericParams(), reqs.getRequirements()); PrintOptions opts; opts.ProtocolQualifiedDependentMemberTypes = true; sig.print(llvm::dbgs(), opts); llvm::dbgs() << "\n"; } // Don't call setRequirementSignature() on the original proto; the // request evaluator will do it for us. if (otherProto == proto) result = reqs; else { auto temp = reqs; ctx.evaluator.cacheOutput( RequirementSignatureRequest{const_cast(otherProto)}, std::move(temp)); } } // FIXME: We don't have the inverses from desugaring available here! SmallVector missingInverses; // Diagnose redundant requirements and conflicting requirements. machine->computeRequirementDiagnostics(errors, missingInverses, proto->getLoc()); diagnoseRequirementErrors(ctx, errors, AllowConcreteTypePolicy::NestedAssocTypes); for (auto *protocol : machine->System.getProtocols()) { auto selfType = protocol->getSelfInterfaceType(); auto concrete = machine->getConcreteType(selfType, machine->getGenericParams(), protocol); if (!concrete || concrete->hasError()) continue; protocol->diagnose(diag::requires_generic_param_made_equal_to_concrete, selfType); } if (!machine->getErrors()) { // If this signature was minimized without errors or non-redundant // concrete conformances, we can re-use the requirement machine for // subsequent queries, instead of building a new requirement machine // from the minimized signature. rewriteCtx.installRequirementMachine(proto, std::move(machine)); } // Return the result for the specific protocol this request was kicked off on. return *result; } } /// Builds the top-level generic signature requirements for this rewrite system. GenericSignature RequirementMachine::computeMinimalGenericSignature( bool reconstituteSugar) { ASSERT(!Sig && "Already computed minimal generic signature"); ASSERT(System.getProtocols().empty() && "Not a top-level generic signature rewrite system"); ASSERT(!Params.empty() && "Not a from-source top-level generic signature rewrite system"); System.minimizeRewriteSystem(Map); if (Dump) { llvm::dbgs() << "Minimized rewrite system:\n"; dump(llvm::dbgs()); } auto rules = System.getMinimizedGenericSignatureRules(); std::vector reqs; std::vector aliases; buildRequirementsFromRules(rules, ArrayRef(), getGenericParams(), reconstituteSugar, reqs, aliases); ASSERT(aliases.empty()); auto sig = GenericSignature::get(getGenericParams(), reqs); // Remember the signature for generic signature queries. In particular, // getConformancePath() needs the current requirement machine's // generic signature. Sig = sig.getCanonicalSignature(); return sig; } /// Check whether the inputs to the \c AbstractGenericSignatureRequest are /// all canonical. static bool isCanonicalRequest(GenericSignature baseSignature, ArrayRef genericParams, ArrayRef requirements) { if (baseSignature && !baseSignature->isCanonical()) return false; for (auto gp : genericParams) { if (!gp->isCanonical()) return false; } for (const auto &req : requirements) { if (!req.isCanonical()) return false; } return true; } GenericSignatureWithError AbstractGenericSignatureRequest::evaluate( Evaluator &evaluator, const GenericSignatureImpl *baseSignatureImpl, SmallVector addedParameters, SmallVector addedRequirements, bool allowInverses) const { GenericSignature baseSignature = GenericSignature{baseSignatureImpl}; // If nothing is added to the base signature, just return the base // signature. if (addedParameters.empty() && addedRequirements.empty()) return GenericSignatureWithError(baseSignature, GenericSignatureErrors()); ASTContext &ctx = addedParameters.empty() ? addedRequirements.front().getFirstType()->getASTContext() : addedParameters.front()->getASTContext(); SmallVector genericParams( baseSignature.getGenericParams().begin(), baseSignature.getGenericParams().end()); genericParams.append( addedParameters.begin(), addedParameters.end()); // If there are no added requirements, we can form the signature directly // with the added parameters. if (addedRequirements.empty() && !allowInverses) { auto result = GenericSignature::get(genericParams, baseSignature.getRequirements()); return GenericSignatureWithError(result, GenericSignatureErrors()); } // If the request is non-canonical, we won't need to build our own // generic signature builder. if (!isCanonicalRequest(baseSignature, addedParameters, addedRequirements)) { // Canonicalize the inputs so we can form the canonical request. auto canBaseSignature = baseSignature.getCanonicalSignature(); SmallVector canAddedParameters; canAddedParameters.reserve(addedParameters.size()); for (auto gp : addedParameters) { auto canGP = gp->getCanonicalType()->castTo(); canAddedParameters.push_back(canGP); } SmallVector canAddedRequirements; canAddedRequirements.reserve(addedRequirements.size()); for (const auto &req : addedRequirements) { canAddedRequirements.push_back(req.getCanonical()); } // Build the canonical signature. auto canSignatureResult = evaluateOrDefault( ctx.evaluator, AbstractGenericSignatureRequest{ canBaseSignature.getPointer(), std::move(canAddedParameters), std::move(canAddedRequirements), allowInverses}, GenericSignatureWithError()); if (!canSignatureResult.getPointer()) return GenericSignatureWithError(); // Substitute in the original generic parameters to form the sugared // result the original request wanted. auto canSignature = canSignatureResult.getPointer(); SmallVector resugaredParameters; resugaredParameters.reserve(canSignature.getGenericParams().size()); if (baseSignature) { resugaredParameters.append(baseSignature.getGenericParams().begin(), baseSignature.getGenericParams().end()); } resugaredParameters.append(addedParameters.begin(), addedParameters.end()); ASSERT(resugaredParameters.size() == canSignature.getGenericParams().size()); SmallVector resugaredRequirements; resugaredRequirements.reserve(canSignature.getRequirements().size()); for (const auto &req : canSignature.getRequirements()) { auto resugaredReq = req.subst( [&](SubstitutableType *type) { if (auto gp = dyn_cast(type)) { unsigned ordinal = canSignature->getGenericParamOrdinal(gp); return Type(resugaredParameters[ordinal]); } return Type(type); }, LookUpConformanceInModule(), SubstFlags::PreservePackExpansionLevel); resugaredRequirements.push_back(resugaredReq); } return GenericSignatureWithError( GenericSignature::get(resugaredParameters, resugaredRequirements), canSignatureResult.getInt()); } // Convert the input Requirements into StructuralRequirements by adding // empty source locations. SmallVector requirements; for (auto req : baseSignature.getRequirements()) requirements.push_back({req, SourceLoc()}); // Add the new requirements. for (auto req : addedRequirements) requirements.push_back({req, SourceLoc()}); // The requirements passed to this request may have been substituted, // meaning the subject type might be a concrete type and not a type // parameter. // // Also, the right hand side of conformance requirements here might be // a protocol composition. // // Desugaring converts these kinds of requirements into "proper" // requirements where the subject type is always a type parameter, // which is what the RuleBuilder expects. SmallVector errors; SmallVector inverses; desugarRequirements(requirements, inverses, errors); /// Next, we need to expand default requirements and then apply inverses. SmallVector paramsAsTypes; if (allowInverses) { for (auto *gtpt : addedParameters) paramsAsTypes.push_back(gtpt); } SmallVector defaults; InverseRequirement::expandDefaults(ctx, paramsAsTypes, defaults); applyInverses(ctx, paramsAsTypes, inverses, requirements, defaults, errors); requirements.append(defaults); auto &rewriteCtx = ctx.getRewriteContext(); if (rewriteCtx.getDebugOptions().contains(DebugFlags::Timers)) { rewriteCtx.beginTimer("AbstractGenericSignatureRequest"); llvm::dbgs() << "\n"; } unsigned attempt = 0; for (;;) { // Preprocess requirements to eliminate conformances on generic parameters // which are made concrete. if (ctx.LangOpts.EnableRequirementMachineConcreteContraction) { SmallVector contractedRequirements; bool debug = rewriteCtx.getDebugOptions() .contains(DebugFlags::ConcreteContraction); if (performConcreteContraction(requirements, contractedRequirements, errors, debug)) { std::swap(contractedRequirements, requirements); } } // Heap-allocate the requirement machine to save stack space. std::unique_ptr machine(new RequirementMachine( rewriteCtx)); auto status = machine->initWithWrittenRequirements(genericParams, requirements); machine->checkCompletionResult(status.first); // We pass reconstituteSugar=false to ensure that if the original // requirements were canonical, the final signature remains canonical. auto result = machine->computeMinimalGenericSignature( /*reconstituteSugar=*/false); auto errorFlags = machine->getErrors(); // Don't bother splitting concrete equivalence classes if there were invalid // requirements, because the signature is not going to be ABI anyway. if (!errorFlags.contains(GenericSignatureErrorFlags::HasInvalidRequirements)) { if (shouldSplitConcreteEquivalenceClasses(result.getRequirements(), /*proto=*/nullptr, machine.get())) { ++attempt; splitConcreteEquivalenceClasses(ctx, result.getRequirements(), /*proto=*/nullptr, machine.get(), result.getGenericParams(), requirements, attempt); continue; } } if (!errorFlags) { // If this signature was minimized without errors or non-redundant // concrete conformances, we can re-use the requirement machine for // subsequent queries, instead of building a new requirement machine // from the minimized signature. Do this before verify(), which // performs queries. rewriteCtx.installRequirementMachine(result.getCanonicalSignature(), std::move(machine)); } if (!errorFlags.contains(GenericSignatureErrorFlags::HasInvalidRequirements)) { // Check invariants. result.verify(); } if (rewriteCtx.getDebugOptions().contains(DebugFlags::Timers)) { rewriteCtx.endTimer("AbstractGenericSignatureRequest"); llvm::dbgs() << result << "\n"; } return GenericSignatureWithError(result, errorFlags); } } GenericSignatureWithError InferredGenericSignatureRequest::evaluate( Evaluator &evaluator, const GenericSignatureImpl *parentSigImpl, GenericParamList *genericParamList, WhereClauseOwner whereClause, SmallVector addedRequirements, SmallVector inferenceSources, SourceLoc loc, ExtensionDecl *forExtension, bool allowInverses) const { GenericSignature parentSig(parentSigImpl); SmallVector genericParams( parentSig.getGenericParams().begin(), parentSig.getGenericParams().end()); unsigned numOuterParams = genericParams.size(); if (forExtension) { numOuterParams = 0; } SmallVector requirements; SmallVector errors; SmallVector inverses; for (const auto &req : parentSig.getRequirements()) requirements.push_back({req, loc}); DeclContext *lookupDC = nullptr; const auto visitRequirement = [&](const Requirement &req, RequirementRepr *reqRepr) { realizeRequirement(lookupDC, req, reqRepr, /*inferRequirements=*/true, requirements, errors); return false; }; if (genericParamList) { // If we have multiple parameter lists, we're in SIL mode, and there's // no parent signature from context. ASSERT(genericParamList->getOuterParameters() == nullptr || !parentSig); // Collect all outer generic parameter lists. SmallVector gpLists; for (auto *outerParamList = genericParamList; outerParamList != nullptr; outerParamList = outerParamList->getOuterParameters()) { gpLists.push_back(outerParamList); } // The generic parameter lists must appear from innermost to outermost. // We walk them backwards to order outer parameters before inner // parameters. for (auto *gpList : llvm::reverse(gpLists)) { ASSERT(gpList->size() > 0 && "Parsed an empty generic parameter list?"); for (auto *gpDecl : *gpList) { auto *gpType = gpDecl->getDeclaredInterfaceType() ->castTo(); genericParams.push_back(gpType); realizeInheritedRequirements(gpDecl, gpType, /*inferRequirements=*/true, requirements, errors); } lookupDC = (*gpList->begin())->getDeclContext(); // Add the generic parameter list's 'where' clause to the builder. // // The only time generic parameter lists have a 'where' clause is // in SIL mode; all other generic declarations have a free-standing // 'where' clause, which will be visited below. WhereClauseOwner(lookupDC, gpList) .visitRequirements(TypeResolutionStage::Structural, visitRequirement); } } // Realize all requirements in the free-standing 'where' clause, if there // is one. if (whereClause) { lookupDC = whereClause.dc; std::move(whereClause).visitRequirements( TypeResolutionStage::Structural, visitRequirement); } auto *moduleForInference = lookupDC->getParentModule(); auto &ctx = moduleForInference->getASTContext(); // Perform requirement inference from function parameter and result // types and such. for (auto source : inferenceSources) { inferRequirements(source, moduleForInference, lookupDC, requirements); } // Finish by adding any remaining requirements. This is used to introduce // inferred same-type requirements when building the generic signature of // an extension whose extended type is a generic typealias. for (const auto &req : addedRequirements) requirements.push_back({req, loc}); desugarRequirements(requirements, inverses, errors); // After realizing requirements, expand default requirements only for local // generic parameters, as the outer parameters have already been expanded. SmallVector paramTypes; if (allowInverses) { paramTypes.append(genericParams.begin() + numOuterParams, genericParams.end()); } SmallVector defaults; InverseRequirement::expandDefaults(ctx, paramTypes, defaults); applyInverses(ctx, paramTypes, inverses, requirements, defaults, errors); // Any remaining implicit defaults in a conditional inverse requirement // extension must be made explicit. if (forExtension) { auto invertibleProtocol = forExtension->isAddingConformanceToInvertible(); // FIXME: to workaround a reverse condfail, always infer the requirements if // the extension is in a swiftinterface file. This is temporary and should // be removed soon. (rdar://130424971) if (auto *sf = forExtension->getOutermostParentSourceFile()) { if (sf->Kind == SourceFileKind::Interface && !ctx.LangOpts.hasFeature(Feature::SE427NoInferenceOnExtension)) { invertibleProtocol = std::nullopt; } } if (invertibleProtocol) { for (auto &def : defaults) { // Check whether a corresponding explicit requirement was provided. for (auto &req : requirements) { // An explicit requirement can match the default exactly. if (req.req.getCanonical() == def.req.getCanonical()) { goto next; } // Disregard requirements on other parameters. if (!req.req.getFirstType()->isEqual(def.req.getFirstType())) { continue; } // Or it can be implied by a requirement on something that's inherently // copyable. if (req.req.getKind() == RequirementKind::Superclass) { // classes are currently always escapable and copyable goto next; } if (req.req.getKind() == RequirementKind::Layout) { // layout constraints currently always imply escapable and copyable goto next; } if (req.req.getKind() == RequirementKind::Conformance && req.req.getProtocolDecl() ->inheritsFrom(def.req.getProtocolDecl())) { goto next; } // A same-type constraint removes the ability for the copyability // to vary independently at all. if (req.req.getKind() == RequirementKind::SameType) { goto next; } } ctx.Diags.diagnose(loc,diag::inverse_conditional_must_be_fully_explicit, ctx.getProtocol(getKnownProtocolKind(*invertibleProtocol)), def.req.getFirstType(), def.req.getProtocolDecl()); next:; } // Don't actually apply the inferred requirements since they should be // stated explicitly. defaults.clear(); } } requirements.append(defaults); auto &rewriteCtx = ctx.getRewriteContext(); if (rewriteCtx.getDebugOptions().contains(DebugFlags::Timers)) { rewriteCtx.beginTimer("InferredGenericSignatureRequest"); llvm::dbgs() << "@ "; auto &sourceMgr = ctx.SourceMgr; loc.print(llvm::dbgs(), sourceMgr); llvm::dbgs() << "\n"; } unsigned attempt = 0; for (;;) { // Preprocess requirements to eliminate conformances on generic parameters // which are made concrete. if (ctx.LangOpts.EnableRequirementMachineConcreteContraction) { SmallVector contractedRequirements; bool debug = rewriteCtx.getDebugOptions() .contains(DebugFlags::ConcreteContraction); if (performConcreteContraction(requirements, contractedRequirements, errors, debug)) { std::swap(contractedRequirements, requirements); } } // Heap-allocate the requirement machine to save stack space. std::unique_ptr machine(new RequirementMachine( rewriteCtx)); auto status = machine->initWithWrittenRequirements(genericParams, requirements); // If completion failed, diagnose an error and return a dummy signature. if (status.first != CompletionResult::Success) { ctx.Diags.diagnose(loc, diag::requirement_machine_completion_failed, /*protocol=*/0, unsigned(status.first)); auto rule = machine->getRuleAsStringForDiagnostics(status.second); ctx.Diags.diagnose(loc, diag::requirement_machine_completion_rule, rule); auto result = GenericSignature::forInvalid(genericParams); if (rewriteCtx.getDebugOptions().contains(DebugFlags::Timers)) { rewriteCtx.endTimer("InferredGenericSignatureRequest"); llvm::dbgs() << result << "\n"; } return GenericSignatureWithError( result, GenericSignatureErrorFlags::CompletionFailed); } auto result = machine->computeMinimalGenericSignature( /*reconstituteSugar=*/true); auto errorFlags = machine->getErrors(); // Diagnose redundant requirements and conflicting requirements. if (attempt == 0) { machine->computeRequirementDiagnostics(errors, inverses, loc); diagnoseRequirementErrors(ctx, errors, (forExtension || !genericParamList) ? AllowConcreteTypePolicy::All : AllowConcreteTypePolicy::AssocTypes); } // Don't bother splitting concrete equivalence classes if there were invalid // requirements, because the signature is not going to be ABI anyway. if (!errorFlags.contains(GenericSignatureErrorFlags::HasInvalidRequirements)) { // Check if we need to rebuild the signature. if (shouldSplitConcreteEquivalenceClasses(result.getRequirements(), /*proto=*/nullptr, machine.get())) { ++attempt; splitConcreteEquivalenceClasses(ctx, result.getRequirements(), /*proto=*/nullptr, machine.get(), result.getGenericParams(), requirements, attempt); continue; } } if (!errorFlags) { // If this signature was minimized without errors or non-redundant // concrete conformances, we can re-use the requirement machine for // subsequent queries, instead of building a new requirement machine // from the minimized signature. Do this before verify(), which // performs queries. rewriteCtx.installRequirementMachine(result.getCanonicalSignature(), std::move(machine)); } if (genericParamList && !forExtension) { for (auto genericParam : result.getInnermostGenericParams()) { auto reduced = result.getReducedType(genericParam); if (reduced->hasError() || reduced->isEqual(genericParam)) continue; // If one side is a parameter pack and the other is not, this is a // same-element requirement that cannot be expressed with only one // type parameter. if (genericParam->isParameterPack() != reduced->isParameterPack()) continue; if (reduced->isTypeParameter()) { ctx.Diags.diagnose(loc, diag::requires_generic_params_made_equal, genericParam, result->getSugaredType(reduced)) .warnUntilSwiftVersion(6); } else { ctx.Diags.diagnose(loc, diag::requires_generic_param_made_equal_to_concrete, genericParam) .warnUntilSwiftVersion(6); } } } if (!errorFlags.contains(GenericSignatureErrorFlags::HasInvalidRequirements)) { // Check invariants. result.verify(); } if (rewriteCtx.getDebugOptions().contains(DebugFlags::Timers)) { rewriteCtx.endTimer("InferredGenericSignatureRequest"); llvm::dbgs() << result << "\n"; } return GenericSignatureWithError(result, errorFlags); } }