diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index c8ebc303849..8596e973bc9 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -2801,6 +2801,15 @@ namespace { } auto selected = *selectedElt; + if (!selected.choice.getBaseType()) { + // This is one of the "outer alternatives", meaning the innermost + // methods didn't work out. + return buildDeclRef(selected.choice, nameLoc, selected.openedFullType, + memberLocator, implicit, + selected.choice.getFunctionRefKind(), + AccessSemantics::Ordinary); + } + switch (selected.choice.getKind()) { case OverloadChoiceKind::DeclViaBridge: { base = cs.coerceToRValue(base); diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index ded69a562d4..aa80921300e 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -987,8 +987,13 @@ namespace { auto tv = CS.createTypeVariable( CS.getConstraintLocator(expr, ConstraintLocator::Member), TVO_CanBindToLValue); - CS.addValueMemberConstraint(baseTy, name, tv, CurDC, functionRefKind, - CS.getConstraintLocator(expr, ConstraintLocator::Member)); + SmallVector outerChoices; + for (auto decl : outerAlternatives) { + outerChoices.push_back(OverloadChoice(Type(), decl, functionRefKind)); + } + CS.addValueMemberConstraint( + baseTy, name, tv, CurDC, functionRefKind, outerChoices, + CS.getConstraintLocator(expr, ConstraintLocator::Member)); return tv; } @@ -1117,6 +1122,7 @@ namespace { } else { CS.addValueMemberConstraint(baseTy, DeclBaseName::createSubscript(), fnTy, CurDC, FunctionRefKind::DoubleApply, + /*outerAlternatives=*/{}, memberLocator); } @@ -1497,9 +1503,12 @@ namespace { TVO_PrefersSubtypeBinding); auto resultTy = CS.createTypeVariable(CS.getConstraintLocator(expr)); auto methodTy = FunctionType::get(argsTy, resultTy); - CS.addValueMemberConstraint(baseTy, expr->getName(), - methodTy, CurDC, expr->getFunctionRefKind(), - CS.getConstraintLocator(expr, ConstraintLocator::ConstructorMember)); + CS.addValueMemberConstraint( + baseTy, expr->getName(), methodTy, CurDC, + expr->getFunctionRefKind(), + /*outerAlternatives=*/{}, + CS.getConstraintLocator(expr, + ConstraintLocator::ConstructorMember)); // The result of the expression is the partial application of the // constructor to the subexpression. @@ -2863,6 +2872,7 @@ namespace { memberTy, CurDC, refKind, + /*outerAlternatives=*/{}, memberLocator); base = memberTy; break; diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index 2030667f96d..be86539a5c5 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -2555,6 +2555,7 @@ ConstraintSystem::simplifyConstructionConstraint( DeclBaseName::createConstructor(), FunctionType::get(tv, resultType), useDC, functionRefKind, + /*outerAlternatives=*/{}, getConstraintLocator( fnLocator, ConstraintLocator::ConstructorMember)); @@ -3443,14 +3444,11 @@ retry_after_fail: return result; } -ConstraintSystem::SolutionKind -ConstraintSystem::simplifyMemberConstraint(ConstraintKind kind, - Type baseTy, DeclName member, - Type memberTy, - DeclContext *useDC, - FunctionRefKind functionRefKind, - TypeMatchOptions flags, - ConstraintLocatorBuilder locatorB) { +ConstraintSystem::SolutionKind ConstraintSystem::simplifyMemberConstraint( + ConstraintKind kind, Type baseTy, DeclName member, Type memberTy, + DeclContext *useDC, FunctionRefKind functionRefKind, + ArrayRef outerAlternatives, TypeMatchOptions flags, + ConstraintLocatorBuilder locatorB) { // Resolve the base type, if we can. If we can't resolve the base type, // then we can't solve this constraint. // FIXME: simplifyType() call here could be getFixedTypeRecursive? @@ -3467,8 +3465,8 @@ ConstraintSystem::simplifyMemberConstraint(ConstraintKind kind, // If requested, generate a constraint. if (flags.contains(TMF_GenerateConstraints)) { addUnsolvedConstraint( - Constraint::createMember(*this, kind, baseTy, memberTy, member, useDC, - functionRefKind, locator)); + Constraint::createMemberOrOuterDisjunction(*this, kind, baseTy, memberTy, member, useDC, + functionRefKind, outerAlternatives, locator)); return SolutionKind::Solved; } @@ -3485,8 +3483,8 @@ ConstraintSystem::simplifyMemberConstraint(ConstraintKind kind, // If we found viable candidates, then we're done! if (!result.ViableCandidates.empty()) { addOverloadSet(memberTy, result.ViableCandidates, useDC, locator, - result.getFavoredChoice()); - + result.getFavoredChoice(), outerAlternatives); + return SolutionKind::Solved; } @@ -3522,7 +3520,8 @@ ConstraintSystem::simplifyMemberConstraint(ConstraintKind kind, // Look through one level of optional. addValueMemberConstraint(baseObjTy->getOptionalObjectType(), - member, memberTy, useDC, functionRefKind, locator); + member, memberTy, useDC, functionRefKind, + outerAlternatives, locator); return SolutionKind::Solved; } return SolutionKind::Error; @@ -5197,6 +5196,7 @@ ConstraintSystem::simplifyConstraint(const Constraint &constraint) { constraint.getSecondType(), constraint.getMemberUseDC(), constraint.getFunctionRefKind(), + /*outerAlternatives=*/{}, TMF_GenerateConstraints, constraint.getLocator()); diff --git a/lib/Sema/Constraint.cpp b/lib/Sema/Constraint.cpp index adfdfd3f844..68a7545c403 100644 --- a/lib/Sema/Constraint.cpp +++ b/lib/Sema/Constraint.cpp @@ -642,6 +642,25 @@ Constraint *Constraint::create(ConstraintSystem &cs, ConstraintKind kind, locator, typeVars); } +Constraint *Constraint::createMemberOrOuterDisjunction( + ConstraintSystem &cs, ConstraintKind kind, Type first, Type second, + DeclName member, DeclContext *useDC, FunctionRefKind functionRefKind, + ArrayRef outerAlternatives, ConstraintLocator *locator) { + auto memberConstraint = createMember(cs, kind, first, second, member, + useDC, functionRefKind, locator); + + if (outerAlternatives.empty()) + return memberConstraint; + + SmallVector constraints; + constraints.push_back(memberConstraint); + memberConstraint->setFavored(); + for (auto choice : outerAlternatives) { + constraints.push_back( + Constraint::createBindOverload(cs, first, choice, useDC, locator)); + } + return Constraint::createDisjunction(cs, constraints, locator, ForgetChoice); +} Constraint *Constraint::createMember(ConstraintSystem &cs, ConstraintKind kind, Type first, Type second, DeclName member, diff --git a/lib/Sema/Constraint.h b/lib/Sema/Constraint.h index 29f8269e070..ca09d09561a 100644 --- a/lib/Sema/Constraint.h +++ b/lib/Sema/Constraint.h @@ -435,6 +435,13 @@ public: Type First, Type Second, Type Third, ConstraintLocator *locator); + /// Create a new member constraint, or a disjunction of that with the outer + /// alternatives. + static Constraint *createMemberOrOuterDisjunction( + ConstraintSystem &cs, ConstraintKind kind, Type first, Type second, + DeclName member, DeclContext *useDC, FunctionRefKind functionRefKind, + ArrayRef outerAlternatives, ConstraintLocator *locator); + /// Create a new member constraint. static Constraint *createMember(ConstraintSystem &cs, ConstraintKind kind, Type first, Type second, DeclName member, diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index 59e53473e53..f70113a687b 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -1472,11 +1472,12 @@ void ConstraintSystem::addOverloadSet(Type boundType, ArrayRef choices, DeclContext *useDC, ConstraintLocator *locator, - OverloadChoice *favoredChoice) { + OverloadChoice *favoredChoice, + ArrayRef outerAlternatives) { assert(!choices.empty() && "Empty overload set"); // If there is a single choice, add the bind overload directly. - if (choices.size() == 1) { + if (choices.size() == 1 && outerAlternatives.empty()) { addBindOverloadConstraint(boundType, choices.front(), locator, useDC); return; } @@ -1512,7 +1513,26 @@ void ConstraintSystem::addOverloadSet(Type boundType, useDC, locator)); } - addDisjunctionConstraint(overloads, locator, ForgetChoice, favoredChoice); + auto innerDisjunction = Constraint::createDisjunction(*this, overloads, + locator, ForgetChoice); + if (outerAlternatives.empty()) { + if (favoredChoice) + innerDisjunction->setFavored(); + + addUnsolvedConstraint(innerDisjunction); + return; + } + + SmallVector outerConstraints; + outerConstraints.push_back(innerDisjunction); + innerDisjunction->setFavored(); + for (auto choice : outerAlternatives) { + outerConstraints.push_back(Constraint::createBindOverload( + *this, boundType, choice, + useDC, locator)); + } + + addDisjunctionConstraint(outerConstraints, locator, ForgetChoice, favoredChoice); } /// If we're resolving an overload set with a decl that has special type diff --git a/lib/Sema/ConstraintSystem.h b/lib/Sema/ConstraintSystem.h index 02f8554cc15..193fba4f2ed 100644 --- a/lib/Sema/ConstraintSystem.h +++ b/lib/Sema/ConstraintSystem.h @@ -1784,14 +1784,15 @@ public: void addValueMemberConstraint(Type baseTy, DeclName name, Type memberTy, DeclContext *useDC, FunctionRefKind functionRefKind, + ArrayRef outerAlternatives, ConstraintLocatorBuilder locator) { assert(baseTy); assert(memberTy); assert(name); assert(useDC); - switch (simplifyMemberConstraint(ConstraintKind::ValueMember, baseTy, name, - memberTy, useDC, functionRefKind, - TMF_GenerateConstraints, locator)) { + switch (simplifyMemberConstraint( + ConstraintKind::ValueMember, baseTy, name, memberTy, useDC, + functionRefKind, outerAlternatives, TMF_GenerateConstraints, locator)) { case SolutionKind::Unsolved: llvm_unreachable("Unsolved result when generating constraints!"); @@ -1800,10 +1801,9 @@ public: case SolutionKind::Error: if (shouldAddNewFailingConstraint()) { - addNewFailingConstraint( - Constraint::createMember(*this, ConstraintKind::ValueMember, baseTy, - memberTy, name, useDC, functionRefKind, - getConstraintLocator(locator))); + addNewFailingConstraint(Constraint::createMemberOrOuterDisjunction( + *this, ConstraintKind::ValueMember, baseTy, memberTy, name, useDC, + functionRefKind, outerAlternatives, getConstraintLocator(locator))); } break; } @@ -1822,6 +1822,7 @@ public: switch (simplifyMemberConstraint(ConstraintKind::UnresolvedValueMember, baseTy, name, memberTy, useDC, functionRefKind, + /*outerAlternatives=*/{}, TMF_GenerateConstraints, locator)) { case SolutionKind::Unsolved: llvm_unreachable("Unsolved result when generating constraints!"); @@ -2190,7 +2191,8 @@ public: /// sets. void addOverloadSet(Type boundType, ArrayRef choices, DeclContext *useDC, ConstraintLocator *locator, - OverloadChoice *favored = nullptr); + OverloadChoice *favored = nullptr, + ArrayRef outerAlternatives = {}); /// \brief Retrieve the allocator used by this constraint system. llvm::BumpPtrAllocator &getAllocator() { return Allocator; } @@ -2554,14 +2556,12 @@ private: ConstraintLocatorBuilder locator); /// \brief Attempt to simplify the given member constraint. - SolutionKind simplifyMemberConstraint(ConstraintKind kind, - Type baseType, DeclName member, - Type memberType, DeclContext *useDC, - FunctionRefKind functionRefKind, - TypeMatchOptions flags, - ConstraintLocatorBuilder locator); + SolutionKind simplifyMemberConstraint( + ConstraintKind kind, Type baseType, DeclName member, Type memberType, + DeclContext *useDC, FunctionRefKind functionRefKind, + ArrayRef outerAlternatives, TypeMatchOptions flags, + ConstraintLocatorBuilder locator); - /// \brief Attempt to simplify the optional object constraint. SolutionKind simplifyOptionalObjectConstraint( Type first, Type second,