From 1265f2e81e817eaa4a5125c2041c1d9fc70b4b94 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Thu, 18 Oct 2018 14:53:06 -0700 Subject: [PATCH 1/4] [Diagnostics] Replace curry level with a boolean flag Since arbitrary currying is no longer allowed `level` could be replaced with the boolean flag which identifies if curried `self` should be skipped or not. --- lib/Sema/CalleeCandidateInfo.cpp | 76 ++++++++++++++++---------------- lib/Sema/CalleeCandidateInfo.h | 10 ++--- 2 files changed, 42 insertions(+), 44 deletions(-) diff --git a/lib/Sema/CalleeCandidateInfo.cpp b/lib/Sema/CalleeCandidateInfo.cpp index 26f9ed88e5794..234bfb6469b44 100644 --- a/lib/Sema/CalleeCandidateInfo.cpp +++ b/lib/Sema/CalleeCandidateInfo.cpp @@ -56,8 +56,8 @@ static bool isSubstitutableFor(Type type, ArchetypeType *archetype, return true; } -UncurriedCandidate::UncurriedCandidate(ValueDecl *decl, unsigned level) -: declOrExpr(decl), level(level), substituted(false) { +UncurriedCandidate::UncurriedCandidate(ValueDecl *decl, bool skipCurriedSelf) +: declOrExpr(decl), skipCurriedSelf(skipCurriedSelf), substituted(false) { if (auto *PD = dyn_cast(decl)) { if (PD->hasValidSignature()) @@ -95,15 +95,15 @@ ArrayRef UncurriedCandidate::getArgumentLabels( if (auto decl = getDecl()) { if (auto func = dyn_cast(decl)) { if (func->hasImplicitSelfDecl()) { - if (level == 0) { + if (!skipCurriedSelf) { scratch.push_back(Identifier()); return scratch; } - --level; + skipCurriedSelf = false; } - if (level == 0) { + if (!skipCurriedSelf) { // Retrieve the argument labels of the corresponding parameter list. for (auto param : *func->getParameters()) { scratch.push_back(param->getArgumentName()); @@ -112,20 +112,18 @@ ArrayRef UncurriedCandidate::getArgumentLabels( } } else if (auto enumElt = dyn_cast(decl)) { // 'self' - if (level == 0) { + if (!skipCurriedSelf) { scratch.push_back(Identifier()); return scratch; } // The associated data of the case. - if (level == 1) { - auto *paramList = enumElt->getParameterList(); - if (!paramList) return { }; - for (auto param : *paramList) { - scratch.push_back(param->getArgumentName()); - } - return scratch; + auto *paramList = enumElt->getParameterList(); + if (!paramList) return { }; + for (auto param : *paramList) { + scratch.push_back(param->getArgumentName()); } + return scratch; } } @@ -143,7 +141,8 @@ void UncurriedCandidate::dump() const { decl->dumpRef(llvm::errs()); else llvm::errs() << "<>"; - llvm::errs() << " - uncurry level " << level; + llvm::errs() << " - ignore curried self = " << (skipCurriedSelf ? "yes" + : "no"); if (auto FT = getUncurriedFunctionType()) llvm::errs() << " - type: " << Type(FT) << "\n"; @@ -322,7 +321,7 @@ CalleeCandidateInfo::evaluateCloseness(UncurriedCandidate candidate, auto candArgs = candidate.getParameters(); SmallBitVector candDefaultMap = - computeDefaultMap(candArgs, candidate.getDecl(), candidate.level); + computeDefaultMap(candArgs, candidate.getDecl(), candidate.skipCurriedSelf); struct OurListener : public MatchCallArgumentListener { CandidateCloseness result = CC_ExactMatch; @@ -589,28 +588,27 @@ void CalleeCandidateInfo::collectCalleeCandidates(Expr *fn, /*implicitDotSyntax=*/false); } - // Determine the callee level for a "bare" reference to the given - // declaration. - auto getCalleeLevel = [implicitDotSyntax](ValueDecl *decl) -> unsigned { + // Determine if we need to skip "self" to get to a "bare" reference. + auto skipCurriedSelf = [implicitDotSyntax](ValueDecl *decl) -> bool { if (auto func = dyn_cast(decl)) { if (func->isOperator() && func->getDeclContext()->isTypeContext() && !implicitDotSyntax) - return 1; + return true; } - return 0; + return false; }; if (auto declRefExpr = dyn_cast(fn)) { auto decl = declRefExpr->getDecl(); - candidates.push_back({ decl, getCalleeLevel(decl) }); + candidates.push_back({ decl, skipCurriedSelf(decl) }); declName = decl->getBaseName().userFacingName(); return; } if (auto declRefExpr = dyn_cast(fn)) { auto decl = declRefExpr->getDecl(); - candidates.push_back({ decl, getCalleeLevel(decl) }); + candidates.push_back({ decl, skipCurriedSelf(decl) }); if (auto selfTy = decl->getDeclContext()->getSelfInterfaceType()) declName = selfTy.getString() + ".init"; @@ -621,7 +619,7 @@ void CalleeCandidateInfo::collectCalleeCandidates(Expr *fn, if (auto overloadedDRE = dyn_cast(fn)) { for (auto cand : overloadedDRE->getDecls()) { - candidates.push_back({ cand, getCalleeLevel(cand) }); + candidates.push_back({ cand, skipCurriedSelf(cand) }); } if (!candidates.empty()) @@ -671,12 +669,13 @@ void CalleeCandidateInfo::collectCalleeCandidates(Expr *fn, baseType = CS.getType(AE->getArg())->getWithoutSpecifierType(); for (auto &C : candidates) { - C.level += 1; + bool hadCurriedSelf = C.skipCurriedSelf; + C.skipCurriedSelf = true; baseType = replaceTypeVariablesWithUnresolved(baseType); // Compute a new substituted type if we have a base type to apply. - if (baseType && C.level == 1 && C.getDecl()) { + if (baseType && !hadCurriedSelf && C.getDecl()) { baseType = baseType ->getWithoutSpecifierType() ->getMetatypeInstanceType(); @@ -691,7 +690,7 @@ void CalleeCandidateInfo::collectCalleeCandidates(Expr *fn, } } } - + return; } } @@ -709,28 +708,27 @@ void CalleeCandidateInfo::collectCalleeCandidates(Expr *fn, // Otherwise, we couldn't tell structurally what is going on here, so try to // dig something out of the constraint system. - unsigned uncurryLevel = 0; + bool hasCurriedSelf = false; // The candidate list of an unresolved_dot_expr is the candidate list of the // base uncurried by one level, and we refer to the name of the member, not to // the name of any base. if (auto UDE = dyn_cast(fn)) { declName = UDE->getName().getBaseName().userFacingName(); - uncurryLevel = 1; + hasCurriedSelf = true; // If base is a module or metatype, this is just a simple // reference so its curry level should be 0. if (auto *DRE = dyn_cast(UDE->getBase())) { if (auto baseType = DRE->getType()) - uncurryLevel = - (baseType->is() || baseType->is()) ? 0 - : 1; + hasCurriedSelf = !(baseType->is() || + baseType->is()); } // If we actually resolved the member to use, return it. auto loc = CS.getConstraintLocator(UDE, ConstraintLocator::Member); if (auto *member = CS.findResolvedMemberRef(loc)) { - candidates.push_back({ member, uncurryLevel }); + candidates.push_back({ member, hasCurriedSelf }); return; } @@ -738,7 +736,7 @@ void CalleeCandidateInfo::collectCalleeCandidates(Expr *fn, auto ctorLoc = CS.getConstraintLocator(UDE, ConstraintLocator::ConstructorMember); if (auto *member = CS.findResolvedMemberRef(ctorLoc)) { - candidates.push_back({ member, uncurryLevel }); + candidates.push_back({ member, hasCurriedSelf }); return; } @@ -754,7 +752,7 @@ void CalleeCandidateInfo::collectCalleeCandidates(Expr *fn, } if (isa(fn)) - uncurryLevel = 1; + hasCurriedSelf = true; // Scan to see if we have a disjunction constraint for this callee. for (auto &constraint : CS.getConstraints()) { @@ -768,7 +766,7 @@ void CalleeCandidateInfo::collectCalleeCandidates(Expr *fn, continue; auto c = bindOverload->getOverloadChoice(); if (c.isDecl()) - candidates.push_back({ c.getDecl(), uncurryLevel }); + candidates.push_back({ c.getDecl(), hasCurriedSelf }); } // If we found some candidates, then we're done. @@ -865,13 +863,13 @@ CalleeCandidateInfo::CalleeCandidateInfo(Type baseType, auto decl = cand.getDecl(); // If this is a method or enum case member (not a var or subscript), then - // the uncurry level is 1 if self has already been applied. - unsigned uncurryLevel = 0; + // we need to skip `self` if it has already been applied. + bool hasCurriedSelf = false; if (decl->getDeclContext()->isTypeContext() && selfAlreadyApplied && !isa(decl)) - uncurryLevel = 1; + hasCurriedSelf = true; - candidates.push_back({ decl, uncurryLevel }); + candidates.push_back({ decl, hasCurriedSelf }); // If we have a base type for this member, try to perform substitutions into // it to get a simpler and more concrete type. diff --git a/lib/Sema/CalleeCandidateInfo.h b/lib/Sema/CalleeCandidateInfo.h index 4b6301e8d9533..d202fe48af028 100644 --- a/lib/Sema/CalleeCandidateInfo.h +++ b/lib/Sema/CalleeCandidateInfo.h @@ -59,7 +59,7 @@ namespace swift { /// struct UncurriedCandidate { PointerUnion declOrExpr; - unsigned level; + bool skipCurriedSelf; Type entityType; // If true, entityType is written in terms of caller archetypes, @@ -71,9 +71,10 @@ namespace swift { // FIXME: Clean this up. bool substituted; - UncurriedCandidate(ValueDecl *decl, unsigned level); + UncurriedCandidate(ValueDecl *decl, bool skipCurriedSelf); UncurriedCandidate(Expr *expr, Type type) - : declOrExpr(expr), level(0), entityType(type), substituted(true) {} + : declOrExpr(expr), skipCurriedSelf(false), entityType(type), + substituted(true) {} ValueDecl *getDecl() const { return declOrExpr.dyn_cast(); @@ -86,12 +87,11 @@ namespace swift { Type getUncurriedType() const { // Start with the known type of the decl. auto type = entityType; - for (unsigned i = 0, e = level; i != e; ++i) { + if (skipCurriedSelf) { auto funcTy = type->getAs(); if (!funcTy) return Type(); type = funcTy->getResult(); } - return type; } From e20723f6c8881a994f6ff124a97382343bb4753c Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Thu, 18 Oct 2018 15:14:50 -0700 Subject: [PATCH 2/4] [ConstraintSystem] Replace curry level with a boolean flag Arbitrary currying is no longer allowed so level could be switched to a boolean flag for methods like `computeDefaultMap` to identify if they need to look through curried self type or not. --- include/swift/AST/Types.h | 2 +- lib/AST/Type.cpp | 10 +++--- lib/Sema/CSApply.cpp | 30 +++++++++--------- lib/Sema/CSDiag.cpp | 38 +++++++++++------------ lib/Sema/CSSimplify.cpp | 62 +++++++++++++++++++++---------------- lib/Sema/ConstraintSystem.h | 2 +- 6 files changed, 76 insertions(+), 68 deletions(-) diff --git a/include/swift/AST/Types.h b/include/swift/AST/Types.h index 9d3a9844c677c..520597494c3ba 100644 --- a/include/swift/AST/Types.h +++ b/include/swift/AST/Types.h @@ -3078,7 +3078,7 @@ END_CAN_TYPE_WRAPPER(FunctionType, AnyFunctionType) /// it. SmallBitVector computeDefaultMap(ArrayRef params, - const ValueDecl *paramOwner, unsigned level); + const ValueDecl *paramOwner, bool skipCurriedSelf); /// Turn a param list into a symbolic and printable representation that does not /// include the types, something like (: , b:, c:) diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 3618f5b4ec800..e18b663a65dc9 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -749,7 +749,7 @@ Type TypeBase::replaceCovariantResultType(Type newResultType, SmallBitVector swift::computeDefaultMap(ArrayRef params, - const ValueDecl *paramOwner, unsigned level) { + const ValueDecl *paramOwner, bool skipCurriedSelf) { SmallBitVector resultVector(params.size()); // No parameter owner means no parameter list means no default arguments // - hand back the zeroed bitvector. @@ -762,15 +762,15 @@ swift::computeDefaultMap(ArrayRef params, const ParameterList *paramList = nullptr; if (auto *func = dyn_cast(paramOwner)) { if (func->hasImplicitSelfDecl()) { - if (level == 1) + if (skipCurriedSelf) paramList = func->getParameters(); - } else if (level == 0) + } else if (!skipCurriedSelf) paramList = func->getParameters(); } else if (auto *subscript = dyn_cast(paramOwner)) { - if (level == 1) + if (skipCurriedSelf) paramList = subscript->getIndices(); } else if (auto *enumElement = dyn_cast(paramOwner)) { - if (level == 1) + if (skipCurriedSelf) paramList = enumElement->getParameterList(); } diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index 587ebd76efe73..f2aa156ec86ed 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -5450,36 +5450,36 @@ static bool isReferenceToMetatypeMember(ConstraintSystem &cs, Expr *expr) { return false; } -static unsigned computeCallLevel(ConstraintSystem &cs, ConcreteDeclRef callee, - ApplyExpr *apply) { - // If we do not have a callee, return a level of 0. +static bool hasCurriedSelf(ConstraintSystem &cs, ConcreteDeclRef callee, + ApplyExpr *apply) { + // If we do not have a callee, return false. if (!callee) { - return 0; + return false; } - // Only calls to members of types can have level > 0. + // Only calls to members of types can have curried 'self'. auto calleeDecl = callee.getDecl(); if (!calleeDecl->getDeclContext()->isTypeContext()) { - return 0; + return false; } - // Level 1 if we're not applying "self". + // Would have `self`, if we're not applying it. if (auto *call = dyn_cast(apply)) { if (!calleeDecl->isInstanceMember() || !isReferenceToMetatypeMember(cs, call->getDirectCallee())) { - return 1; + return true; } - return 0; + return false; } - // Level 1 if we have an operator. + // Operators have curried self. if (isa(apply) || isa(apply) || isa(apply)) { - return 1; + return true; } // Otherwise, we have a normal application. - return 0; + return false; } Expr *ExprRewriter::coerceCallArguments( @@ -5507,12 +5507,12 @@ Expr *ExprRewriter::coerceCallArguments( ConcreteDeclRef callee = findCalleeDeclRef(cs, solution, cs.getConstraintLocator(locator)); - // Determine the level, - unsigned level = apply ? computeCallLevel(cs, callee, apply) : 0; + // Determine whether this application has curried self. + bool skipCurriedSelf = apply ? hasCurriedSelf(cs, callee, apply) : false; // Determine the parameter bindings. SmallBitVector defaultMap - = computeDefaultMap(params, callee.getDecl(), level); + = computeDefaultMap(params, callee.getDecl(), skipCurriedSelf); SmallVector args; AnyFunctionType::decomposeInput(cs.getType(arg), args); diff --git a/lib/Sema/CSDiag.cpp b/lib/Sema/CSDiag.cpp index e89a8f4cc7f97..b3398f27a0b66 100644 --- a/lib/Sema/CSDiag.cpp +++ b/lib/Sema/CSDiag.cpp @@ -2856,10 +2856,10 @@ static bool candidatesHaveAnyDefaultValues( if (!function) continue; if (function->hasImplicitSelfDecl()) { - if (cand.level != 1) + if (!cand.skipCurriedSelf) return false; } else { - if (cand.level != 0) + if (cand.skipCurriedSelf) return false; } @@ -2910,10 +2910,10 @@ static Optional getElementForScalarInitOfArg( if (!function) return getElementForScalarInitSimple(tupleTy); if (function->hasImplicitSelfDecl()) { - if (cand.level != 1) + if (!cand.skipCurriedSelf) return getElementForScalarInitSimple(tupleTy); } else { - if (cand.level != 0) + if (cand.skipCurriedSelf) return getElementForScalarInitSimple(tupleTy); } @@ -2987,7 +2987,7 @@ typeCheckArgumentChildIndependently(Expr *argExpr, Type argType, // diagnostics when we don't force the self type down. if (argType && !candidates.empty()) if (auto decl = candidates[0].getDecl()) - if (decl->isInstanceMember() && candidates[0].level == 0 && + if (decl->isInstanceMember() && !candidates[0].skipCurriedSelf && !isa(decl)) argType = Type(); @@ -3052,7 +3052,7 @@ typeCheckArgumentChildIndependently(Expr *argExpr, Type argType, SmallBitVector defaultMap(params.size()); if (!candidates.empty()) { defaultMap = computeDefaultMap(params, candidates[0].getDecl(), - candidates[0].level); + candidates[0].skipCurriedSelf); } // Form a set of call arguments, using a dummy type (Void), because the @@ -3461,14 +3461,15 @@ diagnoseInstanceMethodAsCurriedMemberOnType(CalleeCandidateInfo &CCI, // it might be worth while to check if it's instance method as curried // member of type problem. if (CCI.closeness == CC_ExactMatch && - (decl->isInstanceMember() && candidate.level == 1)) + (decl->isInstanceMember() && candidate.skipCurriedSelf)) continue; auto params = candidate.getParameters(); // If one of the candidates is an instance method with a single parameter // at the level 0, this might be viable situation for calling instance // method as curried member of type problem. - if (params.size() != 1 || !decl->isInstanceMember() || candidate.level > 0) + if (params.size() != 1 || !decl->isInstanceMember() || + candidate.skipCurriedSelf) return false; } @@ -4020,7 +4021,7 @@ diagnoseSingleCandidateFailures(CalleeCandidateInfo &CCI, Expr *fnExpr, auto params = candidate.getParameters(); SmallBitVector defaultMap = - computeDefaultMap(params, candidate.getDecl(), candidate.level); + computeDefaultMap(params, candidate.getDecl(), candidate.skipCurriedSelf); auto args = decomposeArgType(CCI.CS.getType(argExpr), argLabels); // Check the case where a raw-representable type is constructed from an @@ -4034,7 +4035,7 @@ diagnoseSingleCandidateFailures(CalleeCandidateInfo &CCI, Expr *fnExpr, // MyEnumType.foo // if (params.size() == 1 && args.size() == 1 && candidate.getDecl() && - isa(candidate.getDecl()) && candidate.level == 1) { + isa(candidate.getDecl()) && candidate.skipCurriedSelf) { AnyFunctionType::Param &arg = args[0]; auto resTy = candidate.getResultType()->lookThroughAllOptionalTypes(); @@ -4320,7 +4321,7 @@ bool FailureDiagnosis::diagnoseSubscriptErrors(SubscriptExpr *SE, // We're about to typecheck the index list, which needs to be processed with // self already applied. for (unsigned i = 0, e = calleeInfo.size(); i != e; ++i) - ++calleeInfo.candidates[i].level; + calleeInfo.candidates[i].skipCurriedSelf = true; auto indexExpr = typeCheckArgumentChildIndependently(SE->getIndex(), Type(), calleeInfo); @@ -4329,7 +4330,7 @@ bool FailureDiagnosis::diagnoseSubscriptErrors(SubscriptExpr *SE, // Back to analyzing the candidate list with self applied. for (unsigned i = 0, e = calleeInfo.size(); i != e; ++i) - --calleeInfo.candidates[i].level; + calleeInfo.candidates[i].skipCurriedSelf = false; ArrayRef argLabels = SE->getArgumentLabels(); if (diagnoseParameterErrors(calleeInfo, SE, indexExpr, argLabels)) @@ -4353,9 +4354,8 @@ bool FailureDiagnosis::diagnoseSubscriptErrors(SubscriptExpr *SE, CC_ExactMatch) selfConstraint = CC_SelfMismatch; - // Increase the uncurry level to look past the self argument to the - // indices. - cand.level++; + // Set a flag to look past the self argument to the indices. + cand.skipCurriedSelf = true; // Explode out multi-index subscripts to find the best match. auto indexResult = @@ -4378,7 +4378,7 @@ bool FailureDiagnosis::diagnoseSubscriptErrors(SubscriptExpr *SE, // Any other failures relate to the index list. for (unsigned i = 0, e = calleeInfo.size(); i != e; ++i) - ++calleeInfo.candidates[i].level; + calleeInfo.candidates[i].skipCurriedSelf = true; // TODO: Is there any reason to check for CC_NonLValueInOut here? @@ -4668,7 +4668,7 @@ bool FailureDiagnosis::diagnoseArgumentGenericRequirements( auto params = candidate.getParameters(); SmallBitVector defaultMap = - computeDefaultMap(params, candidate.getDecl(), candidate.level); + computeDefaultMap(params, candidate.getDecl(), candidate.skipCurriedSelf); auto args = decomposeArgType(CS.getType(argExpr), argLabels); SmallVector bindings; @@ -5232,7 +5232,7 @@ static bool isViableOverloadSet(const CalleeCandidateInfo &CCI, return true; }; - auto defaultMap = computeDefaultMap(params, funcDecl, cand.level); + auto defaultMap = computeDefaultMap(params, funcDecl, cand.skipCurriedSelf); InputMatcher IM(params, defaultMap); auto result = IM.match(numArgs, pairMatcher); if (result == InputMatcher::IM_Succeeded) @@ -5413,7 +5413,7 @@ bool FailureDiagnosis::visitApplyExpr(ApplyExpr *callExpr) { if (!calleeInfo.empty()) { auto &&cand = calleeInfo[0]; auto decl = cand.getDecl(); - if (decl && decl->isInstanceMember() && cand.level == 0 && + if (decl && decl->isInstanceMember() && !cand.skipCurriedSelf && cand.getParameters().size() == 1) isInstanceMethodAsCurriedMemberOnType = true; } diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index 638f8a6e8ed9c..ec11896b769cc 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -93,7 +93,7 @@ static Optional scoreParamAndArgNameTypo(StringRef paramName, bool constraints:: areConservativelyCompatibleArgumentLabels(ValueDecl *decl, - unsigned parameterDepth, + bool hasCurriedSelf, ArrayRef labels, bool hasTrailingClosure) { // Bail out conservatively if this isn't a function declaration. @@ -108,14 +108,14 @@ areConservativelyCompatibleArgumentLabels(ValueDecl *decl, } const AnyFunctionType *levelTy = fTy; - for (auto level = parameterDepth; level != 0; --level) { + if (hasCurriedSelf) { levelTy = levelTy->getResult()->getAs(); assert(levelTy && "Parameter list curry level does not match type"); } auto params = levelTy->getParams(); SmallBitVector defaultMap = - computeDefaultMap(params, decl, parameterDepth); + computeDefaultMap(params, decl, hasCurriedSelf); MatchCallArgumentListener listener; SmallVector unusedParamBindings; @@ -576,7 +576,7 @@ matchCallArguments(ArrayRef args, /// Find the callee declaration and uncurry level for a given call /// locator. -static std::tuple, bool> +static std::tuple, bool> getCalleeDeclAndArgs(ConstraintSystem &cs, ConstraintLocatorBuilder callLocator, SmallVectorImpl &argLabelsScratch) { @@ -586,14 +586,16 @@ getCalleeDeclAndArgs(ConstraintSystem &cs, // Break down the call. SmallVector path; auto callExpr = callLocator.getLocatorParts(path); - if (!callExpr) - return std::make_tuple(nullptr, 0, argLabels, hasTrailingClosure); + if (!callExpr) + return std::make_tuple(nullptr, /*hasCurriedSelf=*/false, argLabels, + hasTrailingClosure); // Our remaining path can only be 'ApplyArgument'. if (!path.empty() && !(path.size() <= 2 && path.back().getKind() == ConstraintLocator::ApplyArgument)) - return std::make_tuple(nullptr, 0, argLabels, hasTrailingClosure); + return std::make_tuple(nullptr, /*hasCurriedSelf=*/false, argLabels, + hasTrailingClosure); // Dig out the callee. ConstraintLocator *targetLocator; @@ -617,11 +619,13 @@ getCalleeDeclAndArgs(ConstraintSystem &cs, if (path.size() != 2 || path[0].getKind() != ConstraintLocator::KeyPathComponent || path[1].getKind() != ConstraintLocator::ApplyArgument) - return std::make_tuple(nullptr, 0, argLabels, hasTrailingClosure); - + return std::make_tuple(nullptr, /*hasCurriedSelf=*/false, argLabels, + hasTrailingClosure); + auto componentIndex = path[0].getValue(); if (componentIndex >= keyPath->getComponents().size()) - return std::make_tuple(nullptr, 0, argLabels, hasTrailingClosure); + return std::make_tuple(nullptr, /*hasCurriedSelf=*/false, argLabels, + hasTrailingClosure); auto &component = keyPath->getComponents()[componentIndex]; switch (component.getKind()) { @@ -639,7 +643,8 @@ getCalleeDeclAndArgs(ConstraintSystem &cs, case KeyPathExpr::Component::Kind::OptionalChain: case KeyPathExpr::Component::Kind::OptionalWrap: case KeyPathExpr::Component::Kind::Identity: - return std::make_tuple(nullptr, 0, argLabels, hasTrailingClosure); + return std::make_tuple(nullptr, /*hasCurriedSelf=*/false, argLabels, + hasTrailingClosure); } } else { @@ -650,7 +655,8 @@ getCalleeDeclAndArgs(ConstraintSystem &cs, argLabels = objectLiteral->getArgumentLabels(); hasTrailingClosure = objectLiteral->hasTrailingClosure(); } - return std::make_tuple(nullptr, 0, argLabels, hasTrailingClosure); + return std::make_tuple(nullptr, /*hasCurriedSelf=*/false, argLabels, + hasTrailingClosure); } // Find the overload choice corresponding to the callee locator. @@ -690,12 +696,13 @@ getCalleeDeclAndArgs(ConstraintSystem &cs, // If we didn't find any matching overloads, we're done. if (!choice) - return std::make_tuple(nullptr, 0, argLabels, hasTrailingClosure); + return std::make_tuple(nullptr, /*hasCurriedSelf=*/false, argLabels, + hasTrailingClosure); // If there's a declaration, return it. if (choice->isDecl()) { auto decl = choice->getDecl(); - unsigned level = 0; + bool hasCurriedSelf = false; if (decl->getDeclContext()->isTypeContext()) { if (auto function = dyn_cast(decl)) { // References to instance members on a metatype stay at level 0. @@ -704,20 +711,21 @@ getCalleeDeclAndArgs(ConstraintSystem &cs, cs.getFixedTypeRecursive(choice->getBaseType(), /*wantRValue=*/true) ->is())) - level = 1; + hasCurriedSelf = true; } else if (isa(decl)) { // Subscript level 1 == the indices. - level = 1; + hasCurriedSelf = true; } else if (isa(decl)) { // Enum element level 1 == the payload. - level = 1; + hasCurriedSelf = true; } } - return std::make_tuple(decl, level, argLabels, hasTrailingClosure); + return std::make_tuple(decl, hasCurriedSelf, argLabels, hasTrailingClosure); } - return std::make_tuple(nullptr, 0, argLabels, hasTrailingClosure); + return std::make_tuple(nullptr, /*hasCurriedSelf=*/false, argLabels, + hasTrailingClosure); } class ArgumentFailureTracker : public MatchCallArgumentListener { @@ -761,15 +769,15 @@ ConstraintSystem::TypeMatchResult constraints::matchCallArguments( ArrayRef params, ConstraintLocatorBuilder locator) { // Extract the parameters. ValueDecl *callee; - unsigned calleeLevel; + bool hasCurriedSelf; ArrayRef argLabels; SmallVector argLabelsScratch; bool hasTrailingClosure = false; - std::tie(callee, calleeLevel, argLabels, hasTrailingClosure) = + std::tie(callee, hasCurriedSelf, argLabels, hasTrailingClosure) = getCalleeDeclAndArgs(cs, locator, argLabelsScratch); SmallBitVector defaultMap = - computeDefaultMap(params, callee, calleeLevel); + computeDefaultMap(params, callee, hasCurriedSelf); // Apply labels to arguments. SmallVector argsWithLabels; @@ -3186,16 +3194,16 @@ performMemberLookup(ConstraintKind constraintKind, DeclName memberName, // (if we have any) will apply to the second level of parameters, with // the member lookup binding the first level. But there are cases where // we can get an unapplied declaration reference back. - unsigned parameterDepth; + bool hasCurriedSelf; if (baseObjTy->is()) { - parameterDepth = 0; + hasCurriedSelf = false; } else if (baseObjTy->is() && decl->isInstanceMember()) { - parameterDepth = 0; + hasCurriedSelf = false; } else { - parameterDepth = 1; + hasCurriedSelf = true; } - return areConservativelyCompatibleArgumentLabels(decl, parameterDepth, + return areConservativelyCompatibleArgumentLabels(decl, hasCurriedSelf, argumentLabels->Labels, argumentLabels->HasTrailingClosure); }; diff --git a/lib/Sema/ConstraintSystem.h b/lib/Sema/ConstraintSystem.h index c9ef8a178c8d2..82bf7f16ad6a6 100644 --- a/lib/Sema/ConstraintSystem.h +++ b/lib/Sema/ConstraintSystem.h @@ -3370,7 +3370,7 @@ matchCallArguments(ConstraintSystem &cs, /// given parameter depth cannot be used with the given value. /// If this cannot be proven, conservatively returns true. bool areConservativelyCompatibleArgumentLabels(ValueDecl *decl, - unsigned parameterDepth, + bool hasCurriedSelf, ArrayRef labels, bool hasTrailingClosure); From a0085e1f29a6ecf10f8ea801f9573e89c3769113 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Fri, 19 Oct 2018 13:37:05 -0700 Subject: [PATCH 3/4] [Diagnostics] NFC: Rename `UncurriedCandidate` -> `OverloadCandidate` --- lib/Sema/CSDiag.cpp | 10 ++++---- lib/Sema/CalleeCandidateInfo.cpp | 19 +++++++------- lib/Sema/CalleeCandidateInfo.h | 44 +++++++++++++++----------------- 3 files changed, 34 insertions(+), 39 deletions(-) diff --git a/lib/Sema/CSDiag.cpp b/lib/Sema/CSDiag.cpp index b3398f27a0b66..806ec169872a8 100644 --- a/lib/Sema/CSDiag.cpp +++ b/lib/Sema/CSDiag.cpp @@ -4146,7 +4146,7 @@ static bool diagnoseRawRepresentableMismatch(CalleeCandidateInfo &CCI, auto arguments = decomposeArgType(argType, argLabels); auto bestMatchKind = RawRepresentableMismatch::NotApplicable; - const UncurriedCandidate *bestMatchCandidate = nullptr; + const OverloadCandidate *bestMatchCandidate = nullptr; KnownProtocolKind bestMatchProtocol; size_t bestMatchIndex; @@ -4341,7 +4341,7 @@ bool FailureDiagnosis::diagnoseSubscriptErrors(SubscriptExpr *SE, auto decomposedBaseType = decomposeArgType(baseType, {Identifier()}); auto decomposedIndexType = decomposeArgType(indexType, argLabels); calleeInfo.filterList( - [&](UncurriedCandidate cand) -> CalleeCandidateInfo::ClosenessResultTy { + [&](OverloadCandidate cand) -> CalleeCandidateInfo::ClosenessResultTy { // Classify how close this match is. Non-subscript decls don't match. auto subscriptDecl = dyn_cast_or_null(cand.getDecl()); if (!subscriptDecl || @@ -4402,7 +4402,7 @@ bool FailureDiagnosis::diagnoseSubscriptErrors(SubscriptExpr *SE, // and more concrete expected type for this subscript decl, in order // to diagnose a better error. if (baseType && indexType->hasUnresolvedType()) { - UncurriedCandidate cand = calleeInfo.candidates[0]; + auto cand = calleeInfo.candidates[0]; auto candType = baseType->getTypeOfMember(CS.DC->getParentModule(), cand.getDecl(), nullptr); if (auto *candFunc = candType->getAs()) { @@ -5125,7 +5125,7 @@ bool FailureDiagnosis::diagnoseSubscriptMisuse(ApplyExpr *callExpr) { auto params = decomposeArgType(CS.getType(argExpr), argLabels); using ClosenessPair = CalleeCandidateInfo::ClosenessResultTy; - candidateInfo.filterList([&](UncurriedCandidate cand) -> ClosenessPair { + candidateInfo.filterList([&](OverloadCandidate cand) -> ClosenessPair { auto candFuncType = cand.getUncurriedFunctionType(); if (!candFuncType) return {CC_GeneralMismatch, {}}; @@ -5443,7 +5443,7 @@ bool FailureDiagnosis::visitApplyExpr(ApplyExpr *callExpr) { if (auto fn = fnType->getAs()) { using Closeness = CalleeCandidateInfo::ClosenessResultTy; - calleeInfo.filterList([&](UncurriedCandidate candidate) -> Closeness { + calleeInfo.filterList([&](OverloadCandidate candidate) -> Closeness { auto resultType = candidate.getResultType(); if (!resultType) return {CC_GeneralMismatch, {}}; diff --git a/lib/Sema/CalleeCandidateInfo.cpp b/lib/Sema/CalleeCandidateInfo.cpp index 234bfb6469b44..9da720fbf4e81 100644 --- a/lib/Sema/CalleeCandidateInfo.cpp +++ b/lib/Sema/CalleeCandidateInfo.cpp @@ -56,8 +56,8 @@ static bool isSubstitutableFor(Type type, ArchetypeType *archetype, return true; } -UncurriedCandidate::UncurriedCandidate(ValueDecl *decl, bool skipCurriedSelf) -: declOrExpr(decl), skipCurriedSelf(skipCurriedSelf), substituted(false) { +OverloadCandidate::OverloadCandidate(ValueDecl *decl, bool skipCurriedSelf) + : declOrExpr(decl), skipCurriedSelf(skipCurriedSelf), substituted(false) { if (auto *PD = dyn_cast(decl)) { if (PD->hasValidSignature()) @@ -89,8 +89,8 @@ UncurriedCandidate::UncurriedCandidate(ValueDecl *decl, bool skipCurriedSelf) } } -ArrayRef UncurriedCandidate::getArgumentLabels( - SmallVectorImpl &scratch) { +ArrayRef +OverloadCandidate::getArgumentLabels(SmallVectorImpl &scratch) { scratch.clear(); if (auto decl = getDecl()) { if (auto func = dyn_cast(decl)) { @@ -136,7 +136,7 @@ ArrayRef UncurriedCandidate::getArgumentLabels( return scratch; } -void UncurriedCandidate::dump() const { +void OverloadCandidate::dump() const { if (auto decl = getDecl()) decl->dumpRef(llvm::errs()); else @@ -309,9 +309,8 @@ static bool findGenericSubstitutions(DeclContext *dc, Type paramType, /// Determine how close an argument list is to an already decomposed argument /// list. If the closeness is a miss by a single argument, then this returns /// information about that failure. -CalleeCandidateInfo::ClosenessResultTy -CalleeCandidateInfo::evaluateCloseness(UncurriedCandidate candidate, - ArrayRef actualArgs) { +CalleeCandidateInfo::ClosenessResultTy CalleeCandidateInfo::evaluateCloseness( + OverloadCandidate candidate, ArrayRef actualArgs) { auto *dc = candidate.getDecl() ? candidate.getDecl()->getInnermostDeclContext() : nullptr; @@ -787,7 +786,7 @@ void CalleeCandidateInfo::collectCalleeCandidates(Expr *fn, void CalleeCandidateInfo::filterListArgs(ArrayRef actualArgs) { // Now that we have the candidate list, figure out what the best matches from // the candidate list are, and remove all the ones that aren't at that level. - filterList([&](UncurriedCandidate candidate) -> ClosenessResultTy { + filterList([&](OverloadCandidate candidate) -> ClosenessResultTy { // If this isn't a function or isn't valid at this uncurry level, treat it // as a general mismatch. if (!candidate.hasParameters()) @@ -801,7 +800,7 @@ void CalleeCandidateInfo::filterContextualMemberList(Expr *argExpr) { // If the argument is not present then we expect members without arguments. if (!argExpr) { - return filterList([&](UncurriedCandidate candidate) -> ClosenessResultTy { + return filterList([&](OverloadCandidate candidate) -> ClosenessResultTy { // If this candidate has no arguments, then we're a match. if (!candidate.hasParameters()) return {CC_ExactMatch, {}}; diff --git a/lib/Sema/CalleeCandidateInfo.h b/lib/Sema/CalleeCandidateInfo.h index d202fe48af028..60b06494df75c 100644 --- a/lib/Sema/CalleeCandidateInfo.h +++ b/lib/Sema/CalleeCandidateInfo.h @@ -45,19 +45,17 @@ namespace swift { CC_GeneralMismatch ///< Something else is wrong. }; - /// This is a candidate for a callee, along with an uncurry level. + /// This is a candidate for a callee. /// - /// The uncurry level specifies how far much of a curried value has already - /// been applied. For example, in a funcdecl of: - /// func f(a:Int)(b:Double) -> Int - /// Uncurry level of 0 indicates that we're looking at the "a" argument, an - /// uncurry level of 1 indicates that we're looking at the "b" argument. + /// `skipCurriedSelf` specifies that function type associated with this + /// candidate might have a curried self parameter which needs to be + /// skipped. /// - /// entityType specifies a specific type to use for this decl/expr that may be - /// more resolved than the concrete type. For example, it may have generic + /// `entityType` specifies a specific type to use for this decl/expr that may + /// be more resolved than the concrete type. For example, it may have generic /// arguments substituted in. /// - struct UncurriedCandidate { + struct OverloadCandidate { PointerUnion declOrExpr; bool skipCurriedSelf; Type entityType; @@ -70,12 +68,12 @@ namespace swift { // // FIXME: Clean this up. bool substituted; - - UncurriedCandidate(ValueDecl *decl, bool skipCurriedSelf); - UncurriedCandidate(Expr *expr, Type type) - : declOrExpr(expr), skipCurriedSelf(false), entityType(type), - substituted(true) {} - + + OverloadCandidate(ValueDecl *decl, bool skipCurriedSelf); + OverloadCandidate(Expr *expr, Type type) + : declOrExpr(expr), skipCurriedSelf(false), entityType(type), + substituted(true) {} + ValueDecl *getDecl() const { return declOrExpr.dyn_cast(); } @@ -150,8 +148,8 @@ namespace swift { bool hasTrailingClosure; /// This is the list of candidates identified. - SmallVector candidates; - + SmallVector candidates; + /// This tracks how close the candidates are, after filtering. CandidateCloseness closeness = CC_GeneralMismatch; @@ -196,25 +194,23 @@ namespace swift { using ClosenessResultTy = std::pair; using ClosenessPredicate = - const std::function &; + const std::function &; /// After the candidate list is formed, it can be filtered down to discard /// obviously mismatching candidates and compute a "closeness" for the /// resultant set. ClosenessResultTy - evaluateCloseness(UncurriedCandidate candidate, + evaluateCloseness(OverloadCandidate candidate, ArrayRef actualArgs); - + void filterListArgs(ArrayRef actualArgs); void filterList(ClosenessPredicate predicate); void filterContextualMemberList(Expr *argExpr); bool empty() const { return candidates.empty(); } unsigned size() const { return candidates.size(); } - UncurriedCandidate operator[](unsigned i) const { - return candidates[i]; - } - + OverloadCandidate operator[](unsigned i) const { return candidates[i]; } + /// Given a set of parameter lists from an overload group, and a list of /// arguments, emit a diagnostic indicating any partially matching /// overloads. From c219af099ec7c58680d6f5c9aeb940befa046772 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Fri, 19 Oct 2018 14:56:06 -0700 Subject: [PATCH 4/4] [Diagnostics] NFC: Rename `OverloadCandidate::getUncurried{Function}Type` -> `OverloadCandidate::get{Function}Type` --- lib/Sema/CSDiag.cpp | 6 +++--- lib/Sema/CalleeCandidateInfo.cpp | 4 ++-- lib/Sema/CalleeCandidateInfo.h | 20 +++++++++----------- 3 files changed, 14 insertions(+), 16 deletions(-) diff --git a/lib/Sema/CSDiag.cpp b/lib/Sema/CSDiag.cpp index 806ec169872a8..3c62911faa9c6 100644 --- a/lib/Sema/CSDiag.cpp +++ b/lib/Sema/CSDiag.cpp @@ -5126,7 +5126,7 @@ bool FailureDiagnosis::diagnoseSubscriptMisuse(ApplyExpr *callExpr) { using ClosenessPair = CalleeCandidateInfo::ClosenessResultTy; candidateInfo.filterList([&](OverloadCandidate cand) -> ClosenessPair { - auto candFuncType = cand.getUncurriedFunctionType(); + auto candFuncType = cand.getFunctionType(); if (!candFuncType) return {CC_GeneralMismatch, {}}; @@ -5679,7 +5679,7 @@ bool FailureDiagnosis::visitApplyExpr(ApplyExpr *callExpr) { return false; auto candidate = calleeInfo[0]; - auto *fnType = candidate.getUncurriedFunctionType(); + auto *fnType = candidate.getFunctionType(); if (!fnType) return false; @@ -7228,7 +7228,7 @@ bool FailureDiagnosis::visitUnresolvedMemberExpr(UnresolvedMemberExpr *E) { // expected result type. auto resultTy = candidateInfo[0].getResultType(); if (!resultTy) - resultTy = candidateInfo[0].getUncurriedType(); + resultTy = candidateInfo[0].getType(); if (resultTy && !CS.getContextualType()->is() && !CS.TC.isConvertibleTo(resultTy, CS.getContextualType(), CS.DC)) { diff --git a/lib/Sema/CalleeCandidateInfo.cpp b/lib/Sema/CalleeCandidateInfo.cpp index 9da720fbf4e81..5581f94163a64 100644 --- a/lib/Sema/CalleeCandidateInfo.cpp +++ b/lib/Sema/CalleeCandidateInfo.cpp @@ -143,8 +143,8 @@ void OverloadCandidate::dump() const { llvm::errs() << "<>"; llvm::errs() << " - ignore curried self = " << (skipCurriedSelf ? "yes" : "no"); - - if (auto FT = getUncurriedFunctionType()) + + if (auto FT = getFunctionType()) llvm::errs() << " - type: " << Type(FT) << "\n"; else llvm::errs() << " - type <>: " << entityType << "\n"; diff --git a/lib/Sema/CalleeCandidateInfo.h b/lib/Sema/CalleeCandidateInfo.h index 60b06494df75c..174a0d548c3cb 100644 --- a/lib/Sema/CalleeCandidateInfo.h +++ b/lib/Sema/CalleeCandidateInfo.h @@ -81,8 +81,8 @@ namespace swift { Expr *getExpr() const { return declOrExpr.dyn_cast(); } - - Type getUncurriedType() const { + + Type getType() const { // Start with the known type of the decl. auto type = entityType; if (skipCurriedSelf) { @@ -92,13 +92,13 @@ namespace swift { } return type; } - - AnyFunctionType *getUncurriedFunctionType() const { - if (auto type = getUncurriedType()) + + AnyFunctionType *getFunctionType() const { + if (auto type = getType()) return type->getAs(); return nullptr; } - + /// Given a function candidate with an uncurry level, return the parameter /// type at the specified uncurry level. If there is an error getting to /// the specified input, this returns a null Type. @@ -110,20 +110,18 @@ namespace swift { return FunctionType::composeInput(ctx, params, false); } - bool hasParameters() const { - return getUncurriedFunctionType(); - } + bool hasParameters() const { return getFunctionType(); } ArrayRef getParameters() const { assert(hasParameters()); - return getUncurriedFunctionType()->getParams(); + return getFunctionType()->getParams(); } /// Given a function candidate with an uncurry level, return the parameter /// type at the specified uncurry level. If there is an error getting to /// the specified input, this returns a null Type. Type getResultType() const { - if (auto *funcTy = getUncurriedFunctionType()) + if (auto *funcTy = getFunctionType()) return funcTy->getResult(); return Type(); }