From a1abcee108982e1786f0b45a757cae94a20edb3e Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Tue, 12 Oct 2021 09:51:44 +0100 Subject: [PATCH 1/4] [CS] Introduce ConstructorMemberType locator elt Use this new element to represent the overload type for a constructor call, and have it store a bit indicating whether the call is for a short-form `X(...)` or self-delegating `self.init(...)` call. --- include/swift/Sema/ConstraintLocator.h | 19 ++++++++++++++ .../swift/Sema/ConstraintLocatorPathElts.def | 3 +++ lib/Sema/CSGen.cpp | 25 ++++++++++++------- lib/Sema/CSSimplify.cpp | 12 ++++++--- lib/Sema/ConstraintLocator.cpp | 9 +++++++ 5 files changed, 56 insertions(+), 12 deletions(-) diff --git a/include/swift/Sema/ConstraintLocator.h b/include/swift/Sema/ConstraintLocator.h index 58286d50b39e2..57aec34e998fd 100644 --- a/include/swift/Sema/ConstraintLocator.h +++ b/include/swift/Sema/ConstraintLocator.h @@ -960,6 +960,25 @@ class LocatorPathElt::KeyPathType final } }; +class LocatorPathElt::ConstructorMemberType final + : public StoredIntegerElement<1> { +public: + ConstructorMemberType(bool isShortFormOrSelfDelegating = false) + : StoredIntegerElement(ConstraintLocator::ConstructorMemberType, + isShortFormOrSelfDelegating) {} + + /// Whether this constructor overload is for a short-form init call such as + /// 'X(...)', or a 'self.init(...)' call. Such calls have additional ranking + /// rules. + bool isShortFormOrSelfDelegatingConstructor() const { + return bool(getValue()); + } + + static bool classof(const LocatorPathElt *elt) { + return elt->getKind() == ConstraintLocator::ConstructorMemberType; + } +}; + class LocatorPathElt::ClosureBodyElement final : public StoredPointerElement { public: diff --git a/include/swift/Sema/ConstraintLocatorPathElts.def b/include/swift/Sema/ConstraintLocatorPathElts.def index 0eb57ecf58223..527a977da6158 100644 --- a/include/swift/Sema/ConstraintLocatorPathElts.def +++ b/include/swift/Sema/ConstraintLocatorPathElts.def @@ -60,6 +60,9 @@ CUSTOM_LOCATOR_PATH_ELT(ClosureBody) /// The lookup for a constructor member. SIMPLE_LOCATOR_PATH_ELT(ConstructorMember) +/// The constructor member type in the lookup of a constructor. +CUSTOM_LOCATOR_PATH_ELT(ConstructorMemberType) + /// The desired contextual type passed in to the constraint system. CUSTOM_LOCATOR_PATH_ELT(ContextualType) diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index 1787972004bbd..96f50af5a5fdb 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -1214,8 +1214,14 @@ namespace { auto *memberLoc = CS.getConstraintLocator(expr, ConstraintLocator::ConstructorMember); + auto *fnLoc = + CS.getConstraintLocator(expr, ConstraintLocator::ApplyFunction); + + auto *memberTypeLoc = CS.getConstraintLocator( + fnLoc, LocatorPathElt::ConstructorMemberType()); + auto *memberType = - CS.createTypeVariable(memberLoc, TVO_CanBindToNoEscape); + CS.createTypeVariable(memberTypeLoc, TVO_CanBindToNoEscape); CS.addValueMemberConstraint(MetatypeType::get(witnessType, ctx), DeclNameRef(constrName), memberType, CurDC, @@ -1228,10 +1234,9 @@ namespace { CS.getConstraintLocator(expr, ConstraintLocator::FunctionResult), TVO_CanBindToNoEscape); - CS.addConstraint( - ConstraintKind::ApplicableFunction, - FunctionType::get(params, resultType), memberType, - CS.getConstraintLocator(expr, ConstraintLocator::ApplyFunction)); + CS.addConstraint(ConstraintKind::ApplicableFunction, + FunctionType::get(params, resultType), memberType, + fnLoc); if (constr->isFailable()) return OptionalType::get(witnessType); @@ -1500,10 +1505,12 @@ namespace { // self.super = Super.init() baseTy = MetatypeType::get(baseTy, ctx); - auto methodTy = CS.createTypeVariable( - CS.getConstraintLocator(expr, - ConstraintLocator::ApplyFunction), - TVO_CanBindToNoEscape); + auto memberTypeLoc = CS.getConstraintLocator( + expr, LocatorPathElt::ConstructorMemberType( + /*shortFormOrSelfDelegating*/ true)); + + auto methodTy = + CS.createTypeVariable(memberTypeLoc, TVO_CanBindToNoEscape); // FIXME: Once TVO_PrefersSubtypeBinding is replaced with something // better, we won't need the second type variable at all. diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index 5c3eb28c48c00..3b3f9b3699de5 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -6214,8 +6214,11 @@ ConstraintSystem::simplifyConstructionConstraint( auto fnLocator = getConstraintLocator(locator, ConstraintLocator::ApplyFunction); - auto memberType = createTypeVariable(fnLocator, - TVO_CanBindToNoEscape); + auto memberTypeLoc = + getConstraintLocator(fnLocator, LocatorPathElt::ConstructorMemberType( + /*shortFormOrSelfDelegating*/ true)); + + auto memberType = createTypeVariable(memberTypeLoc, TVO_CanBindToNoEscape); // The constructor will have function type T -> T2, for a fresh type // variable T. T2 is the result type provided via the construction @@ -11338,7 +11341,10 @@ ConstraintSystem::simplifyRestrictedConstraintImpl( ArgumentLists.insert({memberLoc, argList}); } - auto *memberTy = createTypeVariable(memberLoc, TVO_CanBindToNoEscape); + auto *memberTypeLoc = getConstraintLocator( + applicationLoc, LocatorPathElt::ConstructorMemberType()); + + auto *memberTy = createTypeVariable(memberTypeLoc, TVO_CanBindToNoEscape); addValueMemberConstraint(MetatypeType::get(type2, getASTContext()), DeclNameRef(DeclBaseName::createConstructor()), diff --git a/lib/Sema/ConstraintLocator.cpp b/lib/Sema/ConstraintLocator.cpp index 677b596407f2d..c2424a69c2597 100644 --- a/lib/Sema/ConstraintLocator.cpp +++ b/lib/Sema/ConstraintLocator.cpp @@ -47,6 +47,7 @@ unsigned LocatorPathElt::getNewSummaryFlags() const { case ConstraintLocator::ClosureResult: case ConstraintLocator::ClosureBody: case ConstraintLocator::ConstructorMember: + case ConstraintLocator::ConstructorMemberType: case ConstraintLocator::ResultBuilderBodyResult: case ConstraintLocator::InstanceType: case ConstraintLocator::AutoclosureResult: @@ -322,6 +323,14 @@ void ConstraintLocator::dump(SourceManager *sm, raw_ostream &out) const { out << "constructor member"; break; + case ConstructorMemberType: { + auto memberTypeElt = elt.castTo(); + out << "constructor member type"; + if (memberTypeElt.isShortFormOrSelfDelegatingConstructor()) + out << " (for short-form or self.init call)"; + break; + } + case FunctionArgument: out << "function argument"; break; From fee31c69f0958a7349e54d72907f84d7b635205b Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Tue, 12 Oct 2021 09:51:44 +0100 Subject: [PATCH 2/4] [CS] Move constructor ranking rule into CSRanking Previously we were introducing a type variable to mark a constructor's parameter list as `TVO_PrefersSubtypeBinding`. Unfortunately this relies on representing the parameter list as a tuple, which will no longer be properly supported once param flags are removed from tuple types. Move the logic into CSRanking such that we pick up and compare the parameter lists when comparing overload bindings. For now, this still relies on comparing the parameter lists as tuples, as there's some subtle tuple subtyping rules that could potentially affect source compatibility here, but at least we can explicitly strip the parameter flags and localise the hack to CSRanking rather than exposing it as a constraint. --- lib/Sema/CSGen.cpp | 15 ---------- lib/Sema/CSRanking.cpp | 65 +++++++++++++++++++++++++++++++++++++++-- lib/Sema/CSSimplify.cpp | 12 -------- 3 files changed, 62 insertions(+), 30 deletions(-) diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index 96f50af5a5fdb..72fb440470304 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -1512,21 +1512,6 @@ namespace { auto methodTy = CS.createTypeVariable(memberTypeLoc, TVO_CanBindToNoEscape); - // FIXME: Once TVO_PrefersSubtypeBinding is replaced with something - // better, we won't need the second type variable at all. - { - auto argTy = CS.createTypeVariable( - CS.getConstraintLocator(expr, - ConstraintLocator::ApplyArgument), - (TVO_CanBindToLValue | - TVO_CanBindToInOut | - TVO_CanBindToNoEscape | - TVO_PrefersSubtypeBinding)); - CS.addConstraint( - ConstraintKind::FunctionInput, methodTy, argTy, - CS.getConstraintLocator(expr)); - } - CS.addValueMemberConstraint( baseTy, expr->getName(), methodTy, CurDC, expr->getFunctionRefKind(), diff --git a/lib/Sema/CSRanking.cpp b/lib/Sema/CSRanking.cpp index 0fd639e7f10d0..607d7e6e00be8 100644 --- a/lib/Sema/CSRanking.cpp +++ b/lib/Sema/CSRanking.cpp @@ -766,6 +766,38 @@ static void addKeyPathDynamicMemberOverloads( } } +/// Given the bound types of two constructor overloads, returns their parameter +/// list types as tuples to compare for solution ranking, or \c None if they +/// shouldn't be compared. +static Optional> +getConstructorParamsAsTuples(ASTContext &ctx, Type boundTy1, Type boundTy2) { + // If the bound types are placeholders, they haven't been resolved, so let's + // not try and rank them. + if (boundTy1->isPlaceholder() || boundTy2->isPlaceholder()) + return None; + + auto choiceTy1 = boundTy1->lookThroughAllOptionalTypes(); + auto choiceTy2 = boundTy2->lookThroughAllOptionalTypes(); + + auto initParams1 = choiceTy1->castTo()->getParams(); + auto initParams2 = choiceTy2->castTo()->getParams(); + if (initParams1.size() != initParams2.size()) + return None; + + // Don't compare if there are variadic differences. This preserves the + // behavior of when we'd compare through matchTupleTypes with the parameter + // flags intact. + for (auto idx : indices(initParams1)) { + if (initParams1[idx].isVariadic() != initParams2[idx].isVariadic()) + return None; + } + auto tuple1 = AnyFunctionType::composeTuple(ctx, initParams1, + /*wantParamFlags*/ false); + auto tuple2 = AnyFunctionType::composeTuple(ctx, initParams2, + /*wantParamFlags*/ false); + return std::make_pair(tuple1, tuple2); +} + SolutionCompareResult ConstraintSystem::compareSolutions( ConstraintSystem &cs, ArrayRef solutions, const SolutionDiff &diff, unsigned idx1, unsigned idx2) { @@ -1127,11 +1159,23 @@ SolutionCompareResult ConstraintSystem::compareSolutions( for (const auto &binding1 : bindings1) { auto *typeVar = binding1.first; + auto *loc = typeVar->getImpl().getLocator(); + + // Check whether this is the overload type for a short-form init call + // 'X(...)' or 'self.init(...)' call. + auto isShortFormOrSelfDelegatingConstructorBinding = false; + if (auto initMemberTypeElt = + loc->getLastElementAs()) { + isShortFormOrSelfDelegatingConstructorBinding = + initMemberTypeElt->isShortFormOrSelfDelegatingConstructor(); + } // If the type variable isn't one for which we should be looking at the // bindings, don't. - if (!typeVar->getImpl().prefersSubtypeBinding()) + if (!typeVar->getImpl().prefersSubtypeBinding() && + !isShortFormOrSelfDelegatingConstructorBinding) { continue; + } // If both solutions have a binding for this type variable // let's consider it. @@ -1142,9 +1186,24 @@ SolutionCompareResult ConstraintSystem::compareSolutions( auto concreteType1 = binding1.second; auto concreteType2 = binding2->second; - if (!concreteType1->isEqual(concreteType2)) { - typeDiff.insert({typeVar, {concreteType1, concreteType2}}); + // For short-form and self-delegating init calls, we want to prefer + // parameter lists with subtypes over supertypes. To do this, compose tuples + // for the bound parameter lists, and compare them in the type diff. This + // logic preserves the behavior of when we used to bind the parameter list + // as a tuple to a TVO_PrefersSubtypeBinding type variable for such calls. + // FIXME: We should come up with a better way of doing this, though note we + // have some ranking and subtyping rules specific to tuples that we may need + // to preserve to avoid breaking source. + if (isShortFormOrSelfDelegatingConstructorBinding) { + auto diffs = getConstructorParamsAsTuples(cs.getASTContext(), + concreteType1, concreteType2); + if (!diffs) + continue; + std::tie(concreteType1, concreteType2) = *diffs; } + + if (!concreteType1->isEqual(concreteType2)) + typeDiff.insert({typeVar, {concreteType1, concreteType2}}); } for (auto &binding : typeDiff) { diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index 3b3f9b3699de5..04902fe7a4dc8 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -6232,18 +6232,6 @@ ConstraintSystem::simplifyConstructionConstraint( fnLocator, ConstraintLocator::ConstructorMember)); - // FIXME: Once TVO_PrefersSubtypeBinding is replaced with something - // better, we won't need the second type variable at all. - { - auto argType = createTypeVariable( - getConstraintLocator(locator, ConstraintLocator::ApplyArgument), - (TVO_CanBindToLValue | - TVO_CanBindToInOut | - TVO_CanBindToNoEscape | - TVO_PrefersSubtypeBinding)); - addConstraint(ConstraintKind::FunctionInput, memberType, argType, locator); - } - addConstraint(ConstraintKind::ApplicableFunction, fnType, memberType, fnLocator); From b8e4c676c64c788e24cc3f9aa31cad5b38efb5e6 Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Tue, 12 Oct 2021 09:51:45 +0100 Subject: [PATCH 3/4] [CS] Remove function component constraints FunctionInput relies on being able to represent parameter lists as tuples, which won't be possible once parameter flags are stripped from tuple types. FunctionResult is reasonable, but is currently unused. --- include/swift/Sema/Constraint.h | 8 --- include/swift/Sema/ConstraintSystem.h | 7 --- lib/Sema/CSBindings.cpp | 2 - lib/Sema/CSSimplify.cpp | 86 --------------------------- lib/Sema/Constraint.cpp | 12 ---- 5 files changed, 115 deletions(-) diff --git a/include/swift/Sema/Constraint.h b/include/swift/Sema/Constraint.h index a332172825244..aeb3a4f61e49b 100644 --- a/include/swift/Sema/Constraint.h +++ b/include/swift/Sema/Constraint.h @@ -171,12 +171,6 @@ enum class ConstraintKind : char { /// The key path type is chosen based on the selection of overloads for the /// member references along the path. KeyPath, - /// The first type is a function type, the second is the function's - /// input type. - FunctionInput, - /// The first type is a function type, the second is the function's - /// result type. - FunctionResult, /// The first type will be equal to the second type, but only when the /// second type has been fully determined (and mapped down to a concrete /// type). At that point, this constraint will be treated like an `Equal` @@ -691,8 +685,6 @@ class Constraint final : public llvm::ilist_node, case ConstraintKind::KeyPath: case ConstraintKind::KeyPathApplication: case ConstraintKind::Defaultable: - case ConstraintKind::FunctionInput: - case ConstraintKind::FunctionResult: return ConstraintClassification::TypeProperty; case ConstraintKind::Disjunction: diff --git a/include/swift/Sema/ConstraintSystem.h b/include/swift/Sema/ConstraintSystem.h index e009eee2c9a77..c4c2c8810a798 100644 --- a/include/swift/Sema/ConstraintSystem.h +++ b/include/swift/Sema/ConstraintSystem.h @@ -4751,13 +4751,6 @@ class ConstraintSystem { TypeMatchOptions flags, ConstraintLocatorBuilder locator); - /// Attempt to simplify a function input or result constraint. - SolutionKind simplifyFunctionComponentConstraint( - ConstraintKind kind, - Type first, Type second, - TypeMatchOptions flags, - ConstraintLocatorBuilder locator); - /// Attempt to simplify the BridgingConversion constraint. SolutionKind simplifyBridgingConstraint(Type type1, Type type2, diff --git a/lib/Sema/CSBindings.cpp b/lib/Sema/CSBindings.cpp index e132cc762d903..528ce68b84b7b 100644 --- a/lib/Sema/CSBindings.cpp +++ b/lib/Sema/CSBindings.cpp @@ -1336,8 +1336,6 @@ void PotentialBindings::infer(Constraint *constraint) { case ConstraintKind::EscapableFunctionOf: case ConstraintKind::OpenedExistentialOf: case ConstraintKind::KeyPath: - case ConstraintKind::FunctionInput: - case ConstraintKind::FunctionResult: case ConstraintKind::ClosureBodyElement: case ConstraintKind::Conjunction: // Constraints from which we can't do anything. diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index 04902fe7a4dc8..c2fe56bd712aa 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -1632,8 +1632,6 @@ ConstraintSystem::matchTupleTypes(TupleType *tuple1, TupleType *tuple2, case ConstraintKind::ValueMember: case ConstraintKind::ValueWitness: case ConstraintKind::BridgingConversion: - case ConstraintKind::FunctionInput: - case ConstraintKind::FunctionResult: case ConstraintKind::OneWayEqual: case ConstraintKind::OneWayBindParam: case ConstraintKind::DefaultClosureType: @@ -1773,8 +1771,6 @@ static bool matchFunctionRepresentations(FunctionType::ExtInfo einfo1, case ConstraintKind::UnresolvedValueMember: case ConstraintKind::ValueMember: case ConstraintKind::ValueWitness: - case ConstraintKind::FunctionInput: - case ConstraintKind::FunctionResult: case ConstraintKind::OneWayEqual: case ConstraintKind::OneWayBindParam: case ConstraintKind::DefaultClosureType: @@ -2178,8 +2174,6 @@ ConstraintSystem::matchFunctionTypes(FunctionType *func1, FunctionType *func2, case ConstraintKind::ValueMember: case ConstraintKind::ValueWitness: case ConstraintKind::BridgingConversion: - case ConstraintKind::FunctionInput: - case ConstraintKind::FunctionResult: case ConstraintKind::OneWayEqual: case ConstraintKind::OneWayBindParam: case ConstraintKind::DefaultClosureType: @@ -5266,8 +5260,6 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind, case ConstraintKind::UnresolvedValueMember: case ConstraintKind::ValueMember: case ConstraintKind::ValueWitness: - case ConstraintKind::FunctionInput: - case ConstraintKind::FunctionResult: case ConstraintKind::OneWayEqual: case ConstraintKind::OneWayBindParam: case ConstraintKind::DefaultClosureType: @@ -7058,71 +7050,6 @@ ConstraintSystem::simplifyOptionalObjectConstraint( return SolutionKind::Solved; } -/// Attempt to simplify a function input or result constraint. -ConstraintSystem::SolutionKind -ConstraintSystem::simplifyFunctionComponentConstraint( - ConstraintKind kind, - Type first, Type second, - TypeMatchOptions flags, - ConstraintLocatorBuilder locator) { - auto simplified = simplifyType(first); - auto simplifiedCopy = simplified; - - unsigned unwrapCount = 0; - if (shouldAttemptFixes()) { - while (auto objectTy = simplified->getOptionalObjectType()) { - simplified = objectTy; - - // Track how many times we do this so that we can record a fix for each. - ++unwrapCount; - } - - if (simplified->isPlaceholder()) { - if (auto *typeVar = second->getAs()) - recordPotentialHole(typeVar); - return SolutionKind::Solved; - } - } - - if (simplified->isTypeVariableOrMember()) { - if (!flags.contains(TMF_GenerateConstraints)) - return SolutionKind::Unsolved; - - addUnsolvedConstraint( - Constraint::create(*this, kind, simplified, second, - getConstraintLocator(locator))); - } else if (auto *funcTy = simplified->getAs()) { - // Equate it to the other type in the constraint. - Type type; - ConstraintLocator::PathElementKind locKind; - - if (kind == ConstraintKind::FunctionInput) { - type = AnyFunctionType::composeTuple(getASTContext(), - funcTy->getParams()); - locKind = ConstraintLocator::FunctionArgument; - } else if (kind == ConstraintKind::FunctionResult) { - type = funcTy->getResult(); - locKind = ConstraintLocator::FunctionResult; - } else { - llvm_unreachable("Bad function component constraint kind"); - } - - addConstraint(ConstraintKind::Bind, type, second, - locator.withPathElement(locKind)); - } else { - return SolutionKind::Error; - } - - if (unwrapCount > 0) { - auto *fix = ForceOptional::create(*this, simplifiedCopy, second, - getConstraintLocator(locator)); - if (recordFix(fix, /*impact=*/unwrapCount)) - return SolutionKind::Error; - } - - return SolutionKind::Solved; -} - static bool isForKeyPathSubscript(ConstraintSystem &cs, ConstraintLocator *locator) { if (!locator || !locator->getAnchor()) @@ -12048,11 +11975,6 @@ ConstraintSystem::addConstraintImpl(ConstraintKind kind, Type first, case ConstraintKind::PropertyWrapper: return simplifyPropertyWrapperConstraint(first, second, subflags, locator); - case ConstraintKind::FunctionInput: - case ConstraintKind::FunctionResult: - return simplifyFunctionComponentConstraint(kind, first, second, - subflags, locator); - case ConstraintKind::OneWayEqual: case ConstraintKind::OneWayBindParam: return simplifyOneWayConstraint(kind, first, second, subflags, locator); @@ -12582,14 +12504,6 @@ ConstraintSystem::simplifyConstraint(const Constraint &constraint) { /*flags*/ None, constraint.getLocator()); - case ConstraintKind::FunctionInput: - case ConstraintKind::FunctionResult: - return simplifyFunctionComponentConstraint(constraint.getKind(), - constraint.getFirstType(), - constraint.getSecondType(), - /*flags*/ None, - constraint.getLocator()); - case ConstraintKind::Disjunction: case ConstraintKind::Conjunction: // {Dis, Con}junction constraints are never solved here. diff --git a/lib/Sema/Constraint.cpp b/lib/Sema/Constraint.cpp index 3d965e644f0c0..5cde5b9b54d4d 100644 --- a/lib/Sema/Constraint.cpp +++ b/lib/Sema/Constraint.cpp @@ -73,8 +73,6 @@ Constraint::Constraint(ConstraintKind Kind, Type First, Type Second, case ConstraintKind::EscapableFunctionOf: case ConstraintKind::OpenedExistentialOf: case ConstraintKind::OptionalObject: - case ConstraintKind::FunctionInput: - case ConstraintKind::FunctionResult: case ConstraintKind::OneWayEqual: case ConstraintKind::OneWayBindParam: case ConstraintKind::UnresolvedMemberChainBase: @@ -157,8 +155,6 @@ Constraint::Constraint(ConstraintKind Kind, Type First, Type Second, Type Third, case ConstraintKind::BindOverload: case ConstraintKind::Disjunction: case ConstraintKind::Conjunction: - case ConstraintKind::FunctionInput: - case ConstraintKind::FunctionResult: case ConstraintKind::OneWayEqual: case ConstraintKind::OneWayBindParam: case ConstraintKind::DefaultClosureType: @@ -302,8 +298,6 @@ Constraint *Constraint::clone(ConstraintSystem &cs) const { case ConstraintKind::DynamicCallableApplicableFunction: case ConstraintKind::OptionalObject: case ConstraintKind::Defaultable: - case ConstraintKind::FunctionInput: - case ConstraintKind::FunctionResult: case ConstraintKind::OneWayEqual: case ConstraintKind::OneWayBindParam: case ConstraintKind::DefaultClosureType: @@ -448,10 +442,6 @@ void Constraint::print(llvm::raw_ostream &Out, SourceManager *sm) const { break; case ConstraintKind::OptionalObject: Out << " optional with object type "; break; - case ConstraintKind::FunctionInput: - Out << " bind function input of "; break; - case ConstraintKind::FunctionResult: - Out << " bind function result of "; break; case ConstraintKind::BindOverload: { Out << " bound to "; auto overload = getOverloadChoice(); @@ -668,8 +658,6 @@ gatherReferencedTypeVars(Constraint *constraint, case ConstraintKind::LiteralConformsTo: case ConstraintKind::TransitivelyConformsTo: case ConstraintKind::SelfObjectOfProtocol: - case ConstraintKind::FunctionInput: - case ConstraintKind::FunctionResult: case ConstraintKind::OneWayEqual: case ConstraintKind::OneWayBindParam: case ConstraintKind::DefaultClosureType: From ac50dfd1d4af55b9e2ae1621d55b69fff50f8b67 Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Tue, 12 Oct 2021 09:51:45 +0100 Subject: [PATCH 4/4] [CS] Fix crasher caught by stress tester We need to be more lenient checking here as the type variable may not be bound yet. --- lib/Sema/CSRanking.cpp | 18 ++++++++++-------- test/Constraints/pr39543.swift | 11 +++++++++++ 2 files changed, 21 insertions(+), 8 deletions(-) create mode 100644 test/Constraints/pr39543.swift diff --git a/lib/Sema/CSRanking.cpp b/lib/Sema/CSRanking.cpp index 607d7e6e00be8..0b3ba4fb930fb 100644 --- a/lib/Sema/CSRanking.cpp +++ b/lib/Sema/CSRanking.cpp @@ -771,16 +771,18 @@ static void addKeyPathDynamicMemberOverloads( /// shouldn't be compared. static Optional> getConstructorParamsAsTuples(ASTContext &ctx, Type boundTy1, Type boundTy2) { - // If the bound types are placeholders, they haven't been resolved, so let's - // not try and rank them. - if (boundTy1->isPlaceholder() || boundTy2->isPlaceholder()) + auto choiceTy1 = + boundTy1->lookThroughAllOptionalTypes()->getAs(); + auto choiceTy2 = + boundTy2->lookThroughAllOptionalTypes()->getAs(); + + // If the type variables haven't been bound to functions yet, let's not try + // and rank them. + if (!choiceTy1 || !choiceTy2) return None; - auto choiceTy1 = boundTy1->lookThroughAllOptionalTypes(); - auto choiceTy2 = boundTy2->lookThroughAllOptionalTypes(); - - auto initParams1 = choiceTy1->castTo()->getParams(); - auto initParams2 = choiceTy2->castTo()->getParams(); + auto initParams1 = choiceTy1->getParams(); + auto initParams2 = choiceTy2->getParams(); if (initParams1.size() != initParams2.size()) return None; diff --git a/test/Constraints/pr39543.swift b/test/Constraints/pr39543.swift new file mode 100644 index 0000000000000..8acce5a2a4147 --- /dev/null +++ b/test/Constraints/pr39543.swift @@ -0,0 +1,11 @@ +// RUN: %target-swift-ide-test -code-completion -source-filename=%s -code-completion-token=CC + +// PR #39543: Make sure we can complete in this position without crashing. +extension String { + init(format: String, _: Any) { fatalError() } +} +extension RandomAccessCollection { + func foo() { + print(String(format: "", Int(distance(from:#^CC^# startIndex, to: startIndex)))) + } +}