mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
236 lines
9.4 KiB
C++
236 lines
9.4 KiB
C++
//===--- 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<ValueDecl *, Expr*> 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<ValueDecl*>();
|
|
}
|
|
|
|
Expr *getExpr() const {
|
|
return declOrExpr.dyn_cast<Expr*>();
|
|
}
|
|
|
|
Type getType() const {
|
|
// Start with the known type of the decl.
|
|
auto type = entityType;
|
|
if (skipCurriedSelf) {
|
|
auto funcTy = type->getAs<AnyFunctionType>();
|
|
if (!funcTy) return Type();
|
|
type = funcTy->getResult();
|
|
}
|
|
return type;
|
|
}
|
|
|
|
AnyFunctionType *getFunctionType() const {
|
|
if (auto type = getType())
|
|
return type->getAs<AnyFunctionType>();
|
|
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<AnyFunctionType::Param> 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<Identifier> getArgumentLabels(SmallVectorImpl<Identifier> &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<OverloadCandidate, 4> 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<OverloadChoice> 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<CandidateCloseness, FailedArgumentInfo>;
|
|
using ClosenessPredicate =
|
|
const std::function<ClosenessResultTy(OverloadCandidate)> &;
|
|
|
|
/// 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<AnyFunctionType::Param> actualArgs);
|
|
|
|
void filterListArgs(ArrayRef<AnyFunctionType::Param> 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 */
|