//===--- CallerCandidateInfo.h - Failure Diagnosis Info -------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2017 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 represents an analyzed function pointer to determine the // candidates that could be called, or the one concrete decl that will be // called if not ambiguous. // //===----------------------------------------------------------------------===// #ifndef SWIFT_SEMA_CALLEECANDIDATEINFO_H #define SWIFT_SEMA_CALLEECANDIDATEINFO_H namespace swift { using namespace constraints; /// Each match in an ApplyExpr is evaluated for how close of a match it is. /// The result is captured in this enum value, where the earlier entries are /// most specific. enum CandidateCloseness { CC_ExactMatch, ///< This is a perfect match for the arguments. CC_Unavailable, ///< Marked unavailable with @available. CC_Inaccessible, ///< Not accessible from the current context. CC_NonLValueInOut, ///< First arg is inout but no lvalue present. CC_SelfMismatch, ///< Self argument mismatches. CC_OneArgumentNearMismatch, ///< All arguments except one match, near miss. CC_OneArgumentMismatch, ///< All arguments except one match. CC_OneGenericArgumentNearMismatch, ///< All arguments except one match, guessing generic binding, near miss. CC_OneGenericArgumentMismatch, ///< All arguments except one match, guessing generic binding. CC_ArgumentNearMismatch, ///< Argument list mismatch, near miss. CC_ArgumentMismatch, ///< Argument list mismatch. CC_GenericNonsubstitutableMismatch, ///< Arguments match each other, but generic binding not substitutable. CC_ArgumentLabelMismatch, ///< Argument label mismatch. CC_ArgumentCountMismatch, ///< This candidate has wrong # arguments. CC_GeneralMismatch ///< Something else is wrong. }; /// This is a candidate for a callee. /// /// `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 /// arguments substituted in. /// struct OverloadCandidate { PointerUnion declOrExpr; bool skipCurriedSelf; Type entityType; // If true, entityType is written in terms of caller archetypes, // with any unbound generic arguments remaining as interface // type parameters in terms of the callee generic signature. // // If false, entityType is written in terms of callee archetypes. // // FIXME: Clean this up. bool substituted; 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(); } Expr *getExpr() const { return declOrExpr.dyn_cast(); } Type getType() const { // Start with the known type of the decl. auto type = entityType; if (skipCurriedSelf) { auto funcTy = type->getAs(); if (!funcTy) return Type(); type = funcTy->getResult(); } return type; } 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. Type getArgumentType(ASTContext &ctx) const { if (!hasParameters()) return Type(); auto params = getParameters(); return FunctionType::composeInput(ctx, params, false); } bool hasParameters() const { return getFunctionType(); } ArrayRef getParameters() const { assert(hasParameters()); 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 = getFunctionType()) return funcTy->getResult(); return Type(); } /// Retrieve the argument labels that should be used to invoke this /// candidate. ArrayRef getArgumentLabels(SmallVectorImpl &scratch); void dump() const LLVM_ATTRIBUTE_USED; }; class CalleeCandidateInfo { public: ConstraintSystem &CS; /// This is the name of the callee as extracted from the call expression. /// This can be empty in cases like calls to closure exprs. std::string declName; /// True if the call site for this callee syntactically has a trailing /// closure specified. bool hasTrailingClosure; /// This is the list of candidates identified. SmallVector candidates; /// This tracks how close the candidates are, after filtering. CandidateCloseness closeness = CC_GeneralMismatch; /// When we have a candidate that differs by a single argument mismatch, we /// keep track of which argument passed to the call is failed, and what the /// expected type is. If the candidate set disagrees, or if there is more /// than a single argument mismatch, then this is "{ -1, Type() }". struct FailedArgumentInfo { int argumentNumber = -1; ///< Arg # at the call site. Type parameterType = Type(); ///< Expected type at the decl site. DeclContext *declContext = nullptr; ///< Context at the candidate declaration. bool isValid() const { return argumentNumber != -1; } bool operator!=(const FailedArgumentInfo &other) { if (argumentNumber != other.argumentNumber) return true; if (declContext != other.declContext) return true; // parameterType can be null, and isEqual doesn't handle this. if (!parameterType || !other.parameterType) return parameterType.getPointer() != other.parameterType.getPointer(); return !parameterType->isEqual(other.parameterType); } }; FailedArgumentInfo failedArgument = FailedArgumentInfo(); /// Analyze a function expr and break it into a candidate set. On failure, /// this leaves the candidate list empty. CalleeCandidateInfo(Expr *Fn, bool hasTrailingClosure, ConstraintSystem &CS) : CS(CS), hasTrailingClosure(hasTrailingClosure) { collectCalleeCandidates(Fn, /*implicitDotSyntax=*/false); } CalleeCandidateInfo(Type baseType, ArrayRef candidates, bool hasTrailingClosure, ConstraintSystem &CS, bool selfAlreadyApplied = true); ~CalleeCandidateInfo() = default; CalleeCandidateInfo(const CalleeCandidateInfo &CCI) = default; CalleeCandidateInfo &operator=(const CalleeCandidateInfo &CCI); CalleeCandidateInfo(CalleeCandidateInfo &&CCI) = delete; CalleeCandidateInfo &operator=(CalleeCandidateInfo &&CCI) = delete; using ClosenessResultTy = std::pair; using ClosenessPredicate = 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(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(); } 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. void suggestPotentialOverloads(SourceLoc loc, bool isResult = false); /// If the candidate set has been narrowed to a single parameter or single /// archetype that has argument type errors, diagnose that error and /// return true. bool diagnoseGenericParameterErrors(Expr *badArgExpr); /// Emit a diagnostic and return true if this is an error condition we can /// handle uniformly. This should be called after filtering the candidate /// list. bool diagnoseSimpleErrors(const Expr *E); void dump() const LLVM_ATTRIBUTE_USED; private: void collectCalleeCandidates(Expr *fnExpr, bool implicitDotSyntax); }; } // end swift namespace #endif /* SWIFT_SEMA_CALLEECANDIDATEINFO_H */