mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Merge pull request #39302 from hamishknight/iuo-a-refactoring
This commit is contained in:
@@ -460,9 +460,21 @@ ConstraintLocator *ConstraintSystem::getCalleeLocator(
|
||||
}
|
||||
|
||||
auto anchor = locator->getAnchor();
|
||||
auto path = locator->getPath();
|
||||
{
|
||||
// If we have an implicit x[dynamicMember:] subscript call, the callee
|
||||
// is given by the original member locator it is based on, which we can get
|
||||
// by stripping away the implicit member element and everything after it.
|
||||
auto iter = path.rbegin();
|
||||
using ImplicitSubscriptElt = LocatorPathElt::ImplicitDynamicMemberSubscript;
|
||||
if (locator->findLast<ImplicitSubscriptElt>(iter)) {
|
||||
auto newPath = path.drop_back(iter - path.rbegin() + 1);
|
||||
return getConstraintLocator(anchor, newPath);
|
||||
}
|
||||
}
|
||||
|
||||
assert(bool(anchor) && "Expected an anchor!");
|
||||
|
||||
auto path = locator->getPath();
|
||||
{
|
||||
// If we have a locator for a member found through key path dynamic member
|
||||
// lookup, then we need to chop off the elements after the
|
||||
@@ -1687,6 +1699,13 @@ ConstraintSystem::getTypeOfMemberReference(
|
||||
|
||||
AnyFunctionType *funcType;
|
||||
|
||||
// Check if we need to apply a layer of optionality to the resulting type.
|
||||
auto isReferenceOptional = false;
|
||||
if (!isRequirementOrWitness(locator)) {
|
||||
if (isDynamicResult || value->getAttrs().hasAttribute<OptionalAttr>())
|
||||
isReferenceOptional = true;
|
||||
}
|
||||
|
||||
if (isa<AbstractFunctionDecl>(value) ||
|
||||
isa<EnumElementDecl>(value)) {
|
||||
// This is the easy case.
|
||||
@@ -1706,14 +1725,11 @@ ConstraintSystem::getTypeOfMemberReference(
|
||||
if (doesStorageProduceLValue(subscript, baseTy, useDC, locator))
|
||||
elementTy = LValueType::get(elementTy);
|
||||
|
||||
// See ConstraintSystem::resolveOverload() -- optional and dynamic
|
||||
// subscripts are a special case, because the optionality is
|
||||
// applied to the result type and not the type of the reference.
|
||||
if (!isRequirementOrWitness(locator)) {
|
||||
if (subscript->getAttrs().hasAttribute<OptionalAttr>() ||
|
||||
isDynamicResult)
|
||||
elementTy = OptionalType::get(elementTy->getRValueType());
|
||||
}
|
||||
// Optional and dynamic subscripts are a special case, because the
|
||||
// optionality is applied to the result type and not the type of the
|
||||
// reference.
|
||||
if (isReferenceOptional)
|
||||
elementTy = OptionalType::get(elementTy->getRValueType());
|
||||
|
||||
auto indices = subscript->getInterfaceType()
|
||||
->castTo<AnyFunctionType>()->getParams();
|
||||
@@ -1911,6 +1927,10 @@ ConstraintSystem::getTypeOfMemberReference(
|
||||
}
|
||||
}
|
||||
|
||||
// If we need to wrap the type in an optional, do so now.
|
||||
if (isReferenceOptional && !isa<SubscriptDecl>(value))
|
||||
type = OptionalType::get(type->getRValueType());
|
||||
|
||||
// If we opened up any type variables, record the replacements.
|
||||
recordOpenedTypes(locator, replacements);
|
||||
|
||||
@@ -2267,128 +2287,6 @@ isInvalidPartialApplication(ConstraintSystem &cs,
|
||||
return {true, level};
|
||||
}
|
||||
|
||||
std::pair<Type, bool> ConstraintSystem::adjustTypeOfOverloadReference(
|
||||
const OverloadChoice &choice, ConstraintLocator *locator,
|
||||
Type boundType, Type refType) {
|
||||
// If the declaration is unavailable, note that in the score.
|
||||
if (isDeclUnavailable(choice.getDecl(), locator))
|
||||
increaseScore(SK_Unavailable);
|
||||
|
||||
bool bindConstraintCreated = false;
|
||||
const auto kind = choice.getKind();
|
||||
if (kind != OverloadChoiceKind::DeclViaDynamic &&
|
||||
!isRequirementOrWitness(locator) &&
|
||||
choice.getDecl()->getAttrs().hasAttribute<OptionalAttr>() &&
|
||||
!isa<SubscriptDecl>(choice.getDecl())) {
|
||||
// For a non-subscript declaration that is an optional
|
||||
// requirement in a protocol, strip off the lvalue-ness (FIXME:
|
||||
// one cannot assign to such declarations for now) and make a
|
||||
// reference to that declaration be optional.
|
||||
//
|
||||
// Subscript declarations are handled within
|
||||
// getTypeOfMemberReference(); their result types are optional.
|
||||
|
||||
// Deal with values declared as implicitly unwrapped, or
|
||||
// functions with return types that are implicitly unwrapped.
|
||||
// TODO: Move this logic to bindOverloadType.
|
||||
if (choice.isImplicitlyUnwrappedValueOrReturnValue()) {
|
||||
// Build the disjunction to attempt binding both T? and T (or
|
||||
// function returning T? and function returning T).
|
||||
Type ty = createTypeVariable(locator,
|
||||
TVO_CanBindToLValue | TVO_CanBindToNoEscape);
|
||||
buildDisjunctionForImplicitlyUnwrappedOptional(ty, refType, locator);
|
||||
addConstraint(ConstraintKind::Bind, boundType,
|
||||
OptionalType::get(ty->getRValueType()), locator);
|
||||
bindConstraintCreated = true;
|
||||
}
|
||||
|
||||
// TODO: Move this to getTypeOfMemberReference.
|
||||
refType = OptionalType::get(refType->getRValueType());
|
||||
}
|
||||
|
||||
switch (kind) {
|
||||
case OverloadChoiceKind::Decl:
|
||||
case OverloadChoiceKind::DeclViaBridge:
|
||||
case OverloadChoiceKind::DeclViaUnwrappedOptional:
|
||||
case OverloadChoiceKind::TupleIndex:
|
||||
case OverloadChoiceKind::KeyPathApplication:
|
||||
return {refType, bindConstraintCreated};
|
||||
case OverloadChoiceKind::DeclViaDynamic: {
|
||||
// TODO: Move the IUO handling logic here to bindOverloadType.
|
||||
if (isa<SubscriptDecl>(choice.getDecl())) {
|
||||
// We always expect function type for subscripts.
|
||||
auto fnTy = refType->castTo<AnyFunctionType>();
|
||||
if (choice.isImplicitlyUnwrappedValueOrReturnValue()) {
|
||||
auto resultTy = fnTy->getResult();
|
||||
// We expect the element type to be a double-optional.
|
||||
auto optTy = resultTy->getOptionalObjectType();
|
||||
assert(optTy->getOptionalObjectType());
|
||||
|
||||
// For our original type T -> U?? we will generate:
|
||||
// A disjunction V = { U?, U }
|
||||
// and a disjunction boundType = { T -> V?, T -> V }
|
||||
Type ty = createTypeVariable(locator, TVO_CanBindToNoEscape);
|
||||
|
||||
buildDisjunctionForImplicitlyUnwrappedOptional(ty, optTy, locator);
|
||||
|
||||
// Create a new function type with an optional of this type
|
||||
// variable as the result type.
|
||||
if (auto *genFnTy = fnTy->getAs<GenericFunctionType>()) {
|
||||
fnTy = GenericFunctionType::get(
|
||||
genFnTy->getGenericSignature(), genFnTy->getParams(),
|
||||
OptionalType::get(ty), genFnTy->getExtInfo());
|
||||
} else {
|
||||
fnTy = FunctionType::get(fnTy->getParams(), OptionalType::get(ty),
|
||||
fnTy->getExtInfo());
|
||||
}
|
||||
}
|
||||
|
||||
buildDisjunctionForDynamicLookupResult(boundType, fnTy, locator);
|
||||
} else {
|
||||
Type ty = refType;
|
||||
|
||||
// If this is something we need to implicitly unwrap, set up a
|
||||
// new type variable and disjunction that will allow us to make
|
||||
// the choice of whether to do so.
|
||||
if (choice.isImplicitlyUnwrappedValueOrReturnValue()) {
|
||||
// Duplicate the structure of boundType, with fresh type
|
||||
// variables. We'll create a binding disjunction using this,
|
||||
// selecting between options for refType, which is either
|
||||
// Optional or a function type returning Optional.
|
||||
assert(boundType->hasTypeVariable());
|
||||
ty = boundType.transform([this](Type elTy) -> Type {
|
||||
if (auto *tv = dyn_cast<TypeVariableType>(elTy.getPointer())) {
|
||||
return createTypeVariable(tv->getImpl().getLocator(),
|
||||
tv->getImpl().getRawOptions());
|
||||
}
|
||||
return elTy;
|
||||
});
|
||||
|
||||
buildDisjunctionForImplicitlyUnwrappedOptional(
|
||||
ty, refType->getRValueType(), locator);
|
||||
}
|
||||
|
||||
// Build the disjunction to attempt binding both T? and T (or
|
||||
// function returning T? and function returning T).
|
||||
buildDisjunctionForDynamicLookupResult(
|
||||
boundType, OptionalType::get(ty->getRValueType()), locator);
|
||||
|
||||
// We store an Optional of the originally resolved type in the
|
||||
// overload set.
|
||||
// TODO: Move this to getTypeOfMemberReference.
|
||||
refType = OptionalType::get(refType->getRValueType());
|
||||
}
|
||||
|
||||
return {refType, /*bindConstraintCreated*/ true};
|
||||
}
|
||||
case OverloadChoiceKind::DynamicMemberLookup:
|
||||
case OverloadChoiceKind::KeyPathDynamicMemberLookup:
|
||||
return {refType, bindConstraintCreated};
|
||||
}
|
||||
|
||||
llvm_unreachable("Unhandled OverloadChoiceKind in switch.");
|
||||
}
|
||||
|
||||
/// Walk a closure AST to determine its effects.
|
||||
///
|
||||
/// \returns a function's extended info describing the effects, as
|
||||
@@ -2622,15 +2520,15 @@ void ConstraintSystem::buildDisjunctionForOptionalVsUnderlying(
|
||||
Constraint::create(*this, ConstraintKind::Bind, boundTy, ty, locator);
|
||||
bindToOptional->setFavored();
|
||||
|
||||
Type underlyingType;
|
||||
if (auto *fnTy = ty->getAs<AnyFunctionType>())
|
||||
underlyingType = replaceFinalResultTypeWithUnderlying(fnTy);
|
||||
else if (auto *typeVar = rvalueTy->getAs<TypeVariableType>()) {
|
||||
auto underlyingType = rvalueTy->getOptionalObjectType();
|
||||
if (!underlyingType) {
|
||||
// If we don't have an optional, `ty` hasn't been resolved yet.
|
||||
auto *typeVar = rvalueTy->castTo<TypeVariableType>();
|
||||
auto *locator = typeVar->getImpl().getLocator();
|
||||
|
||||
// If `ty` hasn't been resolved yet, we need to allocate a type variable to
|
||||
// represent an object type of a future optional, and add a constraint
|
||||
// between `ty` and `underlyingType` to model it.
|
||||
// We need to allocate a type variable to represent an object type of a
|
||||
// future optional, and add a constraint between `ty` and `underlyingType`
|
||||
// to model it.
|
||||
underlyingType = createTypeVariable(
|
||||
getConstraintLocator(locator, LocatorPathElt::GenericArgument(0)),
|
||||
TVO_PrefersSubtypeBinding | TVO_CanBindToLValue |
|
||||
@@ -2640,12 +2538,7 @@ void ConstraintSystem::buildDisjunctionForOptionalVsUnderlying(
|
||||
// to the underlying type below.
|
||||
addConstraint(ConstraintKind::OptionalObject, typeVar, underlyingType,
|
||||
locator);
|
||||
} else {
|
||||
underlyingType = rvalueTy->getOptionalObjectType();
|
||||
}
|
||||
|
||||
assert(underlyingType);
|
||||
|
||||
if (ty->is<LValueType>())
|
||||
underlyingType = LValueType::get(underlyingType);
|
||||
|
||||
@@ -2664,11 +2557,12 @@ void ConstraintSystem::bindOverloadType(
|
||||
ConstraintLocator *locator, DeclContext *useDC,
|
||||
llvm::function_ref<void(unsigned int, Type, ConstraintLocator *)>
|
||||
verifyThatArgumentIsHashable) {
|
||||
auto &ctx = getASTContext();
|
||||
auto choice = overload.choice;
|
||||
auto openedType = overload.openedType;
|
||||
|
||||
auto bindTypeOrIUO = [&](Type ty) {
|
||||
if (choice.isImplicitlyUnwrappedValueOrReturnValue()) {
|
||||
if (choice.getIUOReferenceKind(*this) == IUOReferenceKind::Value) {
|
||||
// Build the disjunction to attempt binding both T? and T (or
|
||||
// function returning T? and function returning T).
|
||||
buildDisjunctionForImplicitlyUnwrappedOptional(boundType, ty, locator);
|
||||
@@ -2677,45 +2571,75 @@ void ConstraintSystem::bindOverloadType(
|
||||
addConstraint(ConstraintKind::Bind, boundType, ty, locator);
|
||||
}
|
||||
};
|
||||
auto addDynamicMemberSubscriptConstraints = [&](Type argTy, Type resultTy) {
|
||||
// DynamicMemberLookup results are always a (dynamicMember: T1) -> T2
|
||||
// subscript.
|
||||
auto *fnTy = openedType->castTo<FunctionType>();
|
||||
assert(fnTy->getParams().size() == 1 &&
|
||||
"subscript always has one argument");
|
||||
|
||||
auto *callLoc = getConstraintLocator(
|
||||
locator, LocatorPathElt::ImplicitDynamicMemberSubscript());
|
||||
|
||||
// Associate an argument list for the implicit x[dynamicMember:] subscript
|
||||
// if we haven't already.
|
||||
auto *&argList = ArgumentLists[getArgumentInfoLocator(callLoc)];
|
||||
if (!argList) {
|
||||
argList = ArgumentList::createImplicit(
|
||||
ctx, {Argument(SourceLoc(), ctx.Id_dynamicMember, /*expr*/ nullptr)},
|
||||
AllocationArena::ConstraintSolver);
|
||||
}
|
||||
|
||||
auto *callerTy = FunctionType::get(
|
||||
{FunctionType::Param(argTy, ctx.Id_dynamicMember)}, resultTy);
|
||||
|
||||
ConstraintLocatorBuilder builder(callLoc);
|
||||
addConstraint(ConstraintKind::ApplicableFunction, callerTy, fnTy,
|
||||
builder.withPathElement(ConstraintLocator::ApplyFunction));
|
||||
|
||||
if (isExpr<KeyPathExpr>(locator->getAnchor())) {
|
||||
auto paramTy = fnTy->getParams()[0].getParameterType();
|
||||
verifyThatArgumentIsHashable(/*idx*/ 0, paramTy, locator);
|
||||
}
|
||||
};
|
||||
switch (choice.getKind()) {
|
||||
case OverloadChoiceKind::Decl:
|
||||
case OverloadChoiceKind::DeclViaBridge:
|
||||
case OverloadChoiceKind::DeclViaUnwrappedOptional:
|
||||
case OverloadChoiceKind::TupleIndex:
|
||||
case OverloadChoiceKind::KeyPathApplication:
|
||||
case OverloadChoiceKind::DeclViaDynamic:
|
||||
bindTypeOrIUO(openedType);
|
||||
return;
|
||||
case OverloadChoiceKind::DeclViaDynamic: {
|
||||
// Subscripts have optionality applied to their result type rather than
|
||||
// the type of their reference, so there's nothing to adjust here.
|
||||
if (isa<SubscriptDecl>(choice.getDecl())) {
|
||||
bindTypeOrIUO(openedType);
|
||||
return;
|
||||
}
|
||||
|
||||
// Build an outer disjunction to attempt binding both T? and T, then bind
|
||||
// as normal. This is needed to correctly handle e.g IUO properties which
|
||||
// may need two levels of optionality unwrapped T??.
|
||||
auto outerTy = createTypeVariable(locator, TVO_CanBindToLValue);
|
||||
buildDisjunctionForDynamicLookupResult(outerTy, openedType, locator);
|
||||
bindTypeOrIUO(outerTy);
|
||||
return;
|
||||
}
|
||||
case OverloadChoiceKind::DynamicMemberLookup: {
|
||||
// DynamicMemberLookup results are always a (dynamicMember:T1)->T2
|
||||
// subscript.
|
||||
auto refFnType = openedType->castTo<FunctionType>();
|
||||
|
||||
// Before we drop the argument type on the floor, we need to constrain it
|
||||
// to having a literal conformance to ExpressibleByStringLiteral. This
|
||||
// makes the index default to String if otherwise unconstrained.
|
||||
assert(refFnType->getParams().size() == 1 &&
|
||||
"subscript always has one arg");
|
||||
auto argType = refFnType->getParams()[0].getPlainType();
|
||||
|
||||
auto stringLiteral =
|
||||
TypeChecker::getProtocol(getASTContext(), choice.getDecl()->getLoc(),
|
||||
KnownProtocolKind::ExpressibleByStringLiteral);
|
||||
if (!stringLiteral)
|
||||
return;
|
||||
|
||||
addConstraint(ConstraintKind::LiteralConformsTo, argType,
|
||||
// Form constraints for a x[dynamicMember:] subscript with a string literal
|
||||
// argument, where the overload type is bound to the result to model the
|
||||
// fact that this a property access in the source.
|
||||
auto argTy = createTypeVariable(locator, /*options*/ 0);
|
||||
addConstraint(ConstraintKind::LiteralConformsTo, argTy,
|
||||
stringLiteral->getDeclaredInterfaceType(), locator);
|
||||
|
||||
// If this is used inside of the keypath expression, we need to make
|
||||
// sure that argument is Hashable.
|
||||
if (isExpr<KeyPathExpr>(locator->getAnchor()))
|
||||
verifyThatArgumentIsHashable(0, argType, locator);
|
||||
|
||||
// The resolved decl is for subscript(dynamicMember:), however the original
|
||||
// member constraint was for a property. Therefore we need to bind to the
|
||||
// result type.
|
||||
bindTypeOrIUO(refFnType->getResult());
|
||||
addDynamicMemberSubscriptConstraints(argTy, /*resultTy*/ boundType);
|
||||
return;
|
||||
}
|
||||
case OverloadChoiceKind::KeyPathDynamicMemberLookup: {
|
||||
@@ -2764,9 +2688,9 @@ void ConstraintSystem::bindOverloadType(
|
||||
// preferred over key path dynamic member lookup.
|
||||
increaseScore(SK_KeyPathSubscript);
|
||||
|
||||
auto dynamicResultTy = boundType->castTo<TypeVariableType>();
|
||||
auto boundTypeVar = boundType->castTo<TypeVariableType>();
|
||||
auto constraints = getConstraintGraph().gatherConstraints(
|
||||
dynamicResultTy, ConstraintGraph::GatheringKind::EquivalenceClass,
|
||||
boundTypeVar, ConstraintGraph::GatheringKind::EquivalenceClass,
|
||||
[](Constraint *constraint) {
|
||||
return constraint->getKind() == ConstraintKind::ApplicableFunction;
|
||||
});
|
||||
@@ -2790,20 +2714,11 @@ void ConstraintSystem::bindOverloadType(
|
||||
// - Original result type `$T_R` is going to represent result of
|
||||
// the `[dynamicMember: \.[0]]` invocation.
|
||||
|
||||
// Result of the `WritableKeyPath` is going to be l-value type,
|
||||
// let's adjust l-valueness of the result type to accommodate that.
|
||||
//
|
||||
// This is required because we are binding result of the subscript
|
||||
// to its "member type" which becomes dynamic result type. We could
|
||||
// form additional `applicable fn` constraint here and bind it to a
|
||||
// function type, but it would create inconsistency with how properties
|
||||
// are handled, which means more special handling in CSApply.
|
||||
if (keyPathTy->isWritableKeyPath() ||
|
||||
keyPathTy->isReferenceWritableKeyPath())
|
||||
dynamicResultTy->getImpl().setCanBindToLValue(getSavedBindings(),
|
||||
/*enabled=*/true);
|
||||
|
||||
auto fnType = applicableFn->getFirstType()->castTo<FunctionType>();
|
||||
// The function type of the original call-site. We'll want to create a
|
||||
// new applicable fn constraint using its parameter along with a fresh
|
||||
// type variable for the result of the inner subscript.
|
||||
auto originalCallerTy =
|
||||
applicableFn->getFirstType()->castTo<FunctionType>();
|
||||
|
||||
auto subscriptResultTy = createTypeVariable(
|
||||
getConstraintLocator(locator->getAnchor(),
|
||||
@@ -2812,35 +2727,38 @@ void ConstraintSystem::bindOverloadType(
|
||||
|
||||
// FIXME: Verify ExtInfo state is correct, not working by accident.
|
||||
FunctionType::ExtInfo info;
|
||||
auto adjustedFnTy =
|
||||
FunctionType::get(fnType->getParams(), subscriptResultTy, info);
|
||||
auto adjustedFnTy = FunctionType::get(originalCallerTy->getParams(),
|
||||
subscriptResultTy, info);
|
||||
|
||||
// Add a constraint for the inner application that uses the args of the
|
||||
// original call-site, and a fresh type var result equal to the leaf type.
|
||||
ConstraintLocatorBuilder kpLocBuilder(keyPathLoc);
|
||||
addConstraint(
|
||||
ConstraintKind::ApplicableFunction, adjustedFnTy, memberTy,
|
||||
kpLocBuilder.withPathElement(ConstraintLocator::ApplyFunction));
|
||||
|
||||
addConstraint(ConstraintKind::Bind, dynamicResultTy, fnType->getResult(),
|
||||
keyPathLoc);
|
||||
|
||||
addConstraint(ConstraintKind::Equal, subscriptResultTy, leafTy,
|
||||
keyPathLoc);
|
||||
|
||||
addDynamicMemberSubscriptConstraints(/*argTy*/ keyPathTy,
|
||||
originalCallerTy->getResult());
|
||||
|
||||
// Bind the overload type to the opened type as usual to match the fact
|
||||
// that this is a subscript in the source.
|
||||
bindTypeOrIUO(fnType);
|
||||
} else {
|
||||
// Since member type is going to be bound to "leaf" generic parameter
|
||||
// of the keypath, it has to be an r-value always, so let's add a new
|
||||
// constraint to represent that conversion instead of loading member
|
||||
// type into "leaf" directly.
|
||||
addConstraint(ConstraintKind::Equal, memberTy, leafTy, keyPathLoc);
|
||||
|
||||
// Form constraints for a x[dynamicMember:] subscript with a key path
|
||||
// argument, where the overload type is bound to the result to model the
|
||||
// fact that this a property access in the source.
|
||||
addDynamicMemberSubscriptConstraints(/*argTy*/ keyPathTy,
|
||||
boundType);
|
||||
}
|
||||
|
||||
if (isExpr<KeyPathExpr>(locator->getAnchor()))
|
||||
verifyThatArgumentIsHashable(0, keyPathTy, locator);
|
||||
|
||||
// The resolved decl is for subscript(dynamicMember:), however the
|
||||
// original member constraint was either for a property, or we've
|
||||
// re-purposed the overload type variable to represent the result type of
|
||||
// the subscript. In both cases, we need to bind to the result type.
|
||||
bindTypeOrIUO(fnType->getResult());
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -2870,7 +2788,6 @@ void ConstraintSystem::resolveOverload(ConstraintLocator *locator,
|
||||
Type refType;
|
||||
Type openedFullType;
|
||||
|
||||
bool bindConstraintCreated = false;
|
||||
switch (auto kind = choice.getKind()) {
|
||||
case OverloadChoiceKind::Decl:
|
||||
case OverloadChoiceKind::DeclViaBridge:
|
||||
@@ -2904,17 +2821,6 @@ void ConstraintSystem::resolveOverload(ConstraintLocator *locator,
|
||||
= getTypeOfReference(choice.getDecl(),
|
||||
choice.getFunctionRefKind(), locator, useDC);
|
||||
}
|
||||
|
||||
// For a non-subscript declaration found via dynamic lookup, strip
|
||||
// off the lvalue-ness (FIXME: as a temporary hack. We eventually
|
||||
// want this to work) and make a reference to that declaration be
|
||||
// an implicitly unwrapped optional.
|
||||
//
|
||||
// Subscript declarations are handled within
|
||||
// getTypeOfMemberReference(); their result types are unchecked
|
||||
// optional.
|
||||
std::tie(refType, bindConstraintCreated) =
|
||||
adjustTypeOfOverloadReference(choice, locator, boundType, refType);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -3059,11 +2965,9 @@ void ConstraintSystem::resolveOverload(ConstraintLocator *locator,
|
||||
assert(result.second && "Already resolved this overload?");
|
||||
(void)result;
|
||||
|
||||
// In some cases we already created the appropriate bind constraints.
|
||||
if (!bindConstraintCreated) {
|
||||
bindOverloadType(overload, boundType, locator, useDC,
|
||||
verifyThatArgumentIsHashable);
|
||||
}
|
||||
// Add the constraints necessary to bind the overload type.
|
||||
bindOverloadType(overload, boundType, locator, useDC,
|
||||
verifyThatArgumentIsHashable);
|
||||
|
||||
if (isDebugMode()) {
|
||||
PrintOptions PO;
|
||||
@@ -3074,10 +2978,14 @@ void ConstraintSystem::resolveOverload(ConstraintLocator *locator,
|
||||
<< refType->getString(PO) << ")\n";
|
||||
}
|
||||
|
||||
// If this overload is disfavored, note that.
|
||||
if (choice.isDecl() &&
|
||||
choice.getDecl()->getAttrs().hasAttribute<DisfavoredOverloadAttr>()) {
|
||||
increaseScore(SK_DisfavoredOverload);
|
||||
if (auto *decl = choice.getDeclOrNull()) {
|
||||
// If the declaration is unavailable, note that in the score.
|
||||
if (isDeclUnavailable(decl, locator))
|
||||
increaseScore(SK_Unavailable);
|
||||
|
||||
// If this overload is disfavored, note that.
|
||||
if (decl->getAttrs().hasAttribute<DisfavoredOverloadAttr>())
|
||||
increaseScore(SK_DisfavoredOverload);
|
||||
}
|
||||
|
||||
if (choice.isFallbackMemberOnUnwrappedBase()) {
|
||||
@@ -3229,27 +3137,37 @@ DeclName OverloadChoice::getName() const {
|
||||
llvm_unreachable("Unhandled OverloadChoiceKind in switch.");
|
||||
}
|
||||
|
||||
bool OverloadChoice::isImplicitlyUnwrappedValueOrReturnValue() const {
|
||||
if (!isDecl())
|
||||
return false;
|
||||
Optional<IUOReferenceKind>
|
||||
OverloadChoice::getIUOReferenceKind(ConstraintSystem &cs,
|
||||
bool forSecondApplication) const {
|
||||
auto *decl = getDeclOrNull();
|
||||
if (!decl || !decl->isImplicitlyUnwrappedOptional())
|
||||
return None;
|
||||
|
||||
auto *decl = getDecl();
|
||||
if (!decl->isImplicitlyUnwrappedOptional())
|
||||
return false;
|
||||
// If this isn't an IUO return () -> T!, it's an IUO value.
|
||||
if (!decl->getInterfaceType()->is<AnyFunctionType>())
|
||||
return IUOReferenceKind::Value;
|
||||
|
||||
auto itfType = decl->getInterfaceType();
|
||||
if (!itfType->getAs<AnyFunctionType>())
|
||||
return true;
|
||||
auto refKind = getFunctionRefKind();
|
||||
assert(!forSecondApplication || refKind == FunctionRefKind::DoubleApply);
|
||||
|
||||
switch (getFunctionRefKind()) {
|
||||
switch (refKind) {
|
||||
case FunctionRefKind::Unapplied:
|
||||
case FunctionRefKind::Compound:
|
||||
return false;
|
||||
// Such references never produce IUOs.
|
||||
return None;
|
||||
case FunctionRefKind::SingleApply:
|
||||
case FunctionRefKind::DoubleApply:
|
||||
return true;
|
||||
case FunctionRefKind::DoubleApply: {
|
||||
// Check whether this is a curried function reference e.g
|
||||
// (Self) -> (Args...) -> Ret. Such a function reference can only produce
|
||||
// an IUO on the second application.
|
||||
auto isCurried = decl->hasCurriedSelf() && !hasAppliedSelf(cs, *this);
|
||||
if (forSecondApplication != isCurried)
|
||||
return None;
|
||||
break;
|
||||
}
|
||||
llvm_unreachable("unhandled kind");
|
||||
}
|
||||
return IUOReferenceKind::ReturnValue;
|
||||
}
|
||||
|
||||
SolutionResult ConstraintSystem::salvage() {
|
||||
@@ -4549,7 +4467,8 @@ void constraints::simplifyLocator(ASTNode &anchor,
|
||||
continue;
|
||||
}
|
||||
|
||||
case ConstraintLocator::KeyPathDynamicMember: {
|
||||
case ConstraintLocator::KeyPathDynamicMember:
|
||||
case ConstraintLocator::ImplicitDynamicMemberSubscript: {
|
||||
// Key path dynamic member lookup should be completely transparent.
|
||||
path = path.slice(1);
|
||||
continue;
|
||||
@@ -4731,6 +4650,13 @@ ConstraintSystem::getArgumentInfoLocator(ConstraintLocator *locator) {
|
||||
if (auto *UME = getAsExpr<UnresolvedMemberExpr>(anchor))
|
||||
return getConstraintLocator(UME);
|
||||
|
||||
// All implicit x[dynamicMember:] subscript calls can share the same argument
|
||||
// list.
|
||||
if (locator->findLast<LocatorPathElt::ImplicitDynamicMemberSubscript>()) {
|
||||
return getConstraintLocator(
|
||||
ASTNode(), LocatorPathElt::ImplicitDynamicMemberSubscript());
|
||||
}
|
||||
|
||||
auto path = locator->getPath();
|
||||
{
|
||||
// If this is for a dynamic member reference, the argument info is for the
|
||||
|
||||
Reference in New Issue
Block a user