[ConstraintSystem] Move FailureDiagnostic::getFunctionArgApplyInfo

into `ConstraintSystem`.
This commit is contained in:
Holly Borla
2019-12-06 15:43:39 -08:00
parent ff53718c6b
commit 1e013a02cf
5 changed files with 311 additions and 311 deletions

View File

@@ -131,165 +131,6 @@ FailureDiagnostic::getChoiceFor(ConstraintLocator *locator) const {
return getOverloadChoiceIfAvailable(cs.getCalleeLocator(locator));
}
static Type resolveInterfaceType(ConstraintSystem &cs, Type type) {
auto resolvedType = type.transform([&](Type type) -> Type {
if (auto *tvt = type->getAs<TypeVariableType>()) {
// If this type variable is for a generic parameter, return that.
if (auto *gp = tvt->getImpl().getGenericParameter())
return gp;
// Otherwise resolve its fixed type, mapped out of context.
if (auto fixed = cs.getFixedType(tvt))
return resolveInterfaceType(cs, fixed->mapTypeOutOfContext());
return cs.getRepresentative(tvt);
}
if (auto *dmt = type->getAs<DependentMemberType>()) {
// For a dependent member, first resolve the base.
auto newBase = resolveInterfaceType(cs, dmt->getBase());
// Then reconstruct using its associated type.
assert(dmt->getAssocType());
return DependentMemberType::get(newBase, dmt->getAssocType());
}
return type;
});
assert(!resolvedType->hasArchetype());
return resolvedType;
}
/// Given an apply expr, returns true if it is expected to have a direct callee
/// overload, resolvable using `getChoiceFor`. Otherwise, returns false.
static bool shouldHaveDirectCalleeOverload(const CallExpr *callExpr) {
auto *fnExpr = callExpr->getDirectCallee();
// An apply of an apply/subscript doesn't have a direct callee.
if (isa<ApplyExpr>(fnExpr) || isa<SubscriptExpr>(fnExpr))
return false;
// Applies of closures don't have callee overloads.
if (isa<ClosureExpr>(fnExpr))
return false;
// No direct callee for a try!/try?.
if (isa<ForceTryExpr>(fnExpr) || isa<OptionalTryExpr>(fnExpr))
return false;
// If we have an intermediate cast, there's no direct callee.
if (isa<ExplicitCastExpr>(fnExpr))
return false;
// No direct callee for an if expr.
if (isa<IfExpr>(fnExpr))
return false;
// Assume that anything else would have a direct callee.
return true;
}
Optional<FunctionArgApplyInfo>
FailureDiagnostic::getFunctionArgApplyInfo(ConstraintSystem &cs,
ConstraintLocator *locator) {
auto *anchor = locator->getAnchor();
auto path = locator->getPath();
// Look for the apply-arg-to-param element in the locator's path. We may
// have to look through other elements that are generated from an argument
// conversion such as GenericArgument for an optional-to-optional conversion,
// and OptionalPayload for a value-to-optional conversion.
auto iter = path.rbegin();
auto applyArgElt = locator->findLast<LocatorPathElt::ApplyArgToParam>(iter);
if (!applyArgElt)
return None;
auto nextIter = iter + 1;
assert(!locator->findLast<LocatorPathElt::ApplyArgToParam>(nextIter) &&
"Multiple ApplyArgToParam components?");
// Form a new locator that ends at the apply-arg-to-param element, and
// simplify it to get the full argument expression.
auto argPath = path.drop_back(iter - path.rbegin());
auto *argLocator = cs.getConstraintLocator(
anchor, argPath, ConstraintLocator::getSummaryFlagsForPath(argPath));
auto *argExpr = simplifyLocatorToAnchor(argLocator);
// If we were unable to simplify down to the argument expression, we don't
// know what this is.
if (!argExpr)
return None;
Optional<OverloadChoice> choice;
Type rawFnType;
auto *calleeLocator = cs.getCalleeLocator(argLocator);
if (auto overload = cs.findSelectedOverloadFor(calleeLocator)) {
// If we have resolved an overload for the callee, then use that to get the
// function type and callee.
choice = overload->choice;
rawFnType = overload->openedType;
} else {
// If we didn't resolve an overload for the callee, we should be dealing
// with a call of an arbitrary function expr.
if (auto *call = dyn_cast<CallExpr>(anchor)) {
assert(!shouldHaveDirectCalleeOverload(call) &&
"Should we have resolved a callee for this?");
rawFnType = cs.getType(call->getFn());
} else {
// FIXME: ArgumentMismatchFailure is currently used from CSDiag, meaning
// we can end up a BinaryExpr here with an unresolved callee. It should be
// possible to remove this once we've gotten rid of the old CSDiag logic
// and just assert that we have a CallExpr.
auto *apply = cast<ApplyExpr>(anchor);
rawFnType = cs.getType(apply->getFn());
}
}
// Try to resolve the function type by loading lvalues and looking through
// optional types, which can occur for expressions like `fn?(5)`.
auto *fnType = cs.simplifyType(rawFnType)
->getRValueType()
->lookThroughAllOptionalTypes()
->getAs<FunctionType>();
if (!fnType)
return None;
// Resolve the interface type for the function. Note that this may not be a
// function type, for example it could be a generic parameter.
Type fnInterfaceType;
auto *callee = choice ? choice->getDeclOrNull() : nullptr;
if (callee && callee->hasInterfaceType()) {
// If we have a callee with an interface type, we can use it. This is
// preferable to resolveInterfaceType, as this will allow us to get a
// GenericFunctionType for generic decls.
//
// Note that it's possible to find a callee without an interface type. This
// can happen for example with closure parameters, where the interface type
// isn't set until the solution is applied. In that case, use
// resolveInterfaceType.
fnInterfaceType = callee->getInterfaceType();
// Strip off the curried self parameter if necessary.
if (hasAppliedSelf(cs, *choice))
fnInterfaceType = fnInterfaceType->castTo<AnyFunctionType>()->getResult();
if (auto *fn = fnInterfaceType->getAs<AnyFunctionType>()) {
assert(fn->getNumParams() == fnType->getNumParams() &&
"Parameter mismatch?");
(void)fn;
}
} else {
fnInterfaceType = resolveInterfaceType(cs, rawFnType);
}
auto argIdx = applyArgElt->getArgIdx();
auto paramIdx = applyArgElt->getParamIdx();
return FunctionArgApplyInfo(cs, argExpr, argIdx,
cs.simplifyType(cs.getType(argExpr)),
paramIdx, fnInterfaceType, fnType, callee);
}
Type FailureDiagnostic::restoreGenericParameters(
Type type,
llvm::function_ref<void(GenericTypeParamType *, Type)> substitution) {
@@ -930,7 +771,7 @@ bool NoEscapeFuncToTypeConversionFailure::diagnoseParameterUse() const {
// as an argument to another function which accepts @escaping
// function at that position.
auto &cs = getConstraintSystem();
if (auto argApplyInfo = getFunctionArgApplyInfo(cs, getLocator())) {
if (auto argApplyInfo = cs.getFunctionArgApplyInfo(getLocator())) {
auto paramInterfaceTy = argApplyInfo->getParamInterfaceType();
if (paramInterfaceTy->isTypeParameter()) {
auto diagnoseGenericParamFailure = [&](GenericTypeParamDecl *decl) {
@@ -1139,7 +980,7 @@ void MissingOptionalUnwrapFailure::offerDefaultValueUnwrapFixIt(
return;
auto &cs = getConstraintSystem();
if (auto argApplyInfo = getFunctionArgApplyInfo(cs, getLocator()))
if (auto argApplyInfo = cs.getFunctionArgApplyInfo(getLocator()))
if (argApplyInfo->getParameterFlags().isInOut())
return;
@@ -3802,7 +3643,7 @@ bool MissingArgumentsFailure::diagnoseAsError() {
// foo(bar) // `() -> Void` vs. `(Int) -> Void`
// ```
if (locator->isLastElement<LocatorPathElt::ApplyArgToParam>()) {
auto info = *getFunctionArgApplyInfo(cs, locator);
auto info = *(cs.getFunctionArgApplyInfo(locator));
auto *argExpr = info.getArgExpr();
emitDiagnostic(argExpr->getLoc(), diag::cannot_convert_argument_value,
@@ -4018,7 +3859,7 @@ bool MissingArgumentsFailure::diagnoseClosure(ClosureExpr *closure) {
auto *locator = getLocator();
if (locator->isForContextualType()) {
funcType = cs.getContextualType()->getAs<FunctionType>();
} else if (auto info = getFunctionArgApplyInfo(cs, locator)) {
} else if (auto info = cs.getFunctionArgApplyInfo(locator)) {
funcType = info->getParamType()->getAs<FunctionType>();
} else if (locator->isLastElement<LocatorPathElt::ClosureResult>()) {
// Based on the locator we know this this is something like this:
@@ -4732,7 +4573,7 @@ SourceLoc InvalidUseOfAddressOf::getLoc() const {
bool InvalidUseOfAddressOf::diagnoseAsError() {
auto &cs = getConstraintSystem();
if (auto argApplyInfo = getFunctionArgApplyInfo(cs, getLocator())) {
if (auto argApplyInfo = cs.getFunctionArgApplyInfo(getLocator())) {
if (!argApplyInfo->getParameterFlags().isInOut()) {
auto anchor = getAnchor();
emitDiagnostic(anchor->getLoc(), diag::extra_address_of, getToType())
@@ -5259,7 +5100,7 @@ bool InOutConversionFailure::diagnoseAsError() {
if (!path.empty() &&
path.back().getKind() == ConstraintLocator::FunctionArgument) {
if (auto argApplyInfo = getFunctionArgApplyInfo(cs, locator)) {
if (auto argApplyInfo = cs.getFunctionArgApplyInfo(locator)) {
emitDiagnostic(anchor->getLoc(), diag::cannot_convert_argument_value,
argApplyInfo->getArgType(), argApplyInfo->getParamType());
} else {

View File

@@ -91,13 +91,6 @@ public:
Type getType(Expr *expr, bool wantRValue = true) const;
Type getType(const TypeLoc &loc, bool wantRValue = true) const;
/// For a given locator describing a function argument conversion, or a
/// constraint within an argument conversion, returns information about the
/// application of the argument to its parameter. If the locator is not
/// for an argument conversion, returns \c None.
static Optional<FunctionArgApplyInfo>
getFunctionArgApplyInfo(ConstraintSystem &cs, ConstraintLocator *locator);
/// Resolve type variables present in the raw type, if any.
Type resolveType(Type rawType, bool reconstituteSugar = false,
bool wantRValue = true) const {
@@ -191,142 +184,6 @@ private:
std::pair<Expr *, bool> computeAnchor() const;
};
/// Provides information about the application of a function argument to a
/// parameter.
class FunctionArgApplyInfo {
ConstraintSystem &CS;
Expr *ArgExpr;
unsigned ArgIdx;
Type ArgType;
unsigned ParamIdx;
Type FnInterfaceType;
FunctionType *FnType;
const ValueDecl *Callee;
public:
FunctionArgApplyInfo(ConstraintSystem &cs, Expr *argExpr, unsigned argIdx,
Type argType, unsigned paramIdx, Type fnInterfaceType,
FunctionType *fnType, const ValueDecl *callee)
: CS(cs), ArgExpr(argExpr), ArgIdx(argIdx), ArgType(argType),
ParamIdx(paramIdx), FnInterfaceType(fnInterfaceType), FnType(fnType),
Callee(callee) {}
/// \returns The argument being applied.
Expr *getArgExpr() const { return ArgExpr; }
/// \returns The position of the argument, starting at 1.
unsigned getArgPosition() const { return ArgIdx + 1; }
/// \returns The position of the parameter, starting at 1.
unsigned getParamPosition() const { return ParamIdx + 1; }
/// \returns The type of the argument being applied, including any generic
/// substitutions.
///
/// \param withSpecifier Whether to keep the inout or @lvalue specifier of
/// the argument, if any.
Type getArgType(bool withSpecifier = false) const {
return withSpecifier ? ArgType : ArgType->getWithoutSpecifierType();
}
/// \returns The label for the argument being applied.
Identifier getArgLabel() const {
auto *parent = CS.getParentExpr(ArgExpr);
if (auto *te = dyn_cast<TupleExpr>(parent))
return te->getElementName(ArgIdx);
assert(isa<ParenExpr>(parent));
return Identifier();
}
/// \returns A textual description of the argument suitable for diagnostics.
/// For an argument with an unambiguous label, this will the label. Otherwise
/// it will be its position in the argument list.
StringRef getArgDescription(SmallVectorImpl<char> &scratch) const {
llvm::raw_svector_ostream stream(scratch);
// Use the argument label only if it's unique within the argument list.
auto argLabel = getArgLabel();
auto useArgLabel = [&]() -> bool {
if (argLabel.empty())
return false;
if (auto *te = dyn_cast<TupleExpr>(CS.getParentExpr(ArgExpr)))
return llvm::count(te->getElementNames(), argLabel) == 1;
return false;
};
if (useArgLabel()) {
stream << "'";
stream << argLabel;
stream << "'";
} else {
stream << "#";
stream << getArgPosition();
}
return StringRef(scratch.data(), scratch.size());
}
/// \returns The interface type for the function being applied. Note that this
/// may not a function type, for example it could be a generic parameter.
Type getFnInterfaceType() const { return FnInterfaceType; }
/// \returns The function type being applied, including any generic
/// substitutions.
FunctionType *getFnType() const { return FnType; }
/// \returns The callee for the application.
const ValueDecl *getCallee() const { return Callee; }
private:
Type getParamTypeImpl(AnyFunctionType *fnTy,
bool lookThroughAutoclosure) const {
auto param = fnTy->getParams()[ParamIdx];
auto paramTy = param.getPlainType();
if (lookThroughAutoclosure && param.isAutoClosure())
paramTy = paramTy->castTo<FunctionType>()->getResult();
return paramTy;
}
public:
/// \returns The type of the parameter which the argument is being applied to,
/// including any generic substitutions.
///
/// \param lookThroughAutoclosure Whether an @autoclosure () -> T parameter
/// should be treated as being of type T.
Type getParamType(bool lookThroughAutoclosure = true) const {
return getParamTypeImpl(FnType, lookThroughAutoclosure);
}
/// \returns The interface type of the parameter which the argument is being
/// applied to.
///
/// \param lookThroughAutoclosure Whether an @autoclosure () -> T parameter
/// should be treated as being of type T.
Type getParamInterfaceType(bool lookThroughAutoclosure = true) const {
auto interfaceFnTy = FnInterfaceType->getAs<AnyFunctionType>();
if (!interfaceFnTy) {
// If the interface type isn't a function, then just return the resolved
// parameter type.
return getParamType(lookThroughAutoclosure)->mapTypeOutOfContext();
}
return getParamTypeImpl(interfaceFnTy, lookThroughAutoclosure);
}
/// \returns The flags of the parameter which the argument is being applied
/// to.
ParameterTypeFlags getParameterFlags() const {
return FnType->getParams()[ParamIdx].getParameterFlags();
}
ParameterTypeFlags getParameterFlagsAtIndex(unsigned idx) const {
return FnType->getParams()[idx].getParameterFlags();
}
};
/// Base class for all of the diagnostics related to generic requirement
/// failures, provides common information like failed requirement,
/// declaration where such requirement comes from, etc.
@@ -1816,7 +1673,7 @@ public:
ArgumentMismatchFailure(ConstraintSystem &cs, Type argType,
Type paramType, ConstraintLocator *locator)
: ContextualFailure(cs, argType, paramType, locator),
Info(getFunctionArgApplyInfo(cs, getLocator())) {}
Info(cs.getFunctionArgApplyInfo(getLocator())) {}
bool diagnoseAsError() override;
bool diagnoseAsNote() override;

View File

@@ -272,8 +272,7 @@ bool AllowTupleTypeMismatch::coalesceAndDiagnose(
return false;
fromType = cs.getType(tupleExpr);
toType = contextualType;
} else if (auto argApplyInfo =
FailureDiagnostic::getFunctionArgApplyInfo(cs, locator)) {
} else if (auto argApplyInfo = cs.getFunctionArgApplyInfo(locator)) {
purpose = CTP_CallArgument;
fromType = argApplyInfo->getArgType();
toType = argApplyInfo->getParamType();

View File

@@ -3377,6 +3377,164 @@ ConstraintSystem::getArgumentInfo(ConstraintLocator *locator) {
return None;
}
/// Given an apply expr, returns true if it is expected to have a direct callee
/// overload, resolvable using `getChoiceFor`. Otherwise, returns false.
static bool shouldHaveDirectCalleeOverload(const CallExpr *callExpr) {
auto *fnExpr = callExpr->getDirectCallee();
// An apply of an apply/subscript doesn't have a direct callee.
if (isa<ApplyExpr>(fnExpr) || isa<SubscriptExpr>(fnExpr))
return false;
// Applies of closures don't have callee overloads.
if (isa<ClosureExpr>(fnExpr))
return false;
// No direct callee for a try!/try?.
if (isa<ForceTryExpr>(fnExpr) || isa<OptionalTryExpr>(fnExpr))
return false;
// If we have an intermediate cast, there's no direct callee.
if (isa<ExplicitCastExpr>(fnExpr))
return false;
// No direct callee for an if expr.
if (isa<IfExpr>(fnExpr))
return false;
// Assume that anything else would have a direct callee.
return true;
}
Type ConstraintSystem::resolveInterfaceType(Type type) const {
auto resolvedType = type.transform([&](Type type) -> Type {
if (auto *tvt = type->getAs<TypeVariableType>()) {
// If this type variable is for a generic parameter, return that.
if (auto *gp = tvt->getImpl().getGenericParameter())
return gp;
// Otherwise resolve its fixed type, mapped out of context.
if (auto fixed = getFixedType(tvt))
return resolveInterfaceType(fixed->mapTypeOutOfContext());
return getRepresentative(tvt);
}
if (auto *dmt = type->getAs<DependentMemberType>()) {
// For a dependent member, first resolve the base.
auto newBase = resolveInterfaceType(dmt->getBase());
// Then reconstruct using its associated type.
assert(dmt->getAssocType());
return DependentMemberType::get(newBase, dmt->getAssocType());
}
return type;
});
assert(!resolvedType->hasArchetype());
return resolvedType;
}
Optional<FunctionArgApplyInfo>
ConstraintSystem::getFunctionArgApplyInfo(ConstraintLocator *locator) {
auto *anchor = locator->getAnchor();
auto path = locator->getPath();
// Look for the apply-arg-to-param element in the locator's path. We may
// have to look through other elements that are generated from an argument
// conversion such as GenericArgument for an optional-to-optional conversion,
// and OptionalPayload for a value-to-optional conversion.
auto iter = path.rbegin();
auto applyArgElt = locator->findLast<LocatorPathElt::ApplyArgToParam>(iter);
if (!applyArgElt)
return None;
auto nextIter = iter + 1;
assert(!locator->findLast<LocatorPathElt::ApplyArgToParam>(nextIter) &&
"Multiple ApplyArgToParam components?");
// Form a new locator that ends at the apply-arg-to-param element, and
// simplify it to get the full argument expression.
auto argPath = path.drop_back(iter - path.rbegin());
auto *argLocator = getConstraintLocator(
anchor, argPath, ConstraintLocator::getSummaryFlagsForPath(argPath));
auto *argExpr = simplifyLocatorToAnchor(argLocator);
// If we were unable to simplify down to the argument expression, we don't
// know what this is.
if (!argExpr)
return None;
Optional<OverloadChoice> choice;
Type rawFnType;
auto *calleeLocator = getCalleeLocator(argLocator);
if (auto overload = findSelectedOverloadFor(calleeLocator)) {
// If we have resolved an overload for the callee, then use that to get the
// function type and callee.
choice = overload->choice;
rawFnType = overload->openedType;
} else {
// If we didn't resolve an overload for the callee, we should be dealing
// with a call of an arbitrary function expr.
if (auto *call = dyn_cast<CallExpr>(anchor)) {
assert(!shouldHaveDirectCalleeOverload(call) &&
"Should we have resolved a callee for this?");
rawFnType = getType(call->getFn());
} else {
// FIXME: ArgumentMismatchFailure is currently used from CSDiag, meaning
// we can end up a BinaryExpr here with an unresolved callee. It should be
// possible to remove this once we've gotten rid of the old CSDiag logic
// and just assert that we have a CallExpr.
auto *apply = cast<ApplyExpr>(anchor);
rawFnType = getType(apply->getFn());
}
}
// Try to resolve the function type by loading lvalues and looking through
// optional types, which can occur for expressions like `fn?(5)`.
auto *fnType = simplifyType(rawFnType)
->getRValueType()
->lookThroughAllOptionalTypes()
->getAs<FunctionType>();
if (!fnType)
return None;
// Resolve the interface type for the function. Note that this may not be a
// function type, for example it could be a generic parameter.
Type fnInterfaceType;
auto *callee = choice ? choice->getDeclOrNull() : nullptr;
if (callee && callee->hasInterfaceType()) {
// If we have a callee with an interface type, we can use it. This is
// preferable to resolveInterfaceType, as this will allow us to get a
// GenericFunctionType for generic decls.
//
// Note that it's possible to find a callee without an interface type. This
// can happen for example with closure parameters, where the interface type
// isn't set until the solution is applied. In that case, use
// resolveInterfaceType.
fnInterfaceType = callee->getInterfaceType();
// Strip off the curried self parameter if necessary.
if (hasAppliedSelf(*this, *choice))
fnInterfaceType = fnInterfaceType->castTo<AnyFunctionType>()->getResult();
if (auto *fn = fnInterfaceType->getAs<AnyFunctionType>()) {
assert(fn->getNumParams() == fnType->getNumParams() &&
"Parameter mismatch?");
(void)fn;
}
} else {
fnInterfaceType = resolveInterfaceType(rawFnType);
}
auto argIdx = applyArgElt->getArgIdx();
auto paramIdx = applyArgElt->getParamIdx();
return FunctionArgApplyInfo(getParentExpr(argExpr), argExpr, argIdx,
simplifyType(getType(argExpr)),
paramIdx, fnInterfaceType, fnType, callee);
}
bool constraints::isKnownKeyPathType(Type type) {
if (auto *BGT = type->getAs<BoundGenericType>())
return isKnownKeyPathDecl(type->getASTContext(), BGT->getDecl());

View File

@@ -486,6 +486,141 @@ struct SelectedOverload {
Type boundType;
};
/// Provides information about the application of a function argument to a
/// parameter.
class FunctionArgApplyInfo {
Expr *ArgListExpr;
Expr *ArgExpr;
unsigned ArgIdx;
Type ArgType;
unsigned ParamIdx;
Type FnInterfaceType;
FunctionType *FnType;
const ValueDecl *Callee;
public:
FunctionArgApplyInfo(Expr *argListExpr, Expr *argExpr, unsigned argIdx,
Type argType, unsigned paramIdx, Type fnInterfaceType,
FunctionType *fnType, const ValueDecl *callee)
: ArgListExpr(argListExpr), ArgExpr(argExpr), ArgIdx(argIdx),
ArgType(argType), ParamIdx(paramIdx), FnInterfaceType(fnInterfaceType),
FnType(fnType), Callee(callee) {}
/// \returns The argument being applied.
Expr *getArgExpr() const { return ArgExpr; }
/// \returns The position of the argument, starting at 1.
unsigned getArgPosition() const { return ArgIdx + 1; }
/// \returns The position of the parameter, starting at 1.
unsigned getParamPosition() const { return ParamIdx + 1; }
/// \returns The type of the argument being applied, including any generic
/// substitutions.
///
/// \param withSpecifier Whether to keep the inout or @lvalue specifier of
/// the argument, if any.
Type getArgType(bool withSpecifier = false) const {
return withSpecifier ? ArgType : ArgType->getWithoutSpecifierType();
}
/// \returns The label for the argument being applied.
Identifier getArgLabel() const {
if (auto *te = dyn_cast<TupleExpr>(ArgListExpr))
return te->getElementName(ArgIdx);
assert(isa<ParenExpr>(ArgListExpr));
return Identifier();
}
/// \returns A textual description of the argument suitable for diagnostics.
/// For an argument with an unambiguous label, this will the label. Otherwise
/// it will be its position in the argument list.
StringRef getArgDescription(SmallVectorImpl<char> &scratch) const {
llvm::raw_svector_ostream stream(scratch);
// Use the argument label only if it's unique within the argument list.
auto argLabel = getArgLabel();
auto useArgLabel = [&]() -> bool {
if (argLabel.empty())
return false;
if (auto *te = dyn_cast<TupleExpr>(ArgListExpr))
return llvm::count(te->getElementNames(), argLabel) == 1;
return false;
};
if (useArgLabel()) {
stream << "'";
stream << argLabel;
stream << "'";
} else {
stream << "#";
stream << getArgPosition();
}
return StringRef(scratch.data(), scratch.size());
}
/// \returns The interface type for the function being applied. Note that this
/// may not a function type, for example it could be a generic parameter.
Type getFnInterfaceType() const { return FnInterfaceType; }
/// \returns The function type being applied, including any generic
/// substitutions.
FunctionType *getFnType() const { return FnType; }
/// \returns The callee for the application.
const ValueDecl *getCallee() const { return Callee; }
private:
Type getParamTypeImpl(AnyFunctionType *fnTy,
bool lookThroughAutoclosure) const {
auto param = fnTy->getParams()[ParamIdx];
auto paramTy = param.getPlainType();
if (lookThroughAutoclosure && param.isAutoClosure())
paramTy = paramTy->castTo<FunctionType>()->getResult();
return paramTy;
}
public:
/// \returns The type of the parameter which the argument is being applied to,
/// including any generic substitutions.
///
/// \param lookThroughAutoclosure Whether an @autoclosure () -> T parameter
/// should be treated as being of type T.
Type getParamType(bool lookThroughAutoclosure = true) const {
return getParamTypeImpl(FnType, lookThroughAutoclosure);
}
/// \returns The interface type of the parameter which the argument is being
/// applied to.
///
/// \param lookThroughAutoclosure Whether an @autoclosure () -> T parameter
/// should be treated as being of type T.
Type getParamInterfaceType(bool lookThroughAutoclosure = true) const {
auto interfaceFnTy = FnInterfaceType->getAs<AnyFunctionType>();
if (!interfaceFnTy) {
// If the interface type isn't a function, then just return the resolved
// parameter type.
return getParamType(lookThroughAutoclosure)->mapTypeOutOfContext();
}
return getParamTypeImpl(interfaceFnTy, lookThroughAutoclosure);
}
/// \returns The flags of the parameter which the argument is being applied
/// to.
ParameterTypeFlags getParameterFlags() const {
return FnType->getParams()[ParamIdx].getParameterFlags();
}
ParameterTypeFlags getParameterFlagsAtIndex(unsigned idx) const {
return FnType->getParams()[idx].getParameterFlags();
}
};
/// Describes an aspect of a solution that affects its overall score, i.e., a
/// user-defined conversions.
enum ScoreKind {
@@ -1597,6 +1732,16 @@ public:
return findSelectedOverloadFor(calleeLoc);
}
/// Resolve type variables present in the raw type, using generic parameter
/// types where possible.
Type resolveInterfaceType(Type type) const;
/// For a given locator describing a function argument conversion, or a
/// constraint within an argument conversion, returns information about the
/// application of the argument to its parameter. If the locator is not
/// for an argument conversion, returns \c None.
Optional<FunctionArgApplyInfo> getFunctionArgApplyInfo(ConstraintLocator *);
private:
unsigned assignTypeVariableID() {
return TypeCounter++;