diff --git a/include/swift/Sema/ConstraintSystem.h b/include/swift/Sema/ConstraintSystem.h index 35cc33309b778..97f7d5f1479c4 100644 --- a/include/swift/Sema/ConstraintSystem.h +++ b/include/swift/Sema/ConstraintSystem.h @@ -4905,61 +4905,6 @@ class ConstraintSystem { return getExpressionTooComplex(solutionMemory); } - // Utility class that can collect information about the type of an - // argument in an apply. - // - // For example, when given a type variable type that represents the - // argument of a function call, it will walk the constraint graph - // finding any concrete types that are reachable through various - // subtype constraints and will also collect all the literal types - // conformed to by the types it finds on the walk. - // - // This makes it possible to get an idea of the kinds of literals - // and types of arguments that are used in the subexpression rooted - // in this argument, which we can then use to make better choices - // for how we partition the operators in a disjunction (in order to - // avoid visiting all the options). - class ArgumentInfoCollector { - ConstraintSystem &CS; - llvm::SetVector Types; - llvm::SetVector LiteralProtocols; - - void addType(Type ty) { - assert(!ty->is()); - Types.insert(ty); - } - - void addLiteralProtocol(ProtocolDecl *proto) { - LiteralProtocols.insert(proto); - } - - void walk(Type argType); - void minimizeLiteralProtocols(); - - public: - ArgumentInfoCollector(ConstraintSystem &cs, FunctionType *fnTy) : CS(cs) { - for (auto ¶m : fnTy->getParams()) - walk(param.getPlainType()); - - minimizeLiteralProtocols(); - } - - ArgumentInfoCollector(ConstraintSystem &cs, AnyFunctionType::Param param) - : CS(cs) { - walk(param.getPlainType()); - minimizeLiteralProtocols(); - } - - const llvm::SetVector &getTypes() const { return Types; } - const llvm::SetVector &getLiteralProtocols() const { - return LiteralProtocols; - } - - SWIFT_DEBUG_DUMP; - }; - - bool haveTypeInformationForAllArguments(FunctionType *fnType); - typedef std::function ConstraintMatcher; typedef std::function, ConstraintMatcher)> ConstraintMatchLoop; diff --git a/lib/Sema/CSSolver.cpp b/lib/Sema/CSSolver.cpp index 1d7084968d50e..2c12424a49e9d 100644 --- a/lib/Sema/CSSolver.cpp +++ b/lib/Sema/CSSolver.cpp @@ -1611,230 +1611,6 @@ static Constraint *selectBestBindingDisjunction( return firstBindDisjunction; } -// For a given type, collect any concrete types or literal -// conformances we can reach by walking the constraint graph starting -// from this point. -// -// For example, if the type is a type variable, we'll walk back -// through the constraints mentioning this type variable and find what -// types are converted to this type along with what literals are -// conformed-to by this type. -void ConstraintSystem::ArgumentInfoCollector::walk(Type argType) { - llvm::SmallSet visited; - llvm::SmallVector worklist; - worklist.push_back(argType); - - while (!worklist.empty()) { - auto itemTy = worklist.pop_back_val()->getRValueType(); - - if (!itemTy->is()) { - addType(itemTy); - continue; - } - - auto tyvar = itemTy->castTo(); - if (auto fixedTy = CS.getFixedType(tyvar)) { - addType(fixedTy); - continue; - } - - auto *rep = CS.getRepresentative(tyvar); - - // FIXME: This can happen when we have two type variables that are - // subtypes of each other. We would ideally merge those type - // variables somewhere. - if (visited.count(rep)) - continue; - - visited.insert(rep); - - auto constraints = CS.getConstraintGraph().gatherConstraints( - rep, ConstraintGraph::GatheringKind::EquivalenceClass); - - for (auto *constraint : constraints) { - switch (constraint->getKind()) { - case ConstraintKind::LiteralConformsTo: - addLiteralProtocol(constraint->getProtocol()); - break; - - case ConstraintKind::Bind: - case ConstraintKind::Equal: { - auto firstTy = constraint->getFirstType(); - auto secondTy = constraint->getSecondType(); - if (firstTy->is()) { - auto otherRep = - CS.getRepresentative(firstTy->castTo()); - if (otherRep->isEqual(rep)) - worklist.push_back(secondTy); - } - if (secondTy->is()) { - auto otherRep = - CS.getRepresentative(secondTy->castTo()); - if (otherRep->isEqual(rep)) - worklist.push_back(firstTy); - } - break; - } - - case ConstraintKind::Subtype: - case ConstraintKind::OperatorArgumentConversion: - case ConstraintKind::ArgumentConversion: - case ConstraintKind::Conversion: - case ConstraintKind::BridgingConversion: - case ConstraintKind::BindParam: - case ConstraintKind::OpaqueUnderlyingType: { - auto secondTy = constraint->getSecondType(); - if (secondTy->is()) { - auto otherRep = - CS.getRepresentative(secondTy->castTo()); - if (otherRep->isEqual(rep)) - worklist.push_back(constraint->getFirstType()); - } - break; - } - - case ConstraintKind::DynamicTypeOf: - case ConstraintKind::EscapableFunctionOf: { - auto firstTy = constraint->getFirstType(); - if (firstTy->is()) { - auto otherRep = - CS.getRepresentative(firstTy->castTo()); - if (otherRep->isEqual(rep)) - worklist.push_back(constraint->getSecondType()); - } - break; - } - - case ConstraintKind::OptionalObject: { - // Get the underlying object type. - auto secondTy = constraint->getSecondType(); - if (secondTy->is()) { - auto otherRep = - CS.getRepresentative(secondTy->castTo()); - if (otherRep->isEqual(rep)) { - // See if we can actually determine what the underlying - // type is. - Type fixedTy; - auto firstTy = constraint->getFirstType(); - if (!firstTy->is()) { - fixedTy = firstTy; - } else { - fixedTy = CS.getFixedType(firstTy->castTo()); - } - if (fixedTy && fixedTy->getOptionalObjectType()) - worklist.push_back(fixedTy->getOptionalObjectType()); - } - } - break; - } - - case ConstraintKind::KeyPathApplication: - case ConstraintKind::KeyPath: { - auto firstTy = constraint->getFirstType(); - if (firstTy->is()) { - auto otherRep = - CS.getRepresentative(firstTy->castTo()); - if (otherRep->isEqual(rep)) - worklist.push_back(constraint->getThirdType()); - } - break; - } - - case ConstraintKind::BindToPointerType: - case ConstraintKind::ValueMember: - case ConstraintKind::ValueWitness: - case ConstraintKind::UnresolvedValueMember: - case ConstraintKind::Disjunction: - case ConstraintKind::CheckedCast: - case ConstraintKind::OpenedExistentialOf: - case ConstraintKind::ApplicableFunction: - case ConstraintKind::DynamicCallableApplicableFunction: - case ConstraintKind::BindOverload: - case ConstraintKind::FunctionInput: - case ConstraintKind::FunctionResult: - case ConstraintKind::SelfObjectOfProtocol: - case ConstraintKind::ConformsTo: - case ConstraintKind::Defaultable: - case ConstraintKind::OneWayEqual: - case ConstraintKind::OneWayBindParam: - case ConstraintKind::DefaultClosureType: - break; - } - } - } -} - -void ConstraintSystem::ArgumentInfoCollector::minimizeLiteralProtocols() { - if (LiteralProtocols.size() <= 1) - return; - - llvm::SmallVector, 2> candidates; - llvm::SmallVector skippedProtocols; - - for (auto *protocol : LiteralProtocols) { - if (auto defaultType = TypeChecker::getDefaultType(protocol, CS.DC)) { - candidates.push_back({protocol, defaultType}); - continue; - } - - // Looks like argument expected to conform to something like - // `ExpressibleByNilLiteral` which doesn't have a default - // type and as a result can't participate in minimalization. - skippedProtocols.push_back(protocol); - } - - if (candidates.size() <= 1) - return; - - unsigned result = 0; - for (unsigned i = 1, n = candidates.size(); i != n; ++i) { - const auto &candidate = candidates[i]; - - auto first = - TypeChecker::conformsToProtocol(candidate.second, candidates[result].first, - CS.DC); - auto second = - TypeChecker::conformsToProtocol(candidates[result].second, candidate.first, - CS.DC); - if (first.isInvalid() == second.isInvalid()) - return; - - if (!first.isInvalid()) - result = i; - } - - LiteralProtocols.clear(); - LiteralProtocols.insert(candidates[result].first); - LiteralProtocols.insert(skippedProtocols.begin(), skippedProtocols.end()); -} - -void ConstraintSystem::ArgumentInfoCollector::dump() const { - auto &log = llvm::errs(); - log << "types:\n"; - for (auto type : Types) - type->print(log); - log << "\n"; - - log << "literal protocols:\n"; - for (auto *proto : LiteralProtocols) - proto->print(log); - log << "\n"; -} - -// Check to see if we know something about the types of all arguments -// in the given function type. -bool ConstraintSystem::haveTypeInformationForAllArguments( - FunctionType *fnType) { - llvm::SetVector literalConformsTo; - return llvm::all_of(fnType->getParams(), - [&](AnyFunctionType::Param param) -> bool { - ArgumentInfoCollector argInfo(*this, param); - auto countFacts = argInfo.getTypes().size() + - argInfo.getLiteralProtocols().size(); - return countFacts > 0; - }); -} - Optional> ConstraintSystem::findConstraintThroughOptionals( TypeVariableType *typeVar, OptionalWrappingDirection optionalDirection,