Files
swift-mirror/lib/Sema/ConstraintSystem.cpp
Hamish Knight 4716f61fba [AST] Introduce explicit actions for ASTWalker
Replace the use of bool and pointer returns for
`walkToXXXPre`/`walkToXXXPost`, and instead use
explicit actions such as `Action::Continue(E)`,
`Action::SkipChildren(E)`, and `Action::Stop()`.
There are also conditional variants, e.g
`Action::SkipChildrenIf`, `Action::VisitChildrenIf`,
and `Action::StopIf`.

There is still more work that can be done here, in
particular:

- SourceEntityWalker still needs to be migrated.
- Some uses of `return false` in pre-visitation
methods can likely now be replaced by
`Action::Stop`.
- We still use bool and pointer returns internally
within the ASTWalker traversal, which could likely
be improved.

But I'm leaving those as future work for now as
this patch is already large enough.
2022-09-13 10:35:29 +01:00

7042 lines
252 KiB
C++

//===--- ConstraintSystem.cpp - Constraint-based Type Checking ------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2018 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 implements the constraint-based type checker, anchored by the
// \c ConstraintSystem class, which provides type checking and type
// inference for expressions.
//
//===----------------------------------------------------------------------===//
#include "CSDiagnostics.h"
#include "TypeChecker.h"
#include "TypeCheckAvailability.h"
#include "TypeCheckConcurrency.h"
#include "TypeCheckType.h"
#include "swift/AST/Initializer.h"
#include "swift/AST/GenericEnvironment.h"
#include "swift/AST/ParameterList.h"
#include "swift/AST/ProtocolConformance.h"
#include "swift/AST/TypeCheckRequests.h"
#include "swift/Basic/Defer.h"
#include "swift/Basic/Statistic.h"
#include "swift/Sema/CSFix.h"
#include "swift/Sema/ConstraintGraph.h"
#include "swift/Sema/ConstraintSystem.h"
#include "swift/Sema/SolutionResult.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Format.h"
using namespace swift;
using namespace constraints;
using namespace inference;
#define DEBUG_TYPE "ConstraintSystem"
ExpressionTimer::ExpressionTimer(AnchorType Anchor, ConstraintSystem &CS)
: ExpressionTimer(
Anchor, CS,
CS.getASTContext().TypeCheckerOpts.ExpressionTimeoutThreshold) {}
ExpressionTimer::ExpressionTimer(AnchorType Anchor, ConstraintSystem &CS,
unsigned thresholdInMillis)
: Anchor(Anchor), Context(CS.getASTContext()),
StartTime(llvm::TimeRecord::getCurrentTime()),
ThresholdInMillis(thresholdInMillis),
PrintDebugTiming(CS.getASTContext().TypeCheckerOpts.DebugTimeExpressions),
PrintWarning(true) {}
SourceRange ExpressionTimer::getAffectedRange() const {
ASTNode anchor;
if (auto *locator = Anchor.dyn_cast<ConstraintLocator *>()) {
anchor = simplifyLocatorToAnchor(locator);
// If locator couldn't be simplified down to a single AST
// element, let's use its root.
if (!anchor)
anchor = locator->getAnchor();
} else {
anchor = Anchor.get<Expr *>();
}
return anchor.getSourceRange();
}
ExpressionTimer::~ExpressionTimer() {
auto elapsed = getElapsedProcessTimeInFractionalSeconds();
unsigned elapsedMS = static_cast<unsigned>(elapsed * 1000);
if (PrintDebugTiming) {
// Round up to the nearest 100th of a millisecond.
llvm::errs() << llvm::format("%0.2f", ceil(elapsed * 100000) / 100)
<< "ms\t";
if (auto *E = Anchor.dyn_cast<Expr *>()) {
E->getLoc().print(llvm::errs(), Context.SourceMgr);
} else {
auto *locator = Anchor.get<ConstraintLocator *>();
locator->dump(&Context.SourceMgr, llvm::errs());
}
llvm::errs() << "\n";
}
if (!PrintWarning)
return;
const auto WarnLimit = getWarnLimit();
if (WarnLimit == 0 || elapsedMS < WarnLimit)
return;
auto sourceRange = getAffectedRange();
if (sourceRange.Start.isValid()) {
Context.Diags
.diagnose(sourceRange.Start, diag::debug_long_expression, elapsedMS,
WarnLimit)
.highlight(sourceRange);
}
}
ConstraintSystem::ConstraintSystem(DeclContext *dc,
ConstraintSystemOptions options)
: Context(dc->getASTContext()), DC(dc), Options(options),
Arena(dc->getASTContext(), Allocator),
CG(*new ConstraintGraph(*this))
{
assert(DC && "context required");
// Respect the global debugging flag, but turn off debugging while
// parsing and loading other modules.
if (Context.TypeCheckerOpts.DebugConstraintSolver &&
DC->getParentModule()->isMainModule()) {
Options |= ConstraintSystemFlags::DebugConstraints;
}
if (Context.LangOpts.UseClangFunctionTypes)
Options |= ConstraintSystemFlags::UseClangFunctionTypes;
}
ConstraintSystem::~ConstraintSystem() {
delete &CG;
}
void ConstraintSystem::incrementScopeCounter() {
++CountScopes;
// FIXME: (transitional) increment the redundant "always-on" counter.
if (auto *Stats = getASTContext().Stats)
++Stats->getFrontendCounters().NumConstraintScopes;
}
void ConstraintSystem::incrementLeafScopes() {
if (auto *Stats = getASTContext().Stats)
++Stats->getFrontendCounters().NumLeafScopes;
}
bool ConstraintSystem::hasFreeTypeVariables() {
// Look for any free type variables.
return llvm::any_of(TypeVariables, [](const TypeVariableType *typeVar) {
return !typeVar->getImpl().hasRepresentativeOrFixed();
});
}
void ConstraintSystem::addTypeVariable(TypeVariableType *typeVar) {
TypeVariables.insert(typeVar);
// Notify the constraint graph.
(void)CG[typeVar];
}
void ConstraintSystem::mergeEquivalenceClasses(TypeVariableType *typeVar1,
TypeVariableType *typeVar2,
bool updateWorkList) {
assert(typeVar1 == getRepresentative(typeVar1) &&
"typeVar1 is not the representative");
assert(typeVar2 == getRepresentative(typeVar2) &&
"typeVar2 is not the representative");
assert(typeVar1 != typeVar2 && "cannot merge type with itself");
typeVar1->getImpl().mergeEquivalenceClasses(typeVar2, getSavedBindings());
// Merge nodes in the constraint graph.
CG.mergeNodes(typeVar1, typeVar2);
if (updateWorkList) {
addTypeVariableConstraintsToWorkList(typeVar1);
}
}
/// Determine whether the given type variables occurs in the given type.
bool ConstraintSystem::typeVarOccursInType(TypeVariableType *typeVar,
Type type,
bool *involvesOtherTypeVariables) {
SmallPtrSet<TypeVariableType *, 4> typeVars;
type->getTypeVariables(typeVars);
bool occurs = typeVars.count(typeVar);
if (involvesOtherTypeVariables) {
*involvesOtherTypeVariables =
occurs ? typeVars.size() > 1 : !typeVars.empty();
}
return occurs;
}
void ConstraintSystem::assignFixedType(TypeVariableType *typeVar, Type type,
bool updateState,
bool notifyBindingInference) {
assert(!type->hasError() &&
"Should not be assigning a type involving ErrorType!");
typeVar->getImpl().assignFixedType(type, getSavedBindings());
if (!updateState)
return;
if (!type->isTypeVariableOrMember()) {
// If this type variable represents a literal, check whether we picked the
// default literal type. First, find the corresponding protocol.
//
// If we have the constraint graph, we can check all type variables in
// the equivalence class. This is the More Correct path.
// FIXME: Eliminate the less-correct path.
auto typeVarRep = getRepresentative(typeVar);
for (auto *tv : CG[typeVarRep].getEquivalenceClass()) {
auto locator = tv->getImpl().getLocator();
if (!(locator && (locator->directlyAt<CollectionExpr>() ||
locator->directlyAt<LiteralExpr>())))
continue;
auto *literalProtocol = TypeChecker::getLiteralProtocol(
getASTContext(), castToExpr(locator->getAnchor()));
if (!literalProtocol)
continue;
// If the protocol has a default type, check it.
if (auto defaultType = TypeChecker::getDefaultType(literalProtocol, DC)) {
// Check whether the nominal types match. This makes sure that we
// properly handle Array vs. Array<T>.
if (defaultType->getAnyNominal() != type->getAnyNominal()) {
increaseScore(SK_NonDefaultLiteral);
}
}
break;
}
}
// Notify the constraint graph.
CG.bindTypeVariable(typeVar, type);
addTypeVariableConstraintsToWorkList(typeVar);
if (notifyBindingInference)
CG[typeVar].introduceToInference(type);
}
void ConstraintSystem::addTypeVariableConstraintsToWorkList(
TypeVariableType *typeVar) {
// Activate the constraints affected by a change to this type variable.
auto gatheringKind = ConstraintGraph::GatheringKind::AllMentions;
for (auto *constraint : CG.gatherConstraints(typeVar, gatheringKind))
if (!constraint->isActive())
activateConstraint(constraint);
}
/// Retrieve a dynamic result signature for the given declaration.
static std::tuple<char, ObjCSelector, CanType>
getDynamicResultSignature(ValueDecl *decl) {
if (auto func = dyn_cast<AbstractFunctionDecl>(decl)) {
// Handle functions.
auto type = func->getMethodInterfaceType();
return std::make_tuple(func->isStatic(), func->getObjCSelector(),
type->getCanonicalType());
}
if (auto asd = dyn_cast<AbstractStorageDecl>(decl)) {
auto ty = asd->getInterfaceType();
// Strip off a generic signature if we have one. This matches the logic
// for methods, and ensures that we don't take a protocol's generic
// signature into account for a subscript requirement.
if (auto *genericFn = ty->getAs<GenericFunctionType>()) {
ty = FunctionType::get(genericFn->getParams(), genericFn->getResult(),
genericFn->getExtInfo());
}
// Handle properties and subscripts, anchored by the getter's selector.
return std::make_tuple(asd->isStatic(), asd->getObjCGetterSelector(),
ty->getCanonicalType());
}
llvm_unreachable("Not a valid @objc member");
}
LookupResult &ConstraintSystem::lookupMember(Type base, DeclNameRef name) {
// Check whether we've already performed this lookup.
auto &result = MemberLookups[{base, name}];
if (result) return *result;
// Lookup the member.
result = TypeChecker::lookupMember(DC, base, name, defaultMemberLookupOptions);
// If we aren't performing dynamic lookup, we're done.
if (!*result || !base->isAnyObject())
return *result;
// We are performing dynamic lookup. Filter out redundant results early.
llvm::DenseMap<std::tuple<char, ObjCSelector, CanType>, ValueDecl *> known;
bool anyRemovals = false;
for (const auto &entry : *result) {
auto *decl = entry.getValueDecl();
// Remove invalid declarations so the constraint solver doesn't need to
// cope with them.
if (decl->isInvalid()) {
anyRemovals = true;
continue;
}
// If this is the first entry with the signature, record it.
auto &uniqueEntry = known[getDynamicResultSignature(decl)];
if (!uniqueEntry) {
uniqueEntry = decl;
continue;
}
// We have duplication; note that we'll need to remove something,
anyRemovals = true;
// If the entry we recorded was unavailable but this new entry is not,
// replace the recorded entry with this one.
if (isDeclUnavailable(uniqueEntry) && !isDeclUnavailable(decl)) {
uniqueEntry = decl;
}
}
// If there's anything to remove, filter it out now.
if (anyRemovals) {
result->filter([&](LookupResultEntry entry, bool isOuter) -> bool {
auto *decl = entry.getValueDecl();
// Remove invalid declarations so the constraint solver doesn't need to
// cope with them.
if (decl->isInvalid())
return false;
return known[getDynamicResultSignature(decl)] == decl;
});
}
return *result;
}
ArrayRef<Type>
ConstraintSystem::getAlternativeLiteralTypes(KnownProtocolKind kind,
SmallVectorImpl<Type> &scratch) {
assert(scratch.empty());
if (kind == KnownProtocolKind::ExpressibleByIntegerLiteral) {
// Integer literals can be treated as floating point literals.
if (auto floatProto = getASTContext().getProtocol(
KnownProtocolKind::ExpressibleByFloatLiteral)) {
if (auto defaultType = TypeChecker::getDefaultType(floatProto, DC))
scratch.push_back(defaultType);
}
}
return scratch;
}
bool ConstraintSystem::containsCodeCompletionLoc(ASTNode node) const {
SourceRange range = node.getSourceRange();
if (range.isInvalid())
return false;
return Context.SourceMgr.rangeContainsCodeCompletionLoc(range);
}
bool ConstraintSystem::containsCodeCompletionLoc(
const ArgumentList *args) const {
SourceRange range = args->getSourceRange();
if (range.isInvalid())
return false;
return Context.SourceMgr.rangeContainsCodeCompletionLoc(range);
}
ConstraintLocator *ConstraintSystem::getConstraintLocator(
ASTNode anchor, ArrayRef<ConstraintLocator::PathElement> path) {
auto summaryFlags = ConstraintLocator::getSummaryFlagsForPath(path);
return getConstraintLocator(anchor, path, summaryFlags);
}
ConstraintLocator *ConstraintSystem::getConstraintLocator(
ASTNode anchor, ArrayRef<ConstraintLocator::PathElement> path,
unsigned summaryFlags) {
assert(summaryFlags == ConstraintLocator::getSummaryFlagsForPath(path));
// Check whether a locator with this anchor + path already exists.
llvm::FoldingSetNodeID id;
ConstraintLocator::Profile(id, anchor, path);
void *insertPos = nullptr;
auto locator = ConstraintLocators.FindNodeOrInsertPos(id, insertPos);
if (locator)
return locator;
// Allocate a new locator and add it to the set.
locator = ConstraintLocator::create(getAllocator(), anchor, path,
summaryFlags);
ConstraintLocators.InsertNode(locator, insertPos);
return locator;
}
ConstraintLocator *ConstraintSystem::getConstraintLocator(
const ConstraintLocatorBuilder &builder) {
// If the builder has an empty path, just extract its base locator.
if (builder.hasEmptyPath()) {
return builder.getBaseLocator();
}
// We have to build a new locator. Extract the paths from the builder.
SmallVector<LocatorPathElt, 4> path;
auto anchor = builder.getLocatorParts(path);
return getConstraintLocator(anchor, path, builder.getSummaryFlags());
}
ConstraintLocator *ConstraintSystem::getConstraintLocator(
ConstraintLocator *locator,
ArrayRef<ConstraintLocator::PathElement> newElts) {
auto oldPath = locator->getPath();
SmallVector<ConstraintLocator::PathElement, 4> newPath;
newPath.append(oldPath.begin(), oldPath.end());
newPath.append(newElts.begin(), newElts.end());
return getConstraintLocator(locator->getAnchor(), newPath);
}
ConstraintLocator *ConstraintSystem::getConstraintLocator(
const ConstraintLocatorBuilder &builder,
ArrayRef<ConstraintLocator::PathElement> newElts) {
SmallVector<ConstraintLocator::PathElement, 4> newPath;
auto anchor = builder.getLocatorParts(newPath);
newPath.append(newElts.begin(), newElts.end());
return getConstraintLocator(anchor, newPath);
}
ConstraintLocator *ConstraintSystem::getImplicitValueConversionLocator(
ConstraintLocatorBuilder root, ConversionRestrictionKind restriction) {
SmallVector<LocatorPathElt, 4> path;
auto anchor = root.getLocatorParts(path);
{
if (isExpr<DictionaryExpr>(anchor) && path.size() > 1) {
// Drop everything except for first `tuple element #`.
path.pop_back_n(path.size() - 1);
}
// Drop any value-to-optional conversions that were applied along the
// way to reach this one.
while (!path.empty()) {
if (path.back().is<LocatorPathElt::OptionalPayload>()) {
path.pop_back();
continue;
}
break;
}
// If conversion is for a tuple element, let's drop `TupleType`
// components from the path since they carry information for
// diagnostics that `ExprRewriter` won't be able to re-construct
// during solution application.
if (!path.empty() && path.back().is<LocatorPathElt::TupleElement>()) {
path.erase(llvm::remove_if(path,
[](const LocatorPathElt &elt) {
return elt.is<LocatorPathElt::TupleType>();
}),
path.end());
}
}
return getConstraintLocator(/*base=*/getConstraintLocator(anchor, path),
LocatorPathElt::ImplicitConversion(restriction));
}
ConstraintLocator *ConstraintSystem::getCalleeLocator(
ConstraintLocator *locator, bool lookThroughApply,
llvm::function_ref<Type(Expr *)> getType,
llvm::function_ref<Type(Type)> simplifyType,
llvm::function_ref<Optional<SelectedOverload>(ConstraintLocator *)>
getOverloadFor) {
if (locator->findLast<LocatorPathElt::ImplicitConversion>())
return locator;
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);
}
}
{
// 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
// KeyPathDynamicMember element to get the callee locator.
auto iter = path.rbegin();
if (locator->findLast<LocatorPathElt::KeyPathDynamicMember>(iter)) {
auto newPath = path.drop_back(iter - path.rbegin());
return getConstraintLocator(anchor, newPath);
}
}
if (locator->findLast<LocatorPathElt::DynamicCallable>()) {
return getConstraintLocator(anchor, LocatorPathElt::ApplyFunction());
}
if (locator->isLastElement<LocatorPathElt::ArgumentAttribute>()) {
return getConstraintLocator(anchor, path.drop_back());
}
// If we have a locator that starts with a key path component element, we
// may have a callee given by a property or subscript component.
if (auto componentElt =
locator->getFirstElementAs<LocatorPathElt::KeyPathComponent>()) {
auto *kpExpr = castToExpr<KeyPathExpr>(anchor);
auto component = kpExpr->getComponents()[componentElt->getIndex()];
using ComponentKind = KeyPathExpr::Component::Kind;
switch (component.getKind()) {
case ComponentKind::UnresolvedSubscript:
case ComponentKind::Subscript:
// For a subscript the callee is given by 'component -> subscript member'.
return getConstraintLocator(
anchor, {*componentElt, ConstraintLocator::SubscriptMember});
case ComponentKind::UnresolvedProperty:
case ComponentKind::Property:
// For a property, the choice is just given by the component.
return getConstraintLocator(anchor, *componentElt);
case ComponentKind::TupleElement:
llvm_unreachable("Not implemented by CSGen");
break;
case ComponentKind::Invalid:
case ComponentKind::OptionalForce:
case ComponentKind::OptionalChain:
case ComponentKind::OptionalWrap:
case ComponentKind::Identity:
case ComponentKind::DictionaryKey:
case ComponentKind::CodeCompletion:
// These components don't have any callee associated, so just continue.
break;
}
}
// Make sure we handle subscripts before looking at apply exprs. We don't
// want to return a subscript member locator for an expression such as x[](y),
// as its callee is not the subscript, but rather the function it returns.
if (isExpr<SubscriptExpr>(anchor))
return getConstraintLocator(anchor, ConstraintLocator::SubscriptMember);
auto getSpecialFnCalleeLoc = [&](Type fnTy) -> ConstraintLocator * {
fnTy = simplifyType(fnTy);
// It's okay for function type to contain type variable(s) e.g.
// opened generic function types, but not to be one.
assert(!fnTy->is<TypeVariableType>());
// For an apply of a metatype, we have a short-form constructor. Unlike
// other locators to callees, these are anchored on the apply expression
// rather than the function expr.
if (fnTy->is<AnyMetatypeType>()) {
return getConstraintLocator(anchor,
{LocatorPathElt::ApplyFunction(),
LocatorPathElt::ConstructorMember()});
}
// Handle an apply of a nominal type which supports callAsFunction.
if (fnTy->isCallAsFunctionType(DC)) {
return getConstraintLocator(anchor,
{LocatorPathElt::ApplyFunction(),
LocatorPathElt::ImplicitCallAsFunction()});
}
// Handling an apply for a nominal type that supports @dynamicCallable.
if (fnTy->hasDynamicCallableAttribute()) {
return getConstraintLocator(anchor, LocatorPathElt::ApplyFunction());
}
return nullptr;
};
if (lookThroughApply) {
if (auto *applyExpr = getAsExpr<ApplyExpr>(anchor)) {
auto *fnExpr = applyExpr->getFn();
// Handle special cases for applies of non-function types.
if (auto *loc = getSpecialFnCalleeLoc(getType(fnExpr)))
return loc;
// Otherwise fall through and look for locators anchored on the function
// expr. For CallExprs, this can look through things like parens and
// optional chaining.
if (auto *callExpr = getAsExpr<CallExpr>(anchor)) {
anchor = callExpr->getDirectCallee();
} else {
anchor = fnExpr;
}
}
}
if (auto *UDE = getAsExpr<UnresolvedDotExpr>(anchor)) {
if (UDE->isImplicit() &&
UDE->getName().getBaseName() == Context.Id_callAsFunction) {
return getConstraintLocator(anchor,
{LocatorPathElt::ApplyFunction(),
LocatorPathElt::ImplicitCallAsFunction()});
}
return getConstraintLocator(
anchor, TypeChecker::getSelfForInitDelegationInConstructor(DC, UDE)
? ConstraintLocator::ConstructorMember
: ConstraintLocator::Member);
}
if (auto *UME = getAsExpr<UnresolvedMemberExpr>(anchor)) {
return getConstraintLocator(UME, ConstraintLocator::UnresolvedMember);
}
if (isExpr<MemberRefExpr>(anchor))
return getConstraintLocator(anchor, ConstraintLocator::Member);
if (isExpr<ObjectLiteralExpr>(anchor))
return getConstraintLocator(anchor, ConstraintLocator::ConstructorMember);
return getConstraintLocator(anchor);
}
ConstraintLocator *ConstraintSystem::getOpenOpaqueLocator(
ConstraintLocatorBuilder locator, OpaqueTypeDecl *opaqueDecl) {
// Use only the opaque type declaration.
return getConstraintLocator(
ASTNode(opaqueDecl),
{ LocatorPathElt::OpenedOpaqueArchetype(opaqueDecl) }, 0);
}
std::pair<Type, OpenedArchetypeType *> ConstraintSystem::openExistentialType(
Type type, ConstraintLocator *locator) {
OpenedArchetypeType *opened = nullptr;
auto sig = DC->getGenericSignatureOfContext();
Type result = type->openAnyExistentialType(opened, sig);
assert(OpenedExistentialTypes.count(locator) == 0);
OpenedExistentialTypes.insert({locator, opened});
return {result, opened};
}
/// Extend the given depth map by adding depths for all of the subexpressions
/// of the given expression.
static void extendDepthMap(
Expr *expr,
llvm::DenseMap<Expr *, std::pair<unsigned, Expr *>> &depthMap) {
class RecordingTraversal : public ASTWalker {
SmallVector<ClosureExpr *, 4> Closures;
public:
llvm::DenseMap<Expr *, std::pair<unsigned, Expr *>> &DepthMap;
unsigned Depth = 0;
explicit RecordingTraversal(
llvm::DenseMap<Expr *, std::pair<unsigned, Expr *>> &depthMap)
: DepthMap(depthMap) {}
// For argument lists, bump the depth of the arguments, as they are
// effectively nested within the argument list. It's debatable whether we
// should actually do this, as it doesn't reflect the true expression depth,
// but it's needed to preserve compatibility with the behavior from when
// TupleExpr and ParenExpr were used to represent argument lists.
PreWalkResult<ArgumentList *>
walkToArgumentListPre(ArgumentList *ArgList) override {
++Depth;
return Action::Continue(ArgList);
}
PostWalkResult<ArgumentList *>
walkToArgumentListPost(ArgumentList *ArgList) override {
--Depth;
return Action::Continue(ArgList);
}
PreWalkResult<Expr *> walkToExprPre(Expr *E) override {
DepthMap[E] = {Depth, Parent.getAsExpr()};
++Depth;
if (auto CE = dyn_cast<ClosureExpr>(E))
Closures.push_back(CE);
return Action::Continue(E);
}
PostWalkResult<Expr *> walkToExprPost(Expr *E) override {
if (auto CE = dyn_cast<ClosureExpr>(E)) {
assert(Closures.back() == CE);
Closures.pop_back();
}
--Depth;
return Action::Continue(E);
}
PreWalkResult<Stmt *> walkToStmtPre(Stmt *S) override {
if (auto RS = dyn_cast<ReturnStmt>(S)) {
// For return statements, treat the parent of the return expression
// as the closure itself.
if (RS->hasResult() && !Closures.empty()) {
llvm::SaveAndRestore<ParentTy> SavedParent(Parent, Closures.back());
auto E = RS->getResult();
E->walk(*this);
return Action::SkipChildren(S);
}
}
return Action::Continue(S);
}
};
RecordingTraversal traversal(depthMap);
expr->walk(traversal);
}
Optional<std::pair<unsigned, Expr *>> ConstraintSystem::getExprDepthAndParent(
Expr *expr) {
// Bring the set of expression weights up to date.
while (NumInputExprsInWeights < InputExprs.size()) {
extendDepthMap(InputExprs[NumInputExprsInWeights], ExprWeights);
++NumInputExprsInWeights;
}
auto e = ExprWeights.find(expr);
if (e != ExprWeights.end())
return e->second;
return None;
}
Type ConstraintSystem::openUnboundGenericType(GenericTypeDecl *decl,
Type parentTy,
ConstraintLocatorBuilder locator,
bool isTypeResolution) {
if (parentTy) {
parentTy = replaceInferableTypesWithTypeVars(parentTy, locator);
}
// Open up the generic type.
OpenedTypeMap replacements;
openGeneric(decl->getDeclContext(), decl->getGenericSignature(), locator,
replacements);
recordOpenedTypes(locator, replacements);
if (parentTy) {
const auto parentTyInContext =
isTypeResolution
// Type resolution produces interface types, so we have to map
// the parent type into context before binding type variables.
? DC->mapTypeIntoContext(parentTy)
: parentTy;
const auto subs =
parentTyInContext->getContextSubstitutions(decl->getDeclContext());
for (auto pair : subs) {
auto found = replacements.find(
cast<GenericTypeParamType>(pair.first));
if (found == replacements.end()) {
// Can happen with invalid generic code.
continue;
}
addConstraint(ConstraintKind::Bind, found->second, pair.second,
locator);
}
}
// Map the generic parameters to their corresponding type variables.
llvm::SmallVector<Type, 2> arguments;
for (auto gp : decl->getInnermostGenericParamTypes()) {
auto found = replacements.find(
cast<GenericTypeParamType>(gp->getCanonicalType()));
assert(found != replacements.end() &&
"Missing generic parameter?");
arguments.push_back(found->second);
}
// FIXME: For some reason we can end up with unbound->getDecl()
// pointing at a generic TypeAliasDecl here. If we find a way to
// handle generic TypeAliases elsewhere, this can just become a
// call to BoundGenericType::get().
auto result =
TypeResolution::forInterface(
DC, None,
[](auto) -> Type { llvm_unreachable("should not be used"); },
[](auto &, auto) -> Type { llvm_unreachable("should not be used"); })
.applyUnboundGenericArguments(decl, parentTy, SourceLoc(), arguments);
if (!parentTy && !isTypeResolution) {
result = DC->mapTypeIntoContext(result);
}
return result;
}
static void checkNestedTypeConstraints(ConstraintSystem &cs, Type type,
ConstraintLocatorBuilder locator) {
// If this is a type defined inside of constrained extension, let's add all
// of the generic requirements to the constraint system to make sure that it's
// something we can use.
GenericTypeDecl *decl = nullptr;
Type parentTy;
SubstitutionMap subMap;
if (auto *NAT = dyn_cast<TypeAliasType>(type.getPointer())) {
decl = NAT->getDecl();
parentTy = NAT->getParent();
subMap = NAT->getSubstitutionMap();
} else if (auto *AGT = type->getAs<AnyGenericType>()) {
decl = AGT->getDecl();
parentTy = AGT->getParent();
// the context substitution map is fine here, since we can't be adding more
// info than that, unlike a typealias
}
if (!parentTy)
return;
// If this decl is generic, the constraints are handled when the generic
// parameters are applied, so we don't have to handle them here (which makes
// getting the right substitution maps easier).
if (!decl || decl->isGeneric())
return;
// struct A<T> {
// let foo: [T]
// }
//
// extension A : Codable where T: Codable {
// enum CodingKeys: String, CodingKey {
// case foo = "foo"
// }
// }
//
// Reference to `A.CodingKeys.foo` would point to `A` as an
// unbound generic type. Conditional requirements would be
// added when `A` is "opened". Les delay this check until then.
if (parentTy->hasUnboundGenericType())
return;
auto extension = dyn_cast<ExtensionDecl>(decl->getDeclContext());
if (extension && extension->isConstrainedExtension()) {
auto contextSubMap = parentTy->getContextSubstitutionMap(
extension->getParentModule(), extension->getSelfNominalTypeDecl());
if (!subMap) {
// The substitution map wasn't set above, meaning we should grab the map
// for the extension itself.
subMap = parentTy->getContextSubstitutionMap(extension->getParentModule(),
extension);
}
if (auto signature = decl->getGenericSignature()) {
cs.openGenericRequirements(
extension, signature, /*skipProtocolSelfConstraint*/ true, locator,
[&](Type type) {
// Why do we look in two substitution maps? We have to use the
// context substitution map to find types, because we need to
// avoid thinking about them when handling the constraints, or all
// the requirements in the signature become tautologies (if the
// extension has 'T == Int', subMap will map T -> Int, so the
// requirement becomes Int == Int no matter what the actual types
// are here). However, we need the conformances for the extension
// because the requirements might look like `T: P, T.U: Q`, where
// U is an associated type of protocol P.
return type.subst(QuerySubstitutionMap{contextSubMap},
LookUpConformanceInSubstitutionMap(subMap));
});
}
}
// And now make sure the parent is okay, for things like X<T>.Y.Z.
checkNestedTypeConstraints(cs, parentTy, locator);
}
Type ConstraintSystem::replaceInferableTypesWithTypeVars(
Type type, ConstraintLocatorBuilder locator) {
if (!type->hasUnboundGenericType() && !type->hasPlaceholder())
return type;
type = type.transform([&](Type type) -> Type {
if (auto unbound = type->getAs<UnboundGenericType>()) {
return openUnboundGenericType(unbound->getDecl(), unbound->getParent(),
locator, /*isTypeResolution=*/false);
} else if (auto *placeholderTy = type->getAs<PlaceholderType>()) {
if (auto *placeholderRepr = placeholderTy->getOriginator()
.dyn_cast<PlaceholderTypeRepr *>()) {
return createTypeVariable(
getConstraintLocator(
locator, LocatorPathElt::PlaceholderType(placeholderRepr)),
TVO_CanBindToNoEscape | TVO_PrefersSubtypeBinding |
TVO_CanBindToHole);
}
if (auto *var = placeholderTy->getOriginator().dyn_cast<VarDecl *>()) {
if (var->getName().hasDollarPrefix()) {
auto *repr =
new (type->getASTContext()) PlaceholderTypeRepr(var->getLoc());
return createTypeVariable(
getConstraintLocator(locator,
LocatorPathElt::PlaceholderType(repr)),
TVO_CanBindToNoEscape | TVO_PrefersSubtypeBinding |
TVO_CanBindToHole);
}
}
}
return type;
});
if (!type)
return ErrorType::get(getASTContext());
return type;
}
Type ConstraintSystem::openType(Type type, OpenedTypeMap &replacements) {
assert(!type->hasUnboundGenericType());
if (!type->hasTypeParameter())
return type;
return type.transform([&](Type type) -> Type {
assert(!type->is<GenericFunctionType>());
// Replace a generic type parameter with its corresponding type variable.
if (auto genericParam = type->getAs<GenericTypeParamType>()) {
auto known = replacements.find(
cast<GenericTypeParamType>(genericParam->getCanonicalType()));
// FIXME: This should be an assert, however protocol generic signatures
// drop outer generic parameters.
// assert(known != replacements.end());
if (known == replacements.end())
return ErrorType::get(getASTContext());
return known->second;
}
return type;
});
}
Type ConstraintSystem::openOpaqueType(OpaqueTypeArchetypeType *opaque,
ConstraintLocatorBuilder locator) {
auto opaqueDecl = opaque->getDecl();
auto opaqueLocatorKey = getOpenOpaqueLocator(locator, opaqueDecl);
// If we have already opened this opaque type, look in the known set of
// replacements.
auto knownReplacements = OpenedTypes.find(
getConstraintLocator(opaqueLocatorKey));
if (knownReplacements != OpenedTypes.end()) {
auto param = opaque->getInterfaceType()->castTo<GenericTypeParamType>();
for (const auto &replacement : knownReplacements->second) {
if (replacement.first->isEqual(param))
return replacement.second;
}
llvm_unreachable("Missing opaque type replacement");
}
// Open the generic signature of the opaque decl, and bind the "outer" generic
// params to our context. The remaining axes of freedom on the type variable
// corresponding to the underlying type should be the constraints on the
// underlying return type.
auto opaqueLocator = locator.withPathElement(
LocatorPathElt::OpenedOpaqueArchetype(opaqueDecl));
OpenedTypeMap replacements;
openGeneric(DC, opaqueDecl->getOpaqueInterfaceGenericSignature(),
opaqueLocator, replacements);
// If there is an outer generic signature, bind the outer parameters based
// on the substitutions in the opaque type.
auto subs = opaque->getSubstitutions();
if (auto genericSig = subs.getGenericSignature()) {
for (auto *genericParamPtr : genericSig.getGenericParams()) {
Type genericParam(genericParamPtr);
addConstraint(
ConstraintKind::Bind, openType(genericParam, replacements),
genericParam.subst(subs), opaqueLocator);
}
}
recordOpenedTypes(opaqueLocatorKey, replacements);
return openType(opaque->getInterfaceType(), replacements);
}
Type ConstraintSystem::openOpaqueType(Type type, ContextualTypePurpose context,
ConstraintLocatorBuilder locator) {
// Early return if `type` is `NULL` or if there are no opaque archetypes (in
// which case there is certainly nothing for us to do).
if (!type || !type->hasOpaqueArchetype())
return type;
auto inReturnContext = [](ContextualTypePurpose context) {
return context == CTP_ReturnStmt || context == CTP_ReturnSingleExpr;
};
if (!(context == CTP_Initialization || inReturnContext(context)))
return type;
auto shouldOpen = [&](OpaqueTypeArchetypeType *opaqueType) {
if (!inReturnContext(context))
return true;
if (auto *func = dyn_cast<AbstractFunctionDecl>(DC))
return opaqueType->getDecl()->isOpaqueReturnTypeOfFunction(func);
return true;
};
return type.transform([&](Type type) -> Type {
auto *opaqueType = type->getAs<OpaqueTypeArchetypeType>();
if (opaqueType && shouldOpen(opaqueType))
return openOpaqueType(opaqueType, locator);
return type;
});
}
FunctionType *ConstraintSystem::openFunctionType(
AnyFunctionType *funcType,
ConstraintLocatorBuilder locator,
OpenedTypeMap &replacements,
DeclContext *outerDC) {
if (auto *genericFn = funcType->getAs<GenericFunctionType>()) {
auto signature = genericFn->getGenericSignature();
openGenericParameters(outerDC, signature, replacements, locator);
openGenericRequirements(
outerDC, signature, /*skipProtocolSelfConstraint=*/false, locator,
[&](Type type) -> Type { return openType(type, replacements); });
funcType = genericFn->substGenericArgs(
[&](Type type) { return openType(type, replacements); });
}
return funcType->castTo<FunctionType>();
}
Optional<Type> ConstraintSystem::isArrayType(Type type) {
if (auto boundStruct = type->getAs<BoundGenericStructType>()) {
if (boundStruct->getDecl() == type->getASTContext().getArrayDecl())
return boundStruct->getGenericArgs()[0];
}
return None;
}
Optional<std::pair<Type, Type>> ConstraintSystem::isDictionaryType(Type type) {
if (auto boundStruct = type->getAs<BoundGenericStructType>()) {
if (boundStruct->getDecl() == type->getASTContext().getDictionaryDecl()) {
auto genericArgs = boundStruct->getGenericArgs();
return std::make_pair(genericArgs[0], genericArgs[1]);
}
}
return None;
}
Optional<Type> ConstraintSystem::isSetType(Type type) {
if (auto boundStruct = type->getAs<BoundGenericStructType>()) {
if (boundStruct->getDecl() == type->getASTContext().getSetDecl())
return boundStruct->getGenericArgs()[0];
}
return None;
}
Type ConstraintSystem::getFixedTypeRecursive(Type type,
TypeMatchOptions &flags,
bool wantRValue) const {
if (wantRValue)
type = type->getRValueType();
if (auto depMemType = type->getAs<DependentMemberType>()) {
if (!depMemType->getBase()->isTypeVariableOrMember()) return type;
// FIXME: Perform a more limited simplification?
Type newType = simplifyType(type);
if (newType.getPointer() == type.getPointer()) return type;
// Once we've simplified a dependent member type, we need to generate a
// new constraint.
flags |= TMF_GenerateConstraints;
return getFixedTypeRecursive(newType, flags, wantRValue);
}
if (auto typeVar = type->getAs<TypeVariableType>()) {
if (auto fixed = getFixedType(typeVar))
return getFixedTypeRecursive(fixed, flags, wantRValue);
return getRepresentative(typeVar);
}
return type;
}
TypeVariableType *ConstraintSystem::isRepresentativeFor(
TypeVariableType *typeVar, ConstraintLocator::PathElementKind kind) const {
// We only attempt to look for this if type variable is
// a representative.
if (getRepresentative(typeVar) != typeVar)
return nullptr;
auto &CG = getConstraintGraph();
auto result = CG.lookupNode(typeVar);
auto equivalence = result.first.getEquivalenceClass();
auto member = llvm::find_if(equivalence, [=](TypeVariableType *eq) {
auto *loc = eq->getImpl().getLocator();
if (!loc)
return false;
auto path = loc->getPath();
return !path.empty() && path.back().getKind() == kind;
});
if (member == equivalence.end())
return nullptr;
return *member;
}
static Optional<std::pair<VarDecl *, Type>>
getPropertyWrapperInformationFromOverload(
SelectedOverload resolvedOverload, DeclContext *DC,
llvm::function_ref<Optional<std::pair<VarDecl *, Type>>(VarDecl *)>
getInformation) {
if (auto *decl =
dyn_cast_or_null<VarDecl>(resolvedOverload.choice.getDeclOrNull())) {
if (auto declInformation = getInformation(decl)) {
Type type;
VarDecl *memberDecl;
std::tie(memberDecl, type) = *declInformation;
if (Type baseType = resolvedOverload.choice.getBaseType()) {
type =
baseType->getTypeOfMember(DC->getParentModule(), memberDecl, type);
}
return std::make_pair(decl, type);
}
}
return None;
}
Optional<std::pair<VarDecl *, Type>>
ConstraintSystem::getPropertyWrapperProjectionInfo(
SelectedOverload resolvedOverload) {
return getPropertyWrapperInformationFromOverload(
resolvedOverload, DC,
[](VarDecl *decl) -> Optional<std::pair<VarDecl *, Type>> {
if (!decl->hasAttachedPropertyWrapper())
return None;
auto projectionVar = decl->getPropertyWrapperProjectionVar();
if (!projectionVar)
return None;
return std::make_pair(projectionVar,
projectionVar->getInterfaceType());
});
}
Optional<std::pair<VarDecl *, Type>>
ConstraintSystem::getPropertyWrapperInformation(
SelectedOverload resolvedOverload) {
return getPropertyWrapperInformationFromOverload(
resolvedOverload, DC,
[](VarDecl *decl) -> Optional<std::pair<VarDecl *, Type>> {
if (!decl->hasAttachedPropertyWrapper())
return None;
auto backingTy = decl->getPropertyWrapperBackingPropertyType();
if (!backingTy)
return None;
return std::make_pair(decl, backingTy);
});
}
Optional<std::pair<VarDecl *, Type>>
ConstraintSystem::getWrappedPropertyInformation(
SelectedOverload resolvedOverload) {
return getPropertyWrapperInformationFromOverload(
resolvedOverload, DC,
[](VarDecl *decl) -> Optional<std::pair<VarDecl *, Type>> {
if (auto wrapped = decl->getOriginalWrappedProperty())
return std::make_pair(decl, wrapped->getInterfaceType());
return None;
});
}
/// Does a var or subscript produce an l-value?
///
/// \param baseType - the type of the base on which this object
/// is being accessed; must be null if and only if this is not
/// a type member
static bool
doesStorageProduceLValue(AbstractStorageDecl *storage, Type baseType,
DeclContext *useDC,
ConstraintLocator *memberLocator = nullptr) {
const DeclRefExpr *base = nullptr;
if (memberLocator) {
if (auto *const E = getAsExpr(memberLocator->getAnchor())) {
if (auto *MRE = dyn_cast<MemberRefExpr>(E)) {
base = dyn_cast<DeclRefExpr>(MRE->getBase());
} else if (auto *UDE = dyn_cast<UnresolvedDotExpr>(E)) {
base = dyn_cast<DeclRefExpr>(UDE->getBase());
}
}
}
// Unsettable storage decls always produce rvalues.
if (!storage->isSettableInSwift(useDC, base))
return false;
if (!storage->isSetterAccessibleFrom(useDC))
return false;
// If there is no base, or the base is an lvalue, then a reference
// produces an lvalue.
if (!baseType || baseType->is<LValueType>())
return true;
// The base is an rvalue type. The only way an accessor can
// produce an lvalue is if we have a property where both the
// getter and setter are nonmutating.
return (!storage->isGetterMutating() &&
!storage->isSetterMutating());
}
Type GetClosureType::operator()(const AbstractClosureExpr *expr) const {
if (auto closure = dyn_cast<ClosureExpr>(expr)) {
// Look through type bindings, if we have them.
auto mutableClosure = const_cast<ClosureExpr *>(closure);
if (cs.hasType(mutableClosure)) {
return cs.getFixedTypeRecursive(
cs.getType(mutableClosure), /*wantRValue=*/true);
}
return cs.getClosureTypeIfAvailable(closure);
}
return Type();
}
bool
ClosureIsolatedByPreconcurrency::operator()(const ClosureExpr *expr) const {
return expr->isIsolatedByPreconcurrency() ||
cs.preconcurrencyClosures.count(expr);
}
Type ConstraintSystem::getUnopenedTypeOfReference(
VarDecl *value, Type baseType, DeclContext *UseDC,
ConstraintLocator *memberLocator, bool wantInterfaceType,
bool adjustForPreconcurrency) {
return ConstraintSystem::getUnopenedTypeOfReference(
value, baseType, UseDC,
[&](VarDecl *var) -> Type {
if (Type type = getTypeIfAvailable(var))
return type;
if (!var->hasInterfaceType()) {
return ErrorType::get(getASTContext());
}
return wantInterfaceType ? var->getInterfaceType() : var->getType();
},
memberLocator, wantInterfaceType, adjustForPreconcurrency,
GetClosureType{*this},
ClosureIsolatedByPreconcurrency{*this});
}
Type ConstraintSystem::getUnopenedTypeOfReference(
VarDecl *value, Type baseType, DeclContext *UseDC,
llvm::function_ref<Type(VarDecl *)> getType,
ConstraintLocator *memberLocator,
bool wantInterfaceType, bool adjustForPreconcurrency,
llvm::function_ref<Type(const AbstractClosureExpr *)> getClosureType,
llvm::function_ref<bool(const ClosureExpr *)> isolatedByPreconcurrency) {
Type requestedType =
getType(value)->getWithoutSpecifierType()->getReferenceStorageReferent();
// Adjust the type for concurrency if requested.
if (adjustForPreconcurrency)
requestedType = adjustVarTypeForConcurrency(
requestedType, value, UseDC, getClosureType, isolatedByPreconcurrency);
// If we're dealing with contextual types, and we referenced this type from
// a different context, map the type.
if (!wantInterfaceType && requestedType->hasArchetype()) {
auto valueDC = value->getDeclContext();
if (valueDC != UseDC) {
Type mapped = requestedType->mapTypeOutOfContext();
requestedType = UseDC->mapTypeIntoContext(mapped);
}
}
// Qualify storage declarations with an lvalue when appropriate.
// Otherwise, they yield rvalues (and the access must be a load).
if (doesStorageProduceLValue(value, baseType, UseDC, memberLocator) &&
!requestedType->hasError()) {
return LValueType::get(requestedType);
}
return requestedType;
}
void ConstraintSystem::recordOpenedTypes(
ConstraintLocatorBuilder locator,
const OpenedTypeMap &replacements) {
if (replacements.empty())
return;
// If the last path element is an archetype or associated type, ignore it.
SmallVector<LocatorPathElt, 2> pathElts;
auto anchor = locator.getLocatorParts(pathElts);
if (!pathElts.empty() &&
pathElts.back().getKind() == ConstraintLocator::GenericParameter)
return;
// If the locator is empty, ignore it.
if (!anchor && pathElts.empty())
return;
ConstraintLocator *locatorPtr = getConstraintLocator(locator);
assert(locatorPtr && "No locator for opened types?");
#if false
assert(std::find_if(OpenedTypes.begin(), OpenedTypes.end(),
[&](const std::pair<ConstraintLocator *,
ArrayRef<OpenedType>> &entry) {
return entry.first == locatorPtr;
}) == OpenedTypes.end() &&
"already registered opened types for this locator");
#endif
OpenedType* openedTypes
= Allocator.Allocate<OpenedType>(replacements.size());
std::copy(replacements.begin(), replacements.end(), openedTypes);
OpenedTypes.insert(
{locatorPtr, llvm::makeArrayRef(openedTypes, replacements.size())});
}
/// Determine how many levels of argument labels should be removed from the
/// function type when referencing the given declaration.
static unsigned getNumRemovedArgumentLabels(ValueDecl *decl,
bool isCurriedInstanceReference,
FunctionRefKind functionRefKind) {
unsigned numParameterLists = decl->getNumCurryLevels();
switch (functionRefKind) {
case FunctionRefKind::Unapplied:
case FunctionRefKind::Compound:
// Always remove argument labels from unapplied references and references
// that use a compound name.
return numParameterLists;
case FunctionRefKind::SingleApply:
// If we have fewer than two parameter lists, leave the labels.
if (numParameterLists < 2)
return 0;
// If this is a curried reference to an instance method, where 'self' is
// being applied, e.g., "ClassName.instanceMethod(self)", remove the
// argument labels from the resulting function type. The 'self' parameter is
// always unlabeled, so this operation is a no-op for the actual application.
return isCurriedInstanceReference ? numParameterLists : 1;
case FunctionRefKind::DoubleApply:
// Never remove argument labels from a double application.
return 0;
}
llvm_unreachable("Unhandled FunctionRefKind in switch.");
}
/// Determine the number of applications
static unsigned getNumApplications(
ValueDecl *decl, bool hasAppliedSelf, FunctionRefKind functionRefKind) {
switch (functionRefKind) {
case FunctionRefKind::Unapplied:
case FunctionRefKind::Compound:
return 0 + hasAppliedSelf;
case FunctionRefKind::SingleApply:
return 1 + hasAppliedSelf;
case FunctionRefKind::DoubleApply:
return 2;
}
llvm_unreachable("Unhandled FunctionRefKind in switch.");
}
/// Replaces property wrapper types in the parameter list of the given function type
/// with the wrapped-value or projected-value types (depending on argument label).
static FunctionType *
unwrapPropertyWrapperParameterTypes(ConstraintSystem &cs, AbstractFunctionDecl *funcDecl,
FunctionRefKind functionRefKind, FunctionType *functionType,
ConstraintLocatorBuilder locator) {
// Only apply property wrappers to unapplied references to functions.
if (!(functionRefKind == FunctionRefKind::Compound ||
functionRefKind == FunctionRefKind::Unapplied)) {
return functionType;
}
auto *paramList = funcDecl->getParameters();
auto paramTypes = functionType->getParams();
SmallVector<AnyFunctionType::Param, 4> adjustedParamTypes;
DeclNameLoc nameLoc;
auto *ref = getAsExpr(locator.getAnchor());
if (auto *declRef = dyn_cast<DeclRefExpr>(ref)) {
nameLoc = declRef->getNameLoc();
} else if (auto *dotExpr = dyn_cast<UnresolvedDotExpr>(ref)) {
nameLoc = dotExpr->getNameLoc();
} else if (auto *overloadedRef = dyn_cast<OverloadedDeclRefExpr>(ref)) {
nameLoc = overloadedRef->getNameLoc();
} else if (auto *memberExpr = dyn_cast<UnresolvedMemberExpr>(ref)) {
nameLoc = memberExpr->getNameLoc();
}
for (unsigned i : indices(*paramList)) {
Identifier argLabel;
if (functionRefKind == FunctionRefKind::Compound) {
auto &context = cs.getASTContext();
auto argLabelLoc = nameLoc.getArgumentLabelLoc(i);
auto argLabelToken = Lexer::getTokenAtLocation(context.SourceMgr, argLabelLoc);
argLabel = context.getIdentifier(argLabelToken.getText());
}
auto *paramDecl = paramList->get(i);
if (!paramDecl->hasAttachedPropertyWrapper() && !argLabel.hasDollarPrefix()) {
adjustedParamTypes.push_back(paramTypes[i]);
continue;
}
auto *wrappedType = cs.createTypeVariable(cs.getConstraintLocator(locator), 0);
auto paramType = paramTypes[i].getParameterType();
auto paramLabel = paramTypes[i].getLabel();
auto paramInternalLabel = paramTypes[i].getInternalLabel();
adjustedParamTypes.push_back(AnyFunctionType::Param(
wrappedType, paramLabel, ParameterTypeFlags(), paramInternalLabel));
cs.applyPropertyWrapperToParameter(paramType, wrappedType, paramDecl, argLabel,
ConstraintKind::Equal, locator);
}
return FunctionType::get(adjustedParamTypes, functionType->getResult(),
functionType->getExtInfo());
}
/// Determine whether the given locator is for a witness or requirement.
static bool isRequirementOrWitness(const ConstraintLocatorBuilder &locator) {
if (auto last = locator.last()) {
return last->getKind() == ConstraintLocator::ProtocolRequirement ||
last->getKind() == ConstraintLocator::Witness;
}
return false;
}
AnyFunctionType *ConstraintSystem::adjustFunctionTypeForConcurrency(
AnyFunctionType *fnType, ValueDecl *decl, DeclContext *dc,
unsigned numApplies, bool isMainDispatchQueue,
OpenedTypeMap &replacements) {
return swift::adjustFunctionTypeForConcurrency(
fnType, decl, dc, numApplies, isMainDispatchQueue,
GetClosureType{*this}, ClosureIsolatedByPreconcurrency{*this},
[&](Type type) {
if (replacements.empty())
return type;
return openType(type, replacements);
});
}
/// For every parameter in \p type that has an error type, replace that
/// parameter's type by a placeholder type, where \p value is the declaration
/// that declared \p type. This is useful for code completion so we can match
/// the types we do know instead of bailing out completely because \p type
/// contains an error type.
static Type replaceParamErrorTypeByPlaceholder(Type type, ValueDecl *value) {
if (!type->is<AnyFunctionType>() || !isa<AbstractFunctionDecl>(value)) {
return type;
}
auto funcType = type->castTo<AnyFunctionType>();
auto funcDecl = cast<AbstractFunctionDecl>(value);
auto declParams = funcDecl->getParameters();
auto typeParams = funcType->getParams();
assert(declParams->size() == typeParams.size());
SmallVector<AnyFunctionType::Param, 4> newParams;
newParams.reserve(declParams->size());
for (auto i : indices(typeParams)) {
AnyFunctionType::Param param = typeParams[i];
if (param.getPlainType()->is<ErrorType>()) {
auto paramDecl = declParams->get(i);
auto placeholder =
PlaceholderType::get(paramDecl->getASTContext(), paramDecl);
newParams.push_back(param.withType(placeholder));
} else {
newParams.push_back(param);
}
}
assert(newParams.size() == declParams->size());
return FunctionType::get(newParams, funcType->getResult());
}
DeclReferenceType
ConstraintSystem::getTypeOfReference(ValueDecl *value,
FunctionRefKind functionRefKind,
ConstraintLocatorBuilder locator,
DeclContext *useDC) {
if (value->getDeclContext()->isTypeContext() && isa<FuncDecl>(value)) {
// Unqualified lookup can find operator names within nominal types.
auto func = cast<FuncDecl>(value);
assert(func->isOperator() && "Lookup should only find operators");
OpenedTypeMap replacements;
AnyFunctionType *funcType = func->getInterfaceType()
->castTo<AnyFunctionType>();
auto openedType = openFunctionType(
funcType, locator, replacements, func->getDeclContext());
// If we opened up any type variables, record the replacements.
recordOpenedTypes(locator, replacements);
// If this is a method whose result type is dynamic Self, replace
// DynamicSelf with the actual object type.
if (func->getResultInterfaceType()->hasDynamicSelfType()) {
auto params = openedType->getParams();
assert(params.size() == 1);
Type selfTy = params.front().getPlainType()->getMetatypeInstanceType();
openedType = openedType->replaceCovariantResultType(selfTy, 2)
->castTo<FunctionType>();
}
auto origOpenedType = openedType;
if (!isRequirementOrWitness(locator)) {
unsigned numApplies = getNumApplications(value, false, functionRefKind);
openedType = cast<FunctionType>(adjustFunctionTypeForConcurrency(
origOpenedType, func, useDC, numApplies, false, replacements));
}
// The reference implicitly binds 'self'.
return {origOpenedType, openedType,
origOpenedType->getResult(), openedType->getResult()};
}
// Unqualified reference to a local or global function.
if (auto funcDecl = dyn_cast<AbstractFunctionDecl>(value)) {
OpenedTypeMap replacements;
auto funcType = funcDecl->getInterfaceType()->castTo<AnyFunctionType>();
auto numLabelsToRemove = getNumRemovedArgumentLabels(
funcDecl, /*isCurriedInstanceReference=*/false, functionRefKind);
auto openedType = openFunctionType(funcType, locator, replacements,
funcDecl->getDeclContext())
->removeArgumentLabels(numLabelsToRemove);
openedType = unwrapPropertyWrapperParameterTypes(*this, funcDecl, functionRefKind, openedType->castTo<FunctionType>(), locator);
auto origOpenedType = openedType;
if (!isRequirementOrWitness(locator)) {
unsigned numApplies = getNumApplications(
funcDecl, false, functionRefKind);
openedType = cast<FunctionType>(adjustFunctionTypeForConcurrency(
origOpenedType->castTo<FunctionType>(), funcDecl, useDC,
numApplies, false, replacements));
}
if (isForCodeCompletion() && openedType->hasError()) {
// In code completion, replace error types by placeholder types so we can
// match the types we know instead of bailing out completely.
openedType = replaceParamErrorTypeByPlaceholder(openedType, value);
}
// If we opened up any type variables, record the replacements.
recordOpenedTypes(locator, replacements);
return { origOpenedType, openedType, origOpenedType, openedType };
}
// Unqualified reference to a type.
if (auto typeDecl = dyn_cast<TypeDecl>(value)) {
// Resolve the reference to this type declaration in our current context.
auto type =
TypeResolution::forInterface(useDC, TypeResolverContext::InExpression,
/*unboundTyOpener*/ nullptr,
/*placeholderHandler*/ nullptr)
.resolveTypeInContext(typeDecl, /*foundDC*/ nullptr,
/*isSpecialized=*/false);
type = useDC->mapTypeIntoContext(type);
checkNestedTypeConstraints(*this, type, locator);
// Convert any placeholder types and open generics.
type = replaceInferableTypesWithTypeVars(type, locator);
// Module types are not wrapped in metatypes.
if (type->is<ModuleType>())
return { type, type, type, type };
// If it's a value reference, refer to the metatype.
type = MetatypeType::get(type);
return { type, type, type, type };
}
// Only remaining case: unqualified reference to a property.
auto *varDecl = cast<VarDecl>(value);
// Determine the type of the value, opening up that type if necessary.
// FIXME: @preconcurrency
bool wantInterfaceType = !varDecl->getDeclContext()->isLocalContext();
Type valueType =
getUnopenedTypeOfReference(varDecl, Type(), useDC, /*base=*/nullptr,
wantInterfaceType);
assert(!valueType->hasUnboundGenericType() &&
!valueType->hasTypeParameter());
return { valueType, valueType, valueType, valueType };
}
/// Bind type variables for archetypes that are determined from
/// context.
///
/// For example, if we are opening a generic function type
/// nested inside another function, we must bind the outer
/// generic parameters to context archetypes, because the
/// nested function can "capture" these outer generic parameters.
///
/// Another case where this comes up is if a generic type is
/// nested inside a function. We don't support codegen for this
/// yet, but again we need to bind any outer generic parameters
/// to context archetypes, because they're not free.
///
/// A final case we have to handle, even though it is invalid, is
/// when a type is nested inside another protocol. We bind the
/// protocol type variable for the protocol Self to an unresolved
/// type, since it will conform to anything. This of course makes
/// no sense, but we can't leave the type variable dangling,
/// because then we crash later.
///
/// If we ever do want to allow nominal types to be nested inside
/// protocols, the key is to set their declared type to a
/// NominalType whose parent is the 'Self' generic parameter, and
/// not the ProtocolType. Then, within a conforming type context,
/// we can 'reparent' the NominalType to that concrete type, and
/// resolve references to associated types inside that NominalType
/// relative to this concrete 'Self' type.
///
/// Also, of course IRGen would have to know to store the 'Self'
/// metadata as an extra hidden generic parameter in the metadata
/// of such a type, etc.
static void bindArchetypesFromContext(
ConstraintSystem &cs,
DeclContext *outerDC,
ConstraintLocator *locatorPtr,
const OpenedTypeMap &replacements) {
auto bindPrimaryArchetype = [&](Type paramTy, Type contextTy) {
auto found = replacements.find(cast<GenericTypeParamType>(
paramTy->getCanonicalType()));
// We might not have a type variable for this generic parameter
// because either we're opening up an UnboundGenericType,
// in which case we only want to infer the innermost generic
// parameters, or because this generic parameter was constrained
// away into a concrete type.
if (found != replacements.end()) {
auto typeVar = found->second;
cs.addConstraint(ConstraintKind::Bind, typeVar, contextTy,
locatorPtr);
}
};
// Find the innermost non-type context.
for (const auto *parentDC = outerDC;
!parentDC->isModuleScopeContext();
parentDC = parentDC->getParent()) {
if (parentDC->isTypeContext()) {
if (parentDC != outerDC && parentDC->getSelfProtocolDecl()) {
auto selfTy = parentDC->getSelfInterfaceType();
auto contextTy = cs.getASTContext().TheUnresolvedType;
bindPrimaryArchetype(selfTy, contextTy);
}
continue;
}
auto genericSig = parentDC->getGenericSignatureOfContext();
for (auto *paramTy : genericSig.getGenericParams()) {
Type contextTy = cs.DC->mapTypeIntoContext(paramTy);
bindPrimaryArchetype(paramTy, contextTy);
}
break;
}
}
void ConstraintSystem::openGeneric(
DeclContext *outerDC,
GenericSignature sig,
ConstraintLocatorBuilder locator,
OpenedTypeMap &replacements) {
if (!sig)
return;
openGenericParameters(outerDC, sig, replacements, locator);
// Add the requirements as constraints.
openGenericRequirements(
outerDC, sig, /*skipProtocolSelfConstraint=*/false, locator,
[&](Type type) { return openType(type, replacements); });
}
void ConstraintSystem::openGenericParameters(DeclContext *outerDC,
GenericSignature sig,
OpenedTypeMap &replacements,
ConstraintLocatorBuilder locator) {
assert(sig);
// Create the type variables for the generic parameters.
for (auto gp : sig.getGenericParams()) {
(void)openGenericParameter(outerDC, gp, replacements, locator);
}
auto *baseLocator = getConstraintLocator(
locator.withPathElement(LocatorPathElt::OpenedGeneric(sig)));
bindArchetypesFromContext(*this, outerDC, baseLocator, replacements);
}
TypeVariableType *ConstraintSystem::openGenericParameter(
DeclContext *outerDC, GenericTypeParamType *parameter,
OpenedTypeMap &replacements, ConstraintLocatorBuilder locator) {
auto *paramLocator = getConstraintLocator(
locator.withPathElement(LocatorPathElt::GenericParameter(parameter)));
auto typeVar = createTypeVariable(paramLocator, TVO_PrefersSubtypeBinding |
TVO_CanBindToHole);
auto result = replacements.insert(std::make_pair(
cast<GenericTypeParamType>(parameter->getCanonicalType()), typeVar));
assert(result.second);
(void)result;
return typeVar;
}
void ConstraintSystem::openGenericRequirements(
DeclContext *outerDC, GenericSignature signature,
bool skipProtocolSelfConstraint, ConstraintLocatorBuilder locator,
llvm::function_ref<Type(Type)> substFn) {
auto requirements = signature.getRequirements();
for (unsigned pos = 0, n = requirements.size(); pos != n; ++pos) {
auto openedGenericLoc =
locator.withPathElement(LocatorPathElt::OpenedGeneric(signature));
openGenericRequirement(outerDC, pos, requirements[pos],
skipProtocolSelfConstraint, openedGenericLoc,
substFn);
}
}
void ConstraintSystem::openGenericRequirement(
DeclContext *outerDC, unsigned index, const Requirement &req,
bool skipProtocolSelfConstraint, ConstraintLocatorBuilder locator,
llvm::function_ref<Type(Type)> substFn) {
Optional<Requirement> openedReq;
auto openedFirst = substFn(req.getFirstType());
auto kind = req.getKind();
switch (kind) {
case RequirementKind::SameCount:
llvm_unreachable("Same-count requirement not supported here");
case RequirementKind::Conformance: {
auto protoDecl = req.getProtocolDecl();
// Determine whether this is the protocol 'Self' constraint we should
// skip.
if (skipProtocolSelfConstraint && protoDecl == outerDC &&
protoDecl->getSelfInterfaceType()->isEqual(req.getFirstType()))
return;
openedReq = Requirement(kind, openedFirst, req.getSecondType());
break;
}
case RequirementKind::Superclass:
case RequirementKind::SameType:
openedReq = Requirement(kind, openedFirst, substFn(req.getSecondType()));
break;
case RequirementKind::Layout:
openedReq = Requirement(kind, openedFirst, req.getLayoutConstraint());
break;
}
addConstraint(*openedReq,
locator.withPathElement(
LocatorPathElt::TypeParameterRequirement(index, kind)));
}
/// Add the constraint on the type used for the 'Self' type for a member
/// reference.
///
/// \param cs The constraint system.
///
/// \param objectTy The type of the object that we're using to access the
/// member.
///
/// \param selfTy The instance type of the context in which the member is
/// declared.
static void addSelfConstraint(ConstraintSystem &cs, Type objectTy, Type selfTy,
ConstraintLocatorBuilder locator){
assert(!selfTy->is<ProtocolType>());
// Otherwise, use a subtype constraint for classes to cope with inheritance.
if (selfTy->getClassOrBoundGenericClass()) {
cs.addConstraint(ConstraintKind::Subtype, objectTy, selfTy,
cs.getConstraintLocator(locator));
return;
}
// Otherwise, the types must be equivalent.
cs.addConstraint(ConstraintKind::Bind, objectTy, selfTy,
cs.getConstraintLocator(locator));
}
Type constraints::getDynamicSelfReplacementType(
Type baseObjTy, const ValueDecl *member, ConstraintLocator *memberLocator) {
// Constructions must always have their dynamic 'Self' result type replaced
// with the base object type, 'super' or not.
if (isa<ConstructorDecl>(member))
return baseObjTy;
const SuperRefExpr *SuperExpr = nullptr;
if (auto *E = getAsExpr(memberLocator->getAnchor())) {
if (auto *LE = dyn_cast<LookupExpr>(E)) {
SuperExpr = dyn_cast<SuperRefExpr>(LE->getBase());
} else if (auto *UDE = dyn_cast<UnresolvedDotExpr>(E)) {
SuperExpr = dyn_cast<SuperRefExpr>(UDE->getBase());
}
}
// For anything else that isn't 'super', we want it to be the base
// object type.
if (!SuperExpr)
return baseObjTy;
// 'super' is special in that we actually want dynamic 'Self' to behave
// as if the base were 'self'.
const auto *selfDecl = SuperExpr->getSelf();
return selfDecl->getDeclContext()
->getInnermostTypeContext()
->mapTypeIntoContext(selfDecl->getInterfaceType())
->getMetatypeInstanceType();
}
/// Determine whether this locator refers to a member of "DispatchQueue.main",
/// which is a special dispatch queue that executes its work on the main actor.
static bool isMainDispatchQueueMember(ConstraintLocator *locator) {
if (!locator)
return false;
if (locator->getPath().size() != 1 ||
!locator->isLastElement<LocatorPathElt::Member>())
return false;
auto expr = locator->getAnchor().dyn_cast<Expr *>();
if (!expr)
return false;
auto outerUnresolvedDot = dyn_cast<UnresolvedDotExpr>(expr);
if (!outerUnresolvedDot)
return false;
if (!isDispatchQueueOperationName(
outerUnresolvedDot->getName().getBaseName().userFacingName()))
return false;
auto innerUnresolvedDot = dyn_cast<UnresolvedDotExpr>(
outerUnresolvedDot->getBase());
if (!innerUnresolvedDot)
return false;
if (innerUnresolvedDot->getName().getBaseName().userFacingName() != "main")
return false;
auto typeExpr = dyn_cast<TypeExpr>(innerUnresolvedDot->getBase());
if (!typeExpr)
return false;
auto typeRepr = typeExpr->getTypeRepr();
if (!typeRepr)
return false;
auto identTypeRepr = dyn_cast<IdentTypeRepr>(typeRepr);
if (!identTypeRepr)
return false;
auto components = identTypeRepr->getComponentRange();
if (components.empty())
return false;
if (components.back()->getNameRef().getBaseName().userFacingName() !=
"DispatchQueue")
return false;
return true;
}
/// Type-erase occurrences of covariant 'Self'-rooted type parameters to their
/// most specific non-dependent bounds throughout the given type, using
/// \p baseTy as the existential base object type.
///
/// \note If a 'Self'-rooted type parameter is bound to a concrete type, this
/// routine will recurse into the concrete type.
static Type
typeEraseExistentialSelfReferences(
Type refTy, Type baseTy,
TypePosition outermostPosition) {
assert(baseTy->isExistentialType());
if (!refTy->hasTypeParameter()) {
return refTy;
}
const auto existentialSig =
baseTy->getASTContext().getOpenedExistentialSignature(baseTy,
GenericSignature());
unsigned metatypeDepth = 0;
/// Check whether the given type has a reference to the generic parameter
/// that we are erasing.
auto hasErasedGenericParameter = [&](Type type) {
if (!type->hasTypeParameter())
return false;
return type.findIf([&](Type type) {
if (auto gp = type->getAs<GenericTypeParamType>())
return gp->getDepth() == 0;
return false;
});
};
std::function<Type(Type, TypePosition)> transformFn;
transformFn = [&](Type type, TypePosition initialPos) -> Type {
return type.transformWithPosition(
initialPos, [&](TypeBase *t, TypePosition currPos) -> Optional<Type> {
if (!t->hasTypeParameter()) {
return Type(t);
}
if (t->is<MetatypeType>()) {
const auto instanceTy = t->getMetatypeInstanceType();
++metatypeDepth;
const auto erasedTy = transformFn(instanceTy, currPos);
--metatypeDepth;
if (instanceTy.getPointer() == erasedTy.getPointer()) {
return Type(t);
}
return Type(ExistentialMetatypeType::get(erasedTy));
}
// Opaque types whose substitutions involve this type parameter are
// erased to their upper bound.
if (auto opaque = dyn_cast<OpaqueTypeArchetypeType>(t)) {
for (auto replacementType :
opaque->getSubstitutions().getReplacementTypes()) {
if (hasErasedGenericParameter(replacementType)) {
Type interfaceType = opaque->getInterfaceType();
auto genericSig =
opaque->getDecl()->getOpaqueInterfaceGenericSignature();
return genericSig->getNonDependentUpperBounds(interfaceType);
}
}
}
if (!t->isTypeParameter()) {
// Recurse.
return None;
}
if (t->getRootGenericParam()->getDepth() > 0) {
return Type(t);
}
// If the type parameter is beyond the domain of the existential generic
// signature, ignore it.
if (!existentialSig->isValidTypeParameter(t)) {
return Type(t);
}
// If the type parameter is bound to a concrete type, recurse into it.
if (const auto concreteTy = existentialSig->getConcreteType(t)) {
const auto erasedTy = transformFn(concreteTy, currPos);
if (erasedTy.getPointer() == concreteTy.getPointer()) {
// Don't return the concrete type if we haven't type-erased anything
// inside it, or else we might inadvertently transform a normal
// metatype into an existential one.
return Type(t);
}
return erasedTy;
}
switch (currPos) {
case TypePosition::Covariant:
break;
case TypePosition::Contravariant:
case TypePosition::Invariant:
return Type(t);
}
Type erasedTy;
// The upper bounds of 'Self' is the existential base type.
if (t->is<GenericTypeParamType>()) {
erasedTy = baseTy;
} else {
erasedTy = existentialSig->getNonDependentUpperBounds(t);
}
if (metatypeDepth) {
if (const auto existential = erasedTy->getAs<ExistentialType>())
return existential->getConstraintType();
}
return erasedTy;
});
};
return transformFn(refTy, outermostPosition);
}
Type constraints::typeEraseOpenedExistentialReference(
Type type, Type existentialBaseType, TypeVariableType *openedTypeVar,
TypePosition outermostPosition) {
Type selfGP = GenericTypeParamType::get(false, 0, 0, type->getASTContext());
// First, temporarily reconstitute the 'Self' generic parameter.
type = type.transformRec([&](TypeBase *t) -> Optional<Type> {
// Don't recurse into children unless we have to.
if (!type->hasTypeVariable())
return Type(t);
if (isa<TypeVariableType>(t) && t->isEqual(openedTypeVar))
return selfGP;
// Recurse.
return None;
});
// Then, type-erase occurrences of covariant 'Self'-rooted type parameters.
type = typeEraseExistentialSelfReferences(type, existentialBaseType,
outermostPosition);
// Finally, swap the 'Self'-corresponding type variable back in.
return type.transformRec([&](TypeBase *t) -> Optional<Type> {
// Don't recurse into children unless we have to.
if (!type->hasTypeParameter())
return Type(t);
if (isa<GenericTypeParamType>(t) && t->isEqual(selfGP))
return Type(openedTypeVar);
// Recurse.
return None;
});
}
Type ConstraintSystem::getMemberReferenceTypeFromOpenedType(
Type &openedType, Type baseObjTy, ValueDecl *value, DeclContext *outerDC,
ConstraintLocator *locator, bool hasAppliedSelf,
bool isStaticMemberRefOnProtocol, bool isDynamicResult,
OpenedTypeMap &replacements) {
Type type = openedType;
// Cope with dynamic 'Self'.
if (!outerDC->getSelfProtocolDecl()) {
const auto replacementTy =
getDynamicSelfReplacementType(baseObjTy, value, locator);
if (auto func = dyn_cast<AbstractFunctionDecl>(value)) {
if (func->hasDynamicSelfResult() &&
!baseObjTy->getOptionalObjectType()) {
type = type->replaceCovariantResultType(replacementTy, 2);
}
} else if (auto *decl = dyn_cast<SubscriptDecl>(value)) {
if (decl->getElementInterfaceType()->hasDynamicSelfType()) {
type = type->replaceCovariantResultType(replacementTy, 2);
}
} else if (auto *decl = dyn_cast<VarDecl>(value)) {
if (decl->getValueInterfaceType()->hasDynamicSelfType()) {
type = type->replaceCovariantResultType(replacementTy, 1);
}
}
}
// Check if we need to apply a layer of optionality to the uncurried type.
if (!isRequirementOrWitness(locator)) {
if (isDynamicResult || value->getAttrs().hasAttribute<OptionalAttr>()) {
const auto applyOptionality = [&](FunctionType *fnTy) -> Type {
Type resultTy;
// 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 (isa<SubscriptDecl>(value)) {
auto *innerFn = fnTy->getResult()->castTo<FunctionType>();
resultTy = FunctionType::get(
innerFn->getParams(),
OptionalType::get(innerFn->getResult()->getRValueType()),
innerFn->getExtInfo());
} else {
resultTy = OptionalType::get(fnTy->getResult()->getRValueType());
}
return FunctionType::get(fnTy->getParams(), resultTy,
fnTy->getExtInfo());
};
// FIXME: Refactor 'replaceCovariantResultType' not to rely on the passed
// uncurry level.
//
// This is done after handling dynamic 'Self' to make
// 'replaceCovariantResultType' work, so we have to transform both types.
openedType = applyOptionality(openedType->castTo<FunctionType>());
type = applyOptionality(type->castTo<FunctionType>());
}
}
if (hasAppliedSelf) {
// For a static member referenced through a metatype or an instance
// member referenced through an instance, strip off the 'self'.
type = type->castTo<FunctionType>()->getResult();
} else {
// For an unbound instance method reference, replace the 'Self'
// parameter with the base type.
type = type->replaceSelfParameterType(baseObjTy);
}
// Superficially, protocol members with an existential base are accessed
// directly on the existential, and not an opened archetype, and we may have
// to adjust the type of the reference (e.g. covariant 'Self' type-erasure) to
// support certain accesses.
if (!isStaticMemberRefOnProtocol && !isDynamicResult &&
baseObjTy->isExistentialType() && outerDC->getSelfProtocolDecl() &&
// If there are no type variables, there were no references to 'Self'.
type->hasTypeVariable()) {
auto getResultType = [](Type type) {
if (auto *funcTy = type->getAs<FunctionType>())
return funcTy->getResult();
return type;
};
auto nonErasedResultTy = getResultType(type);
const auto selfGP = cast<GenericTypeParamType>(
outerDC->getSelfInterfaceType()->getCanonicalType());
auto openedTypeVar = replacements.lookup(selfGP);
type = typeEraseOpenedExistentialReference(type, baseObjTy, openedTypeVar,
TypePosition::Covariant);
if (!hasFixFor(locator) &&
AddExplicitExistentialCoercion::isRequired(
*this, nonErasedResultTy,
[&](TypeVariableType *typeVar) {
return openedTypeVar == typeVar ? baseObjTy : Optional<Type>();
},
locator)) {
recordFix(AddExplicitExistentialCoercion::create(
*this, getResultType(type), locator));
}
}
// Construct an idealized parameter type of the initializer associated
// with object literal, which generally simplifies the first label
// (e.g. "colorLiteralRed:") by stripping all the redundant stuff about
// literals (leaving e.g. "red:").
{
auto anchor = locator->getAnchor();
if (auto *OLE = getAsExpr<ObjectLiteralExpr>(anchor)) {
auto fnType = type->castTo<FunctionType>();
SmallVector<AnyFunctionType::Param, 4> params(fnType->getParams().begin(),
fnType->getParams().end());
switch (OLE->getLiteralKind()) {
case ObjectLiteralExpr::colorLiteral:
params[0] = params[0].withLabel(Context.getIdentifier("red"));
break;
case ObjectLiteralExpr::fileLiteral:
case ObjectLiteralExpr::imageLiteral:
params[0] = params[0].withLabel(Context.getIdentifier("resourceName"));
break;
}
type =
FunctionType::get(params, fnType->getResult(), fnType->getExtInfo());
}
}
if (isForCodeCompletion() && type->hasError()) {
// In code completion, replace error types by placeholder types so we can
// match the types we know instead of bailing out completely.
type = replaceParamErrorTypeByPlaceholder(type, value);
}
return type;
}
DeclReferenceType
ConstraintSystem::getTypeOfMemberReference(
Type baseTy, ValueDecl *value, DeclContext *useDC,
bool isDynamicResult,
FunctionRefKind functionRefKind,
ConstraintLocator *locator,
OpenedTypeMap *replacementsPtr) {
// Figure out the instance type used for the base.
Type resolvedBaseTy = getFixedTypeRecursive(baseTy, /*wantRValue=*/true);
// If the base is a module type, just use the type of the decl.
if (resolvedBaseTy->is<ModuleType>()) {
return getTypeOfReference(value, functionRefKind, locator, useDC);
}
// Check to see if the self parameter is applied, in which case we'll want to
// strip it off later.
auto hasAppliedSelf = doesMemberRefApplyCurriedSelf(resolvedBaseTy, value);
auto baseObjTy = resolvedBaseTy->getMetatypeInstanceType();
FunctionType::Param baseObjParam(baseObjTy);
// Indicates whether this is a valid reference to a static member on a
// protocol metatype. Such a reference is only valid if performed through
// leading dot syntax e.g. `foo(.bar)` where implicit base is a protocol
// metatype and `bar` is static member declared in a protocol or its
// extension.
bool isStaticMemberRefOnProtocol = false;
if (resolvedBaseTy->is<MetatypeType>() && baseObjTy->isExistentialType() &&
value->isStatic()) {
isStaticMemberRefOnProtocol =
locator->isLastElement<LocatorPathElt::UnresolvedMember>();
}
if (auto *typeDecl = dyn_cast<TypeDecl>(value)) {
assert(!isa<ModuleDecl>(typeDecl) && "Nested module?");
auto memberTy = TypeChecker::substMemberTypeWithBase(DC->getParentModule(),
typeDecl, baseObjTy);
// If the member type is a constraint, e.g. because the
// reference is to a typealias with an underlying protocol
// or composition type, the member reference has existential
// type.
if (memberTy->isConstraintType())
memberTy = ExistentialType::get(memberTy);
checkNestedTypeConstraints(*this, memberTy, locator);
// Convert any placeholders and open any generics.
memberTy = replaceInferableTypesWithTypeVars(memberTy, locator);
// Wrap it in a metatype.
memberTy = MetatypeType::get(memberTy);
auto openedType = FunctionType::get({baseObjParam}, memberTy);
return { openedType, openedType, memberTy, memberTy };
}
// Figure out the declaration context to use when opening this type.
DeclContext *innerDC = value->getInnermostDeclContext();
DeclContext *outerDC = value->getDeclContext();
// Open the type of the generic function or member of a generic type.
Type openedType;
OpenedTypeMap localReplacements;
auto &replacements = replacementsPtr ? *replacementsPtr : localReplacements;
unsigned numRemovedArgumentLabels = getNumRemovedArgumentLabels(
value, /*isCurriedInstanceReference*/ !hasAppliedSelf, functionRefKind);
AnyFunctionType *funcType;
if (isa<AbstractFunctionDecl>(value) || isa<EnumElementDecl>(value)) {
if (auto ErrorTy = value->getInterfaceType()->getAs<ErrorType>()) {
auto genericErrorTy = ErrorType::get(ErrorTy->getASTContext());
return { genericErrorTy, genericErrorTy, genericErrorTy, genericErrorTy };
}
// This is the easy case.
funcType = value->getInterfaceType()->castTo<AnyFunctionType>();
} else {
// For a property, build a type (Self) -> PropType.
// For a subscript, build a type (Self) -> (Indices...) -> ElementType.
//
// If the access is mutating, wrap the storage type in an lvalue type.
Type refType;
if (auto *subscript = dyn_cast<SubscriptDecl>(value)) {
auto elementTy = subscript->getElementInterfaceType();
if (doesStorageProduceLValue(subscript, baseTy, useDC, locator))
elementTy = LValueType::get(elementTy);
auto indices = subscript->getInterfaceType()
->castTo<AnyFunctionType>()->getParams();
// FIXME: Verify ExtInfo state is correct, not working by accident.
FunctionType::ExtInfo info;
refType = FunctionType::get(indices, elementTy, info);
} else {
// Delay the adjustment for preconcurrency until after we've formed
// the function type for this kind of reference. Otherwise we will lose
// track of the adjustment in the formed function's return type.
refType = getUnopenedTypeOfReference(cast<VarDecl>(value), baseTy, useDC,
locator,
/*wantInterfaceType=*/true,
/*adjustForPreconcurrency=*/false);
}
auto selfTy = outerDC->getSelfInterfaceType();
// If this is a reference to an instance member that applies self,
// where self is a value type and the base type is an lvalue, wrap it in an
// inout type.
auto selfFlags = ParameterTypeFlags();
if (value->isInstanceMember() && hasAppliedSelf &&
!outerDC->getDeclaredInterfaceType()->hasReferenceSemantics() &&
baseTy->is<LValueType>() &&
!selfTy->hasError())
selfFlags = selfFlags.withInOut(true);
// If the storage is generic, add a generic signature.
FunctionType::Param selfParam(selfTy, Identifier(), selfFlags);
// FIXME: Verify ExtInfo state is correct, not working by accident.
if (auto sig = innerDC->getGenericSignatureOfContext()) {
GenericFunctionType::ExtInfo info;
funcType = GenericFunctionType::get(sig, {selfParam}, refType, info);
} else {
FunctionType::ExtInfo info;
funcType = FunctionType::get({selfParam}, refType, info);
}
}
// While opening member function type, let's delay opening requirements
// to allow contextual types to affect the situation.
if (auto *genericFn = funcType->getAs<GenericFunctionType>()) {
openGenericParameters(outerDC, genericFn->getGenericSignature(),
replacements, locator);
openedType = genericFn->substGenericArgs(
[&](Type type) { return openType(type, replacements); });
} else {
openedType = funcType;
}
openedType = openedType->removeArgumentLabels(numRemovedArgumentLabels);
// If we are looking at a member of an existential, open the existential.
Type baseOpenedTy = baseObjTy;
if (isStaticMemberRefOnProtocol) {
// In diagnostic mode, let's not try to replace base type
// if there is already a known issue associated with this
// reference e.g. it might be incorrect initializer call
// or result type is invalid.
if (!(shouldAttemptFixes() && hasFixFor(getConstraintLocator(locator)))) {
if (auto concreteSelf =
getConcreteReplacementForProtocolSelfType(value)) {
// Concrete type replacing `Self` could be generic, so we need
// to make sure that it's opened before use.
baseOpenedTy = openType(concreteSelf, replacements);
baseObjTy = baseOpenedTy;
}
}
} else if (baseObjTy->isExistentialType()) {
auto openedArchetype =
OpenedArchetypeType::get(baseObjTy->getCanonicalType(),
useDC->getGenericSignatureOfContext());
OpenedExistentialTypes.insert(
{getConstraintLocator(locator), openedArchetype});
baseOpenedTy = openedArchetype;
}
// Constrain the 'self' object type.
auto openedParams = openedType->castTo<FunctionType>()->getParams();
assert(openedParams.size() == 1);
Type selfObjTy = openedParams.front().getPlainType()->getMetatypeInstanceType();
if (outerDC->getSelfProtocolDecl()) {
// For a protocol, substitute the base object directly. We don't need a
// conformance constraint because we wouldn't have found the declaration
// if it didn't conform.
addConstraint(ConstraintKind::Bind, baseOpenedTy, selfObjTy,
getConstraintLocator(locator));
} else if (!isDynamicResult) {
addSelfConstraint(*this, baseOpenedTy, selfObjTy, locator);
}
// Open generic requirements after self constraint has been
// applied and contextual types have been propagated. This
// helps diagnostics because instead of self type conversion
// failing we'll get a generic requirement constraint failure
// if mismatch is related to generic parameters which is much
// easier to diagnose.
if (auto *genericFn = funcType->getAs<GenericFunctionType>()) {
openGenericRequirements(
outerDC, genericFn->getGenericSignature(),
/*skipProtocolSelfConstraint=*/true, locator,
[&](Type type) { return openType(type, replacements); });
}
if (auto *funcDecl = dyn_cast<AbstractFunctionDecl>(value)) {
auto *fullFunctionType = openedType->getAs<AnyFunctionType>();
// Strip off the 'self' parameter
auto *functionType = fullFunctionType->getResult()->getAs<FunctionType>();
functionType = unwrapPropertyWrapperParameterTypes(*this, funcDecl, functionRefKind,
functionType, locator);
// FIXME: Verify ExtInfo state is correct, not working by accident.
FunctionType::ExtInfo info;
openedType =
FunctionType::get(fullFunctionType->getParams(), functionType, info);
}
// Adjust the opened type for concurrency.
Type origOpenedType = openedType;
if ((isa<AbstractFunctionDecl>(value) || isa<EnumElementDecl>(value)) &&
!isRequirementOrWitness(locator)) {
unsigned numApplies = getNumApplications(
value, hasAppliedSelf, functionRefKind);
openedType = adjustFunctionTypeForConcurrency(
origOpenedType->castTo<AnyFunctionType>(), value, useDC, numApplies,
isMainDispatchQueueMember(locator), replacements);
} else if (auto subscript = dyn_cast<SubscriptDecl>(value)) {
openedType = adjustFunctionTypeForConcurrency(
origOpenedType->castTo<AnyFunctionType>(), subscript, useDC,
/*numApplies=*/2, /*isMainDispatchQueue=*/false, replacements);
} else if (auto var = dyn_cast<VarDecl>(value)) {
// Adjust the function's result type, since that's the Var's actual type.
auto origFnType = origOpenedType->castTo<AnyFunctionType>();
auto resultTy = adjustVarTypeForConcurrency(
origFnType->getResult(), var, useDC, GetClosureType{*this},
ClosureIsolatedByPreconcurrency{*this});
openedType = FunctionType::get(
origFnType->getParams(), resultTy, origFnType->getExtInfo());
}
// Compute the type of the reference.
Type type = getMemberReferenceTypeFromOpenedType(
openedType, baseObjTy, value, outerDC, locator, hasAppliedSelf,
isStaticMemberRefOnProtocol, isDynamicResult, replacements);
// Do the same thing for the original type, if there can be any difference.
Type origType = type;
if (openedType.getPointer() != origOpenedType.getPointer()) {
origType = getMemberReferenceTypeFromOpenedType(
origOpenedType, baseObjTy, value, outerDC, locator, hasAppliedSelf,
isStaticMemberRefOnProtocol, isDynamicResult, replacements);
}
// If we opened up any type variables, record the replacements.
recordOpenedTypes(locator, replacements);
return { origOpenedType, openedType, origType, type };
}
Type ConstraintSystem::getEffectiveOverloadType(ConstraintLocator *locator,
const OverloadChoice &overload,
bool allowMembers,
DeclContext *useDC) {
switch (overload.getKind()) {
case OverloadChoiceKind::Decl:
// Declaration choices are handled below.
break;
case OverloadChoiceKind::DeclViaBridge:
case OverloadChoiceKind::DeclViaDynamic:
case OverloadChoiceKind::DeclViaUnwrappedOptional:
case OverloadChoiceKind::DynamicMemberLookup:
case OverloadChoiceKind::KeyPathDynamicMemberLookup:
case OverloadChoiceKind::KeyPathApplication:
case OverloadChoiceKind::TupleIndex:
return Type();
}
auto decl = overload.getDecl();
// Ignore type declarations.
if (isa<TypeDecl>(decl))
return Type();
// Declarations returning unwrapped optionals don't have a single effective
// type.
if (decl->isImplicitlyUnwrappedOptional())
return Type();
// In a pattern binding initializer, all of its bound variables have no
// effective overload type.
if (auto *PBI = dyn_cast<PatternBindingInitializer>(useDC)) {
if (auto *VD = dyn_cast<VarDecl>(decl)) {
if (PBI->getBinding() == VD->getParentPatternBinding()) {
return Type();
}
}
}
// Retrieve the interface type.
auto type = decl->getInterfaceType();
if (type->hasError()) {
return Type();
}
// If we have a generic function type, drop the generic signature; we don't
// need it for this comparison.
if (auto genericFn = type->getAs<GenericFunctionType>()) {
type = FunctionType::get(genericFn->getParams(),
genericFn->getResult(),
genericFn->getExtInfo());
}
// If this declaration is within a type context, we might not be able
// to handle it.
if (decl->getDeclContext()->isTypeContext()) {
if (!allowMembers)
return Type();
const auto withDynamicSelfResultReplaced = [&](Type type,
unsigned uncurryLevel) {
const Type baseObjTy = overload.getBaseType()
->getRValueType()
->getMetatypeInstanceType()
->lookThroughAllOptionalTypes();
return type->replaceCovariantResultType(
getDynamicSelfReplacementType(baseObjTy, decl, locator),
uncurryLevel);
};
OpenedTypeMap emptyReplacements;
if (auto subscript = dyn_cast<SubscriptDecl>(decl)) {
auto elementTy = subscript->getElementInterfaceType();
if (doesStorageProduceLValue(subscript, overload.getBaseType(), useDC))
elementTy = LValueType::get(elementTy);
else if (elementTy->hasDynamicSelfType()) {
elementTy = withDynamicSelfResultReplaced(elementTy,
/*uncurryLevel=*/0);
}
// 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 (subscript->getAttrs().hasAttribute<OptionalAttr>())
elementTy = OptionalType::get(elementTy->getRValueType());
auto indices = subscript->getInterfaceType()
->castTo<AnyFunctionType>()->getParams();
// FIXME: Verify ExtInfo state is correct, not working by accident.
FunctionType::ExtInfo info;
type = adjustFunctionTypeForConcurrency(
FunctionType::get(indices, elementTy, info),
subscript, useDC, /*numApplies=*/1, /*isMainDispatchQueue=*/false,
emptyReplacements);
} else if (auto var = dyn_cast<VarDecl>(decl)) {
type = var->getValueInterfaceType();
if (doesStorageProduceLValue(var, overload.getBaseType(), useDC)) {
type = LValueType::get(type);
} else if (type->hasDynamicSelfType()) {
type = withDynamicSelfResultReplaced(type, /*uncurryLevel=*/0);
}
type = adjustVarTypeForConcurrency(
type, var, useDC, GetClosureType{*this},
ClosureIsolatedByPreconcurrency{*this});
} else if (isa<AbstractFunctionDecl>(decl) || isa<EnumElementDecl>(decl)) {
if (decl->isInstanceMember() &&
(!overload.getBaseType() ||
(!overload.getBaseType()->getAnyNominal() &&
!overload.getBaseType()->is<ExistentialType>())))
return Type();
// Cope with 'Self' returns.
if (!decl->getDeclContext()->getSelfProtocolDecl()) {
if (isa<AbstractFunctionDecl>(decl) &&
cast<AbstractFunctionDecl>(decl)->hasDynamicSelfResult()) {
if (!overload.getBaseType())
return Type();
if (!overload.getBaseType()->getOptionalObjectType()) {
// `Int??(0)` if we look through all optional types for `Self`
// we'll end up with incorrect type `Int?` for result because
// the actual result type is `Int??`.
if (isa<ConstructorDecl>(decl) && overload.getBaseType()
->getRValueType()
->getMetatypeInstanceType()
->getOptionalObjectType())
return Type();
type = withDynamicSelfResultReplaced(type, /*uncurryLevel=*/2);
}
}
}
auto hasAppliedSelf =
doesMemberRefApplyCurriedSelf(overload.getBaseType(), decl);
unsigned numApplies = getNumApplications(
decl, hasAppliedSelf, overload.getFunctionRefKind());
type = adjustFunctionTypeForConcurrency(
type->castTo<FunctionType>(),
decl, useDC, numApplies, /*isMainDispatchQueue=*/false,
emptyReplacements)
->getResult();
}
}
// Handle "@objc optional" for non-subscripts; subscripts are handled above.
if (decl->getAttrs().hasAttribute<OptionalAttr>() &&
!isa<SubscriptDecl>(decl))
type = OptionalType::get(type->getRValueType());
return type;
}
void ConstraintSystem::addOverloadSet(Type boundType,
ArrayRef<OverloadChoice> choices,
DeclContext *useDC,
ConstraintLocator *locator,
Optional<unsigned> favoredIndex) {
// If there is a single choice, add the bind overload directly.
if (choices.size() == 1) {
addBindOverloadConstraint(boundType, choices.front(), locator, useDC);
return;
}
SmallVector<Constraint *, 4> candidates;
generateConstraints(candidates, boundType, choices, useDC, locator,
favoredIndex);
// For an overload set (disjunction) from newly generated candidates.
addOverloadSet(candidates, locator);
}
void ConstraintSystem::addOverloadSet(ArrayRef<Constraint *> choices,
ConstraintLocator *locator) {
assert(!choices.empty() && "Empty overload set");
// If there is a single choice, attempt it right away.
if (choices.size() == 1) {
simplifyConstraint(*choices.front());
return;
}
auto *disjunction =
Constraint::createDisjunction(*this, choices, locator, ForgetChoice);
addUnsolvedConstraint(disjunction);
if (simplifyAppliedOverloads(disjunction, locator))
retireFailedConstraint(disjunction);
}
/// If we're resolving an overload set with a decl that has special type
/// checking semantics, compute the type of the reference. For now, follow
/// the lead of \c getTypeOfMemberReference and return a pair of
/// the full opened type and the reference's type.
static DeclReferenceType getTypeOfReferenceWithSpecialTypeCheckingSemantics(
ConstraintSystem &CS, ConstraintLocator *locator,
DeclTypeCheckingSemantics semantics) {
switch (semantics) {
case DeclTypeCheckingSemantics::Normal:
llvm_unreachable("Decl does not have special type checking semantics!");
case DeclTypeCheckingSemantics::TypeOf: {
// Proceed with a "DynamicType" operation. This produces an existential
// metatype from existentials, or a concrete metatype from non-
// existentials (as seen from the current abstraction level), which can't
// be expressed in the type system currently.
auto input = CS.createTypeVariable(
CS.getConstraintLocator(locator, ConstraintLocator::FunctionArgument),
TVO_CanBindToNoEscape);
auto output = CS.createTypeVariable(
CS.getConstraintLocator(locator, ConstraintLocator::FunctionResult),
TVO_CanBindToNoEscape);
FunctionType::Param inputArg(input,
CS.getASTContext().getIdentifier("of"));
CS.addConstraint(
ConstraintKind::DynamicTypeOf, output, input,
CS.getConstraintLocator(locator, ConstraintLocator::DynamicType));
// FIXME: Verify ExtInfo state is correct, not working by accident.
FunctionType::ExtInfo info;
auto refType = FunctionType::get({inputArg}, output, info);
return {refType, refType, refType, refType};
}
case DeclTypeCheckingSemantics::WithoutActuallyEscaping: {
// Proceed with a "WithoutActuallyEscaping" operation. The body closure
// receives a copy of the argument closure that is temporarily made
// @escaping.
auto noescapeClosure = CS.createTypeVariable(
CS.getConstraintLocator(locator, ConstraintLocator::FunctionArgument),
TVO_CanBindToNoEscape);
auto escapeClosure = CS.createTypeVariable(
CS.getConstraintLocator(locator, ConstraintLocator::FunctionArgument),
TVO_CanBindToNoEscape);
CS.addConstraint(ConstraintKind::EscapableFunctionOf, escapeClosure,
noescapeClosure, CS.getConstraintLocator(locator));
auto result = CS.createTypeVariable(
CS.getConstraintLocator(locator, ConstraintLocator::FunctionResult),
TVO_CanBindToNoEscape);
FunctionType::Param arg(escapeClosure);
auto bodyClosure = FunctionType::get(arg, result,
FunctionType::ExtInfoBuilder()
.withNoEscape(true)
.withAsync(true)
.withThrows(true)
.build());
FunctionType::Param args[] = {
FunctionType::Param(noescapeClosure),
FunctionType::Param(bodyClosure, CS.getASTContext().getIdentifier("do")),
};
auto refType = FunctionType::get(args, result,
FunctionType::ExtInfoBuilder()
.withNoEscape(false)
.withAsync(true)
.withThrows(true)
.build());
return {refType, refType, refType, refType};
}
case DeclTypeCheckingSemantics::OpenExistential: {
// The body closure receives a freshly-opened archetype constrained by the
// existential type as its input.
auto openedTy = CS.createTypeVariable(
CS.getConstraintLocator(locator, ConstraintLocator::FunctionArgument),
TVO_CanBindToNoEscape);
auto existentialTy = CS.createTypeVariable(
CS.getConstraintLocator(locator, ConstraintLocator::FunctionArgument),
TVO_CanBindToNoEscape);
CS.addConstraint(ConstraintKind::OpenedExistentialOf, openedTy,
existentialTy, CS.getConstraintLocator(locator));
auto result = CS.createTypeVariable(
CS.getConstraintLocator(locator, ConstraintLocator::FunctionResult),
TVO_CanBindToNoEscape);
FunctionType::Param bodyArgs[] = {FunctionType::Param(openedTy)};
auto bodyClosure = FunctionType::get(bodyArgs, result,
FunctionType::ExtInfoBuilder()
.withNoEscape(true)
.withThrows(true)
.withAsync(true)
.build());
FunctionType::Param args[] = {
FunctionType::Param(existentialTy),
FunctionType::Param(bodyClosure, CS.getASTContext().getIdentifier("do")),
};
auto refType = FunctionType::get(args, result,
FunctionType::ExtInfoBuilder()
.withNoEscape(false)
.withThrows(true)
.withAsync(true)
.build());
return {refType, refType, refType, refType};
}
}
llvm_unreachable("Unhandled DeclTypeCheckingSemantics in switch.");
}
/// Try to identify and fix failures related to partial function application
/// e.g. partial application of `init` or 'mutating' instance methods.
static std::pair<bool, unsigned>
isInvalidPartialApplication(ConstraintSystem &cs,
const AbstractFunctionDecl *member,
ConstraintLocator *locator) {
// If this is a compiler synthesized implicit conversion, let's skip
// the check because the base of `UDE` is not the base of the injected
// initializer.
if (locator->isLastElement<LocatorPathElt::ConstructorMember>() &&
locator->findFirst<LocatorPathElt::ImplicitConversion>())
return {false, 0};
auto *UDE = getAsExpr<UnresolvedDotExpr>(locator->getAnchor());
if (UDE == nullptr)
return {false,0};
auto baseTy =
cs.simplifyType(cs.getType(UDE->getBase()))->getWithoutSpecifierType();
auto isInvalidIfPartiallyApplied = [&]() {
if (auto *FD = dyn_cast<FuncDecl>(member)) {
// 'mutating' instance methods cannot be partially applied.
if (FD->isMutating())
return true;
// Instance methods cannot be referenced on 'super' from a static
// context.
if (UDE->getBase()->isSuperExpr() &&
baseTy->is<MetatypeType>() &&
!FD->isStatic())
return true;
}
// Another unsupported partial application is related
// to constructor delegation via 'self.init' or 'super.init'.
//
// Note that you can also write 'self.init' or 'super.init'
// inside a static context -- since 'self' is a metatype there
// it doesn't have the special delegation meaning that it does
// in the body of a constructor.
if (isa<ConstructorDecl>(member) && !baseTy->is<MetatypeType>()) {
// Check for a `super.init` delegation...
if (UDE->getBase()->isSuperExpr())
return true;
// ... and `self.init` delegation. Note that in a static context,
// `self.init` is just an ordinary partial application; it's OK
// because there's no associated instance for delegation.
if (auto *DRE = dyn_cast<DeclRefExpr>(UDE->getBase())) {
if (auto *baseDecl = DRE->getDecl()) {
if (baseDecl->getBaseName() == cs.getASTContext().Id_self)
return true;
}
}
}
return false;
};
if (!isInvalidIfPartiallyApplied())
return {false,0};
// If base is a metatype it would be ignored (unless this is an initializer
// call), but if it is some other type it means that we have a single
// application level already.
unsigned level = 0;
if (!baseTy->is<MetatypeType>())
++level;
if (auto *call = dyn_cast_or_null<CallExpr>(cs.getParentExpr(UDE))) {
level += 1;
}
return {true, level};
}
FunctionType::ExtInfo ConstraintSystem::closureEffects(ClosureExpr *expr) {
return evaluateOrDefault(
getASTContext().evaluator, ClosureEffectsRequest{expr},
FunctionType::ExtInfo());
}
FunctionType::ExtInfo ClosureEffectsRequest::evaluate(
Evaluator &evaluator, ClosureExpr *expr) const {
// A walker that looks for 'try' and 'throw' expressions
// that aren't nested within closures, nested declarations,
// or exhaustive catches.
class FindInnerThrows : public ASTWalker {
DeclContext *DC;
bool FoundThrow = false;
PreWalkResult<Expr *> walkToExprPre(Expr *expr) override {
// If we've found a 'try', record it and terminate the traversal.
if (isa<TryExpr>(expr)) {
FoundThrow = true;
return Action::Stop();
}
// Don't walk into a 'try!' or 'try?'.
if (isa<ForceTryExpr>(expr) || isa<OptionalTryExpr>(expr)) {
return Action::SkipChildren(expr);
}
// Do not recurse into other closures.
if (isa<ClosureExpr>(expr))
return Action::SkipChildren(expr);
return Action::Continue(expr);
}
PreWalkAction walkToDeclPre(Decl *decl) override {
// Do not walk into function or type declarations.
return Action::VisitChildrenIf(isa<PatternBindingDecl>(decl));
}
bool isSyntacticallyExhaustive(DoCatchStmt *stmt) {
for (auto catchClause : stmt->getCatches()) {
for (auto &LabelItem : catchClause->getMutableCaseLabelItems()) {
if (isSyntacticallyExhaustive(catchClause->getStartLoc(),
LabelItem))
return true;
}
}
return false;
}
bool isSyntacticallyExhaustive(SourceLoc CatchLoc,
CaseLabelItem &LabelItem) {
// If it's obviously non-exhaustive, great.
if (LabelItem.getGuardExpr())
return false;
// If we can show that it's exhaustive without full
// type-checking, great.
if (LabelItem.isSyntacticallyExhaustive())
return true;
// Okay, resolve the pattern.
Pattern *pattern = LabelItem.getPattern();
if (!LabelItem.isPatternResolved()) {
pattern = TypeChecker::resolvePattern(pattern, DC,
/*isStmtCondition*/false);
if (!pattern) return false;
// Save that aside while we explore the type.
LabelItem.setPattern(pattern, /*resolved=*/true);
}
// Require the pattern to have a particular shape: a number
// of is-patterns applied to an irrefutable pattern.
pattern = pattern->getSemanticsProvidingPattern();
while (auto isp = dyn_cast<IsPattern>(pattern)) {
Type castType;
if (auto castTypeRepr = isp->getCastTypeRepr()) {
castType = TypeResolution::resolveContextualType(
castTypeRepr, DC, TypeResolverContext::InExpression,
/*unboundTyOpener*/ nullptr,
/*placeholderHandler*/ nullptr);
} else {
castType = isp->getCastType();
}
if (castType->hasError()) {
return false;
}
if (!isp->hasSubPattern()) {
pattern = nullptr;
break;
} else {
pattern = isp->getSubPattern()->getSemanticsProvidingPattern();
}
}
if (pattern && pattern->isRefutablePattern()) {
return false;
}
// Okay, now it should be safe to coerce the pattern.
// Pull the top-level pattern back out.
pattern = LabelItem.getPattern();
auto &ctx = DC->getASTContext();
if (!ctx.getErrorDecl())
return false;
auto contextualPattern =
ContextualPattern::forRawPattern(pattern, DC);
pattern = TypeChecker::coercePatternToType(
contextualPattern, ctx.getErrorExistentialType(),
TypeResolverContext::InExpression);
if (!pattern)
return false;
LabelItem.setPattern(pattern, /*resolved=*/true);
return LabelItem.isSyntacticallyExhaustive();
}
PreWalkResult<Stmt *> walkToStmtPre(Stmt *stmt) override {
// If we've found a 'throw', record it and terminate the traversal.
if (isa<ThrowStmt>(stmt)) {
FoundThrow = true;
return Action::Stop();
}
// Handle do/catch differently.
if (auto doCatch = dyn_cast<DoCatchStmt>(stmt)) {
// Only walk into the 'do' clause of a do/catch statement
// if the catch isn't syntactically exhaustive.
if (!isSyntacticallyExhaustive(doCatch)) {
if (!doCatch->getBody()->walk(*this))
return Action::Stop();
}
// Walk into all the catch clauses.
for (auto catchClause : doCatch->getCatches()) {
if (!catchClause->walk(*this))
return Action::Stop();
}
// We've already walked all the children we care about.
return Action::SkipChildren(stmt);
}
if (auto forEach = dyn_cast<ForEachStmt>(stmt)) {
if (forEach->getTryLoc().isValid()) {
FoundThrow = true;
return Action::Stop();
}
}
return Action::Continue(stmt);
}
public:
FindInnerThrows(DeclContext *dc)
: DC(dc) {}
bool foundThrow() { return FoundThrow; }
};
// If either 'throws' or 'async' was explicitly specified, use that
// set of effects.
bool throws = expr->getThrowsLoc().isValid();
bool async = expr->getAsyncLoc().isValid();
bool concurrent = expr->getAttrs().hasAttribute<SendableAttr>();
if (throws || async) {
return ASTExtInfoBuilder()
.withThrows(throws)
.withAsync(async)
.withConcurrent(concurrent)
.build();
}
// Scan the body to determine the effects.
auto body = expr->getBody();
if (!body)
return ASTExtInfoBuilder().withConcurrent(concurrent).build();
auto throwFinder = FindInnerThrows(expr);
body->walk(throwFinder);
return ASTExtInfoBuilder()
.withThrows(throwFinder.foundThrow())
.withAsync(bool(findAsyncNode(expr)))
.withConcurrent(concurrent)
.build();
}
bool ConstraintSystem::isAsynchronousContext(DeclContext *dc) {
if (auto func = dyn_cast<AbstractFunctionDecl>(dc))
return func->isAsyncContext();
if (auto closure = dyn_cast<ClosureExpr>(dc)) {
return evaluateOrDefault(
getASTContext().evaluator,
ClosureEffectsRequest{const_cast<ClosureExpr *>(closure)},
FunctionType::ExtInfo()).isAsync();
}
return false;
}
void ConstraintSystem::buildDisjunctionForOptionalVsUnderlying(
Type boundTy, Type ty, ConstraintLocator *locator) {
// NOTE: If we use other locator kinds for these disjunctions, we
// need to account for it in solution scores for forced-unwraps.
assert(locator->getPath().back().getKind() ==
ConstraintLocator::ImplicitlyUnwrappedDisjunctionChoice ||
locator->getPath().back().getKind() ==
ConstraintLocator::DynamicLookupResult);
assert(!ty->is<InOutType>());
auto rvalueTy = ty->getWithoutSpecifierType();
// If the type to bind is a placeholder, we can propagate it, as we don't know
// whether it can be optional or non-optional, and we would have already
// recorded a fix for it.
if (rvalueTy->isPlaceholder()) {
addConstraint(ConstraintKind::Bind, boundTy, ty, locator);
return;
}
// Create the constraint to bind to the optional type and make it the favored
// choice.
auto *bindToOptional =
Constraint::create(*this, ConstraintKind::Bind, boundTy, ty, locator);
bindToOptional->setFavored();
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();
// 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 |
TVO_CanBindToNoEscape);
// Using a `typeVar` here because l-value is going to be applied
// to the underlying type below.
addConstraint(ConstraintKind::OptionalObject, typeVar, underlyingType,
locator);
}
if (ty->is<LValueType>())
underlyingType = LValueType::get(underlyingType);
auto *bindToUnderlying = Constraint::create(*this, ConstraintKind::Bind,
boundTy, underlyingType, locator);
llvm::SmallVector<Constraint *, 2> choices = {bindToOptional,
bindToUnderlying};
// Create the disjunction
addDisjunctionConstraint(choices, locator, RememberChoice);
}
void ConstraintSystem::bindOverloadType(
const SelectedOverload &overload, Type boundType,
ConstraintLocator *locator, DeclContext *useDC,
llvm::function_ref<void(unsigned int, Type, ConstraintLocator *)>
verifyThatArgumentIsHashable) {
auto &ctx = getASTContext();
auto choice = overload.choice;
auto openedType = overload.adjustedOpenedType;
auto bindTypeOrIUO = [&](Type ty) {
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);
} else {
// Add the type binding constraint.
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)},
/*firstTrailingClosureIndex=*/None,
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:
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;
}
// The opened type of an unbound member reference has optionality applied
// to the uncurried type.
if (!doesMemberRefApplyCurriedSelf(choice.getBaseType(),
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: {
auto stringLiteral =
TypeChecker::getProtocol(getASTContext(), choice.getDecl()->getLoc(),
KnownProtocolKind::ExpressibleByStringLiteral);
if (!stringLiteral)
return;
// 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);
addDynamicMemberSubscriptConstraints(argTy, /*resultTy*/ boundType);
return;
}
case OverloadChoiceKind::KeyPathDynamicMemberLookup: {
auto *fnType = openedType->castTo<FunctionType>();
assert(fnType->getParams().size() == 1 &&
"subscript always has one argument");
// Parameter type is KeyPath<T, U> where `T` is a root type
// and U is a leaf type (aka member type).
auto keyPathTy =
fnType->getParams()[0].getPlainType()->castTo<BoundGenericType>();
auto *keyPathDecl = keyPathTy->getAnyNominal();
assert(isKnownKeyPathType(keyPathTy) &&
"parameter is supposed to be a keypath");
auto *keyPathLoc = getConstraintLocator(
locator, LocatorPathElt::KeyPathDynamicMember(keyPathDecl));
auto rootTy = keyPathTy->getGenericArgs()[0];
auto leafTy = keyPathTy->getGenericArgs()[1];
// Member would either point to mutable or immutable property, we
// don't which at the moment, so let's allow its type to be l-value.
auto memberTy = createTypeVariable(keyPathLoc, TVO_CanBindToLValue |
TVO_CanBindToNoEscape);
// Attempt to lookup a member with a give name in the root type and
// assign result to the leaf type of the keypath.
bool isSubscriptRef = locator->isSubscriptMemberRef();
DeclNameRef memberName = isSubscriptRef
? DeclNameRef::createSubscript()
// FIXME: Should propagate name-as-written through.
: DeclNameRef(choice.getName());
addValueMemberConstraint(LValueType::get(rootTy), memberName, memberTy,
useDC,
isSubscriptRef ? FunctionRefKind::DoubleApply
: FunctionRefKind::Unapplied,
/*outerAlternatives=*/{}, keyPathLoc);
// In case of subscript things are more complicated comparing to "dot"
// syntax, because we have to get "applicable function" constraint
// associated with index expression and re-bind it to match "member type"
// looked up by dynamically.
if (isSubscriptRef) {
// Make sure that regular subscript declarations (if any) are
// preferred over key path dynamic member lookup.
increaseScore(SK_KeyPathSubscript);
auto boundTypeVar = boundType->castTo<TypeVariableType>();
auto constraints = getConstraintGraph().gatherConstraints(
boundTypeVar, ConstraintGraph::GatheringKind::EquivalenceClass,
[](Constraint *constraint) {
return constraint->getKind() == ConstraintKind::ApplicableFunction;
});
assert(constraints.size() == 1);
auto *applicableFn = constraints.front();
retireConstraint(applicableFn);
// Original subscript expression e.g. `<base>[0]` generated following
// constraint `($T_A0, [$T_A1], ...) -> $T_R applicable fn $T_S` where
// `$T_S` is supposed to be bound to each subscript choice e.g.
// `(Int) -> Int`.
//
// Here is what we need to do to make this work as-if expression was
// `<base>[dynamicMember: \.[0]]`:
// - Right-hand side function type would have to get a new result type
// since it would have to point to result type of `\.[0]`, arguments
// though should stay the same.
// - Left-hand side `$T_S` is going to point to a new "member type"
// we are looking up based on the root type of the key path.
// - Original result type `$T_R` is going to represent result of
// the `[dynamicMember: \.[0]]` invocation.
// 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(),
ConstraintLocator::FunctionResult),
TVO_CanBindToLValue | TVO_CanBindToNoEscape);
// FIXME: Verify ExtInfo state is correct, not working by accident.
FunctionType::ExtInfo 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::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);
}
return;
}
}
llvm_unreachable("Unhandled OverloadChoiceKind in switch.");
}
void ConstraintSystem::resolveOverload(ConstraintLocator *locator,
Type boundType,
OverloadChoice choice,
DeclContext *useDC) {
// Add a conformance constraint to make sure that given type conforms
// to Hashable protocol, which is important for key path subscript
// components.
auto verifyThatArgumentIsHashable = [&](unsigned index, Type argType,
ConstraintLocator *locator) {
if (auto *hashable = TypeChecker::getProtocol(
argType->getASTContext(), choice.getDecl()->getLoc(),
KnownProtocolKind::Hashable)) {
addConstraint(ConstraintKind::ConformsTo, argType,
hashable->getDeclaredInterfaceType(),
getConstraintLocator(
locator, LocatorPathElt::TupleElement(index)));
}
};
// Determine the type to which we'll bind the overload set's type.
Type openedType;
Type adjustedOpenedType;
Type refType;
Type adjustedRefType;
switch (auto kind = choice.getKind()) {
case OverloadChoiceKind::Decl:
case OverloadChoiceKind::DeclViaBridge:
case OverloadChoiceKind::DeclViaDynamic:
case OverloadChoiceKind::DeclViaUnwrappedOptional:
case OverloadChoiceKind::DynamicMemberLookup:
case OverloadChoiceKind::KeyPathDynamicMemberLookup: {
// If we refer to a top-level decl with special type-checking semantics,
// handle it now.
const auto semantics =
TypeChecker::getDeclTypeCheckingSemantics(choice.getDecl());
DeclReferenceType declRefType;
if (semantics != DeclTypeCheckingSemantics::Normal) {
declRefType = getTypeOfReferenceWithSpecialTypeCheckingSemantics(
*this, locator, semantics);
} else if (auto baseTy = choice.getBaseType()) {
// Retrieve the type of a reference to the specific declaration choice.
assert(!baseTy->hasTypeParameter());
declRefType = getTypeOfMemberReference(
baseTy, choice.getDecl(), useDC,
(kind == OverloadChoiceKind::DeclViaDynamic),
choice.getFunctionRefKind(), locator, nullptr);
} else {
declRefType = getTypeOfReference(
choice.getDecl(), choice.getFunctionRefKind(), locator, useDC);
}
openedType = declRefType.openedType;
adjustedOpenedType = declRefType.adjustedOpenedType;
refType = declRefType.referenceType;
adjustedRefType = declRefType.adjustedReferenceType;
break;
}
case OverloadChoiceKind::TupleIndex:
if (auto lvalueTy = choice.getBaseType()->getAs<LValueType>()) {
// When the base of a tuple lvalue, the member is always an lvalue.
auto tuple = lvalueTy->getObjectType()->castTo<TupleType>();
adjustedRefType = tuple->getElementType(choice.getTupleIndex())->getRValueType();
adjustedRefType = LValueType::get(adjustedRefType);
} else {
// When the base is a tuple rvalue, the member is always an rvalue.
auto tuple = choice.getBaseType()->castTo<TupleType>();
adjustedRefType = tuple->getElementType(choice.getTupleIndex())->getRValueType();
}
refType = adjustedRefType;
break;
case OverloadChoiceKind::KeyPathApplication: {
// Key path application looks like a subscript(keyPath: KeyPath<Base, T>).
// The element type is T or @lvalue T based on the key path subtype and
// the mutability of the base.
auto keyPathIndexTy = createTypeVariable(
getConstraintLocator(locator, ConstraintLocator::FunctionArgument),
TVO_CanBindToInOut);
auto elementTy = createTypeVariable(
getConstraintLocator(locator, ConstraintLocator::FunctionArgument),
TVO_CanBindToLValue | TVO_CanBindToNoEscape);
auto elementObjTy = createTypeVariable(
getConstraintLocator(locator, ConstraintLocator::FunctionArgument),
TVO_CanBindToNoEscape);
addConstraint(ConstraintKind::Equal, elementTy, elementObjTy, locator);
// The element result is an lvalue or rvalue based on the key path class.
addKeyPathApplicationConstraint(
keyPathIndexTy, choice.getBaseType(), elementTy, locator);
FunctionType::Param indices[] = {
FunctionType::Param(keyPathIndexTy, getASTContext().Id_keyPath),
};
// FIXME: Verify ExtInfo state is correct, not working by accident.
FunctionType::ExtInfo subscriptInfo;
auto subscriptTy = FunctionType::get(indices, elementTy, subscriptInfo);
FunctionType::Param baseParam(choice.getBaseType());
// FIXME: Verify ExtInfo state is correct, not working by accident.
FunctionType::ExtInfo fullInfo;
auto fullTy = FunctionType::get({baseParam}, subscriptTy, fullInfo);
openedType = fullTy;
adjustedOpenedType = fullTy;
// FIXME: @preconcurrency
refType = subscriptTy;
adjustedRefType = subscriptTy;
// Increase the score so that actual subscripts get preference.
// ...except if we're solving for code completion and the index expression
// contains the completion location
auto SE = getAsExpr<SubscriptExpr>(locator->getAnchor());
if (!isForCodeCompletion() ||
(SE && !containsCodeCompletionLoc(SE->getArgs()))) {
increaseScore(SK_KeyPathSubscript);
}
break;
}
}
assert(!refType->hasTypeParameter() && "Cannot have a dependent type here");
assert(!adjustedRefType->hasTypeParameter() &&
"Cannot have a dependent type here");
if (auto *decl = choice.getDeclOrNull()) {
// If we're choosing an asynchronous declaration within a synchronous
// context, or vice-versa, increase the async/async mismatch score.
if (auto func = dyn_cast<AbstractFunctionDecl>(decl)) {
if (!Options.contains(ConstraintSystemFlags::IgnoreAsyncSyncMismatch) &&
!func->hasPolymorphicEffect(EffectKind::Async) &&
func->isAsyncContext() != isAsynchronousContext(useDC)) {
increaseScore(
func->isAsyncContext() ? SK_AsyncInSyncMismatch : SK_SyncInAsync);
}
}
if (isa<SubscriptDecl>(decl)) {
if (locator->isResultOfKeyPathDynamicMemberLookup() ||
locator->isKeyPathSubscriptComponent()) {
// Subscript type has a format of (Self[.Type) -> (Arg...) -> Result
auto declTy = adjustedOpenedType->castTo<FunctionType>();
auto subscriptTy = declTy->getResult()->castTo<FunctionType>();
// If we have subscript, each of the arguments has to conform to
// Hashable, because it would be used as a component inside key path.
for (auto index : indices(subscriptTy->getParams())) {
const auto &param = subscriptTy->getParams()[index];
verifyThatArgumentIsHashable(index, param.getParameterType(), locator);
}
}
}
if (isa<AbstractFunctionDecl>(decl) || isa<TypeDecl>(decl)) {
auto anchor = locator->getAnchor();
// TODO: Instead of not increasing the score for arguments to #selector,
// a better fix for this is to port over the #selector diagnostics from
// CSApply to constraint fixes, and not attempt invalid disjunction
// choices based on the selector kind on the valid code path.
if (choice.getFunctionRefKind() == FunctionRefKind::Unapplied &&
!UnevaluatedRootExprs.contains(getAsExpr(anchor))) {
increaseScore(SK_UnappliedFunction);
}
}
if (auto *afd = dyn_cast<AbstractFunctionDecl>(decl)) {
// Check whether applying this overload would result in invalid
// partial function application e.g. partial application of
// mutating method or initializer.
// This check is supposed to be performed without
// `shouldAttemptFixes` because name lookup can't
// detect that particular partial application is
// invalid, so it has to return all of the candidates.
bool isInvalidPartialApply;
unsigned level;
std::tie(isInvalidPartialApply, level) =
isInvalidPartialApplication(*this, afd, locator);
if (isInvalidPartialApply) {
// No application at all e.g. `Foo.bar`.
if (level == 0) {
// Swift 4 and earlier failed to diagnose a reference to a mutating
// method without any applications at all, which would get
// miscompiled into a function with undefined behavior. Warn for
// source compatibility.
bool isWarning = !getASTContext().isSwiftVersionAtLeast(5);
(void)recordFix(
AllowInvalidPartialApplication::create(isWarning, *this, locator));
} else if (level == 1) {
// `Self` parameter is applied, e.g. `foo.bar` or `Foo.bar(&foo)`
(void)recordFix(AllowInvalidPartialApplication::create(
/*isWarning=*/false, *this, locator));
}
// Otherwise both `Self` and arguments are applied,
// e.g. `foo.bar()` or `Foo.bar(&foo)()`, and there is nothing to do.
}
}
}
// Note that we have resolved this overload.
auto overload = SelectedOverload{
choice, openedType, adjustedOpenedType, refType, adjustedRefType,
boundType};
auto result = ResolvedOverloads.insert({locator, overload});
assert(result.second && "Already resolved this overload?");
(void)result;
// Add the constraints necessary to bind the overload type.
bindOverloadType(overload, boundType, locator, useDC,
verifyThatArgumentIsHashable);
if (isDebugMode()) {
PrintOptions PO;
PO.PrintTypesForDebugging = true;
auto &log = llvm::errs();
log.indent(solverState ? solverState->getCurrentIndent() : 2);
log << "(overload set choice binding ";
boundType->print(log, PO);
log << " := ";
adjustedRefType->print(log, PO);
auto openedAtLoc = getOpenedTypes(locator);
if (!openedAtLoc.empty()) {
log << " [";
llvm::interleave(
openedAtLoc.begin(), openedAtLoc.end(),
[&](OpenedType opened) {
opened.second->getImpl().getGenericParameter()->print(log, PO);
log << " := ";
Type(opened.second).print(log, PO);
},
[&]() { log << ", "; });
log << "]";
}
log << ")\n";
}
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()) {
increaseScore(SK_UnresolvedMemberViaOptional);
}
}
Type ConstraintSystem::simplifyTypeImpl(Type type,
llvm::function_ref<Type(TypeVariableType *)> getFixedTypeFn) const {
return type.transform([&](Type type) -> Type {
if (auto tvt = dyn_cast<TypeVariableType>(type.getPointer()))
return getFixedTypeFn(tvt);
// If this is a dependent member type for which we end up simplifying
// the base to a non-type-variable, perform lookup.
if (auto depMemTy = dyn_cast<DependentMemberType>(type.getPointer())) {
// Simplify the base.
Type newBase = simplifyTypeImpl(depMemTy->getBase(), getFixedTypeFn);
if (newBase->isPlaceholder()) {
return PlaceholderType::get(getASTContext(), depMemTy);
}
// If nothing changed, we're done.
if (newBase.getPointer() == depMemTy->getBase().getPointer())
return type;
// Dependent member types should only be created for associated types.
auto assocType = depMemTy->getAssocType();
assert(depMemTy->getAssocType() && "Expected associated type!");
// FIXME: It's kind of weird in general that we have to look
// through lvalue, inout and IUO types here
Type lookupBaseType = newBase->getWithoutSpecifierType();
if (auto selfType = lookupBaseType->getAs<DynamicSelfType>())
lookupBaseType = selfType->getSelfType();
if (lookupBaseType->mayHaveMembers()) {
auto *proto = assocType->getProtocol();
auto conformance = DC->getParentModule()->lookupConformance(
lookupBaseType, proto);
if (!conformance) {
// FIXME: This regresses diagnostics if removed, but really the
// handling of a missing conformance should be the same for
// tuples and non-tuples.
if (lookupBaseType->is<TupleType>())
return DependentMemberType::get(lookupBaseType, assocType);
// If the base type doesn't conform to the associatedtype's protocol,
// there will be a missing conformance fix applied in diagnostic mode,
// so the concrete dependent member type is considered a "hole" in
// order to continue solving.
auto memberTy = DependentMemberType::get(lookupBaseType, assocType);
if (shouldAttemptFixes() &&
getPhase() == ConstraintSystemPhase::Solving) {
return PlaceholderType::get(getASTContext(), memberTy);
}
return memberTy;
}
auto subs = SubstitutionMap::getProtocolSubstitutions(
proto, lookupBaseType, conformance);
auto result = assocType->getDeclaredInterfaceType().subst(subs);
if (!result->hasError())
return result;
}
return DependentMemberType::get(lookupBaseType, assocType);
}
return type;
});
}
Type ConstraintSystem::simplifyType(Type type) const {
if (!type->hasTypeVariable())
return type;
// Map type variables down to the fixed types of their representatives.
return simplifyTypeImpl(type,
[&](TypeVariableType *tvt) -> Type {
if (auto fixed = getFixedType(tvt))
return simplifyType(fixed);
return getRepresentative(tvt);
});
}
void Solution::recordSingleArgMatchingChoice(ConstraintLocator *locator) {
auto &cs = getConstraintSystem();
assert(argumentMatchingChoices.find(locator) ==
argumentMatchingChoices.end() &&
"recording multiple bindings for same locator");
argumentMatchingChoices.insert(
{cs.getConstraintLocator(locator, ConstraintLocator::ApplyArgument),
MatchCallArgumentResult::forArity(1)});
}
Type Solution::simplifyType(Type type) const {
if (!(type->hasTypeVariable() || type->hasPlaceholder()))
return type;
// Map type variables to fixed types from bindings.
auto &cs = getConstraintSystem();
auto resolvedType = cs.simplifyTypeImpl(
type, [&](TypeVariableType *tvt) -> Type { return getFixedType(tvt); });
// Placeholders shouldn't be reachable through a solution, they are only
// useful to determine what went wrong exactly.
if (resolvedType->hasPlaceholder()) {
return resolvedType.transform([&](Type type) {
return type->isPlaceholder() ? Type(cs.getASTContext().TheUnresolvedType)
: type;
});
}
return resolvedType;
}
Type Solution::simplifyTypeForCodeCompletion(Type Ty) const {
auto &CS = getConstraintSystem();
// First, instantiate all type variables that we know, but don't replace
// placeholders by unresolved types.
Ty = CS.simplifyTypeImpl(Ty, [this](TypeVariableType *typeVar) -> Type {
return getFixedType(typeVar);
});
// Next, replace all placeholders by type variables. We know that all type
// variables now in the type originate from placeholders.
Ty = Ty.transform([](Type type) -> Type {
if (auto *placeholder = type->getAs<PlaceholderType>()) {
if (auto *typeVar =
placeholder->getOriginator().dyn_cast<TypeVariableType *>()) {
return typeVar;
}
}
return type;
});
// Replace all type variables (which must come from placeholders) by their
// generic parameters. Because we call into simplifyTypeImpl
Ty = CS.simplifyTypeImpl(Ty, [&CS](TypeVariableType *typeVar) -> Type {
// Code completion depends on generic parameter type being represented in
// terms of `ArchetypeType` since it's easy to extract protocol requirements
// from it.
auto getTypeVarAsArchetype = [](TypeVariableType *typeVar) -> Type {
if (auto *GP = typeVar->getImpl().getGenericParameter()) {
if (auto *GPD = GP->getDecl()) {
return GPD->getInnermostDeclContext()->mapTypeIntoContext(GP);
}
}
return Type();
};
if (auto archetype = getTypeVarAsArchetype(typeVar)) {
return archetype;
}
// When applying the logic below to get contextual types inside result
// builders, the code completion type variable is connected by a one-way
// constraint to a type variable in the buildBlock call, but that is not the
// type variable that represents the argument type. We need to find the type
// variable representing the argument to retrieve protocol requirements from
// it. Look for a ArgumentConversion constraint that allows us to retrieve
// the argument type var.
for (auto argConstraint :
CS.getConstraintGraph()[typeVar].getConstraints()) {
if (argConstraint->getKind() == ConstraintKind::ArgumentConversion &&
argConstraint->getFirstType()->getRValueType()->isEqual(typeVar)) {
if (auto argTV =
argConstraint->getSecondType()->getAs<TypeVariableType>()) {
if (auto archetype = getTypeVarAsArchetype(argTV)) {
return archetype;
}
}
}
}
return typeVar;
});
// Logic to determine the contextual type inside buildBlock result builders:
//
// When completing inside a result builder, the result builder
// @ViewBuilder var body: some View {
// Text("Foo")
// #^COMPLETE^#
// }
// gets rewritten to
// @ViewBuilder var body: some View {
// let $__builder2: Text
// let $__builder0 = Text("Foo")
// let $__builder1 = #^COMPLETE^#
// $__builder2 = ViewBuilder.buildBlock($__builder0, $__builder1)
// return $__builder2
// }
// Inside the constraint system
// let $__builder1 = #^COMPLETE^#
// gets type checked without context, so we can't know the contextual type for
// the code completion token. But we know that $__builder1 (and thus the type
// of #^COMPLETE^#) is used as the second argument to ViewBuilder.buildBlock,
// so we can extract the contextual type from that call. To do this, figure
// out the type variable that is used for $__builder1 in the buildBlock call.
// This type variable is connected to the type variable of $__builder1's
// definition by a one-way constraint.
if (auto TV = Ty->getAs<TypeVariableType>()) {
for (auto constraint : CS.getConstraintGraph()[TV].getConstraints()) {
if (constraint->getKind() == ConstraintKind::OneWayEqual &&
constraint->getSecondType()->isEqual(TV)) {
return simplifyTypeForCodeCompletion(constraint->getFirstType());
}
}
}
// Remove any remaining type variables and placeholders
Ty = simplifyType(Ty);
return Ty->getRValueType();
}
size_t Solution::getTotalMemory() const {
return sizeof(*this) + typeBindings.getMemorySize() +
overloadChoices.getMemorySize() +
ConstraintRestrictions.getMemorySize() +
llvm::capacity_in_bytes(Fixes) + DisjunctionChoices.getMemorySize() +
OpenedTypes.getMemorySize() + OpenedExistentialTypes.getMemorySize() +
(DefaultedConstraints.size() * sizeof(void *)) +
ImplicitCallAsFunctionRoots.getMemorySize();
}
DeclContext *Solution::getDC() const { return constraintSystem->DC; }
DeclName OverloadChoice::getName() const {
switch (getKind()) {
case OverloadChoiceKind::Decl:
case OverloadChoiceKind::DeclViaDynamic:
case OverloadChoiceKind::DeclViaBridge:
case OverloadChoiceKind::DeclViaUnwrappedOptional:
return getDecl()->getName();
case OverloadChoiceKind::KeyPathApplication:
// TODO: This should probably produce subscript(keyPath:), but we
// don't currently pre-filter subscript overload sets by argument
// keywords, so "subscript" is still the name that keypath subscripts
// are looked up by.
return DeclBaseName::createSubscript();
case OverloadChoiceKind::DynamicMemberLookup:
case OverloadChoiceKind::KeyPathDynamicMemberLookup:
return DeclName(DynamicMember.getPointer());
case OverloadChoiceKind::TupleIndex:
llvm_unreachable("no name!");
}
llvm_unreachable("Unhandled OverloadChoiceKind in switch.");
}
Optional<IUOReferenceKind>
OverloadChoice::getIUOReferenceKind(ConstraintSystem &cs,
bool forSecondApplication) const {
auto *decl = getDeclOrNull();
if (!decl || !decl->isImplicitlyUnwrappedOptional())
return None;
// If this isn't an IUO return () -> T!, it's an IUO value.
if (!decl->getInterfaceType()->is<AnyFunctionType>())
return IUOReferenceKind::Value;
auto refKind = getFunctionRefKind();
assert(!forSecondApplication || refKind == FunctionRefKind::DoubleApply);
switch (refKind) {
case FunctionRefKind::Unapplied:
case FunctionRefKind::Compound:
// Such references never produce IUOs.
return None;
case FunctionRefKind::SingleApply:
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;
}
}
return IUOReferenceKind::ReturnValue;
}
SolutionResult ConstraintSystem::salvage() {
if (isDebugMode()) {
llvm::errs() << "---Attempting to salvage and emit diagnostics---\n";
}
setPhase(ConstraintSystemPhase::Diagnostics);
// Attempt to solve again, capturing all states that come from our attempts to
// select overloads or bind type variables.
//
// FIXME: can this be removed? We need to arrange for recordFixes to be
// eliminated.
SmallVector<Solution, 2> viable;
viable.clear();
{
// Set up solver state.
SolverState state(*this, FreeTypeVariableBinding::Disallow);
state.recordFixes = true;
// Solve the system.
solveImpl(viable);
// If we hit a threshold, we're done.
if (isTooComplex(viable))
return SolutionResult::forTooComplex(getTooComplexRange());
// Before removing any "fixed" solutions, let's check
// if ambiguity is caused by fixes and diagnose if possible.
if (diagnoseAmbiguityWithFixes(viable))
return SolutionResult::forAmbiguous(viable);
// Check whether we have a best solution; this can happen if we found
// a series of fixes that worked.
if (auto best = findBestSolution(viable, /*minimize=*/true)) {
if (*best != 0)
viable[0] = std::move(viable[*best]);
viable.erase(viable.begin() + 1, viable.end());
return SolutionResult::forSolved(std::move(viable[0]));
}
// FIXME: If we were able to actually fix things along the way,
// we may have to hunt for the best solution. For now, we don't care.
// Remove solutions that require fixes; the fixes in those systems should
// be diagnosed rather than any ambiguity.
auto hasFixes = [](const Solution &sol) { return !sol.Fixes.empty(); };
auto newEnd = std::remove_if(viable.begin(), viable.end(), hasFixes);
viable.erase(newEnd, viable.end());
// If there are multiple solutions, try to diagnose an ambiguity.
if (viable.size() > 1) {
if (isDebugMode()) {
auto &log = llvm::errs();
log << "---Ambiguity error: " << viable.size()
<< " solutions found---\n";
int i = 0;
for (auto &solution : viable) {
log << "---Ambiguous solution #" << i++ << "---\n";
solution.dump(log);
log << "\n";
}
}
if (diagnoseAmbiguity(viable)) {
return SolutionResult::forAmbiguous(viable);
}
}
// Fall through to produce diagnostics.
}
// Could not produce a specific diagnostic; punt to the client.
return SolutionResult::forUndiagnosedError();
}
static void diagnoseOperatorAmbiguity(ConstraintSystem &cs,
Identifier operatorName,
ArrayRef<Solution> solutions,
ConstraintLocator *locator) {
auto &ctx = cs.getASTContext();
auto &DE = ctx.Diags;
auto *anchor = castToExpr(locator->getAnchor());
auto *applyExpr = cast<ApplyExpr>(cs.getParentExpr(anchor));
auto isEnumWithAssociatedValues = [](Type type) -> bool {
if (auto *enumType = type->getAs<EnumType>())
return !enumType->getDecl()->hasOnlyCasesWithoutAssociatedValues();
return false;
};
const auto &solution = solutions.front();
if (auto *binaryOp = dyn_cast<BinaryExpr>(applyExpr)) {
auto *lhs = binaryOp->getLHS();
auto *rhs = binaryOp->getRHS();
auto lhsType =
solution.simplifyType(solution.getType(lhs))->getRValueType();
auto rhsType =
solution.simplifyType(solution.getType(rhs))->getRValueType();
if (lhsType->isEqual(rhsType)) {
DE.diagnose(anchor->getLoc(), diag::cannot_apply_binop_to_same_args,
operatorName.str(), lhsType)
.highlight(lhs->getSourceRange())
.highlight(rhs->getSourceRange());
if (isStandardComparisonOperator(binaryOp->getFn()) &&
isEnumWithAssociatedValues(lhsType)) {
DE.diagnose(applyExpr->getLoc(),
diag::no_binary_op_overload_for_enum_with_payload,
operatorName.str());
return;
}
} else if (operatorName == ctx.Id_MatchOperator) {
DE.diagnose(anchor->getLoc(), diag::cannot_match_expr_pattern_with_value,
lhsType, rhsType);
} else {
DE.diagnose(anchor->getLoc(), diag::cannot_apply_binop_to_args,
operatorName.str(), lhsType, rhsType)
.highlight(lhs->getSourceRange())
.highlight(rhs->getSourceRange());
}
} else {
auto *arg = applyExpr->getArgs()->getUnlabeledUnaryExpr();
assert(arg && "Expected a unary arg");
auto argType = solution.simplifyType(solution.getType(arg));
DE.diagnose(anchor->getLoc(), diag::cannot_apply_unop_to_arg,
operatorName.str(), argType->getRValueType());
}
std::set<std::string> parameters;
for (const auto &solution : solutions) {
auto overload = solution.getOverloadChoice(locator);
auto overloadType = overload.adjustedOpenedType;
// Let's suggest only concrete overloads here.
// Notes are going to take care of the rest,
// since printing types like `(Self, Self)` is not
// really useful.
if (overloadType->hasTypeVariable())
continue;
if (auto *fnType = overloadType->getAs<FunctionType>())
parameters.insert(
FunctionType::getParamListAsString(fnType->getParams()));
}
// All of the overload choices had generic parameters like `Self`.
if (parameters.empty())
return;
DE.diagnose(anchor->getLoc(), diag::suggest_partial_overloads,
/*isResult=*/false, operatorName.str(),
llvm::join(parameters, ", "));
}
std::string swift::describeGenericType(ValueDecl *GP, bool includeName) {
if (!GP)
return "";
Decl *parent = nullptr;
if (auto *AT = dyn_cast<AssociatedTypeDecl>(GP)) {
parent = AT->getProtocol();
} else {
auto *dc = GP->getDeclContext();
parent = dc->getInnermostDeclarationDeclContext();
}
if (!parent)
return "";
llvm::SmallString<64> result;
llvm::raw_svector_ostream OS(result);
OS << Decl::getDescriptiveKindName(GP->getDescriptiveKind());
if (includeName && GP->hasName())
OS << " '" << GP->getBaseName() << "'";
OS << " of ";
OS << Decl::getDescriptiveKindName(parent->getDescriptiveKind());
if (auto *decl = dyn_cast<ValueDecl>(parent)) {
if (decl->hasName())
OS << " '" << decl->getName() << "'";
}
return OS.str().str();
}
/// Special handling of conflicts associated with generic arguments.
///
/// func foo<T>(_: T, _: T) {}
/// func bar(x: Int, y: Float) {
/// foo(x, y)
/// }
///
/// It's done by first retrieving all generic parameters from each solution,
/// filtering bindings into a distinct set and diagnosing any differences.
static bool diagnoseConflictingGenericArguments(ConstraintSystem &cs,
const SolutionDiff &diff,
ArrayRef<Solution> solutions) {
if (!diff.overloads.empty())
return false;
bool noFixes = llvm::all_of(solutions, [](const Solution &solution) -> bool {
const auto score = solution.getFixedScore();
return score.Data[SK_Fix] == 0 && solution.Fixes.empty();
});
bool allMismatches =
llvm::all_of(solutions, [](const Solution &solution) -> bool {
return llvm::all_of(
solution.Fixes, [](const ConstraintFix *fix) -> bool {
return fix->getKind() == FixKind::AllowArgumentTypeMismatch ||
fix->getKind() == FixKind::AllowFunctionTypeMismatch ||
fix->getKind() == FixKind::AllowTupleTypeMismatch ||
fix->getKind() == FixKind::GenericArgumentsMismatch ||
fix->getKind() == FixKind::InsertCall;
});
});
if (!noFixes && !allMismatches)
return false;
auto &DE = cs.getASTContext().Diags;
llvm::SmallDenseMap<TypeVariableType *,
std::pair<GenericTypeParamType *, SourceLoc>, 4>
genericParams;
// Consider all representative type variables across all solutions.
for (auto &solution : solutions) {
for (auto &typeBinding : solution.typeBindings) {
auto *typeVar = typeBinding.first;
if (auto *GP = typeVar->getImpl().getGenericParameter()) {
auto *locator = typeVar->getImpl().getLocator();
auto *repr = cs.getRepresentative(typeVar);
// If representative is another generic parameter let's
// use its generic parameter type instead of originator's,
// but it's possible that generic parameter is equated to
// some other type e.g.
//
// func foo<T>(_: T) -> T {}
//
// In this case when reference to function `foo` is "opened"
// type variable representing `T` would be equated to
// type variable representing a result type of the reference.
if (auto *reprGP = repr->getImpl().getGenericParameter())
GP = reprGP;
genericParams[repr] = {GP, getLoc(locator->getAnchor())};
}
}
}
llvm::SmallDenseMap<std::pair<GenericTypeParamType *, SourceLoc>,
SmallVector<Type, 4>>
conflicts;
for (const auto &entry : genericParams) {
auto *typeVar = entry.first;
auto GP = entry.second;
llvm::SmallSetVector<Type, 4> arguments;
for (const auto &solution : solutions) {
auto type = solution.typeBindings.lookup(typeVar);
// Type variables gathered from a solution's type binding context may not
// exist in another given solution because some solutions may have
// additional type variables not present in other solutions due to taking
// different paths in the solver.
if (!type)
continue;
// Contextual opaque result type is uniquely identified by
// declaration it's associated with, so we have to compare
// declarations instead of using pointer equality on such types.
if (auto *opaque = type->getAs<OpaqueTypeArchetypeType>()) {
auto *decl = opaque->getDecl();
arguments.remove_if([&](Type argType) -> bool {
if (auto *otherOpaque = argType->getAs<OpaqueTypeArchetypeType>()) {
return decl == otherOpaque->getDecl();
}
return false;
});
}
arguments.insert(type);
}
if (arguments.size() > 1)
conflicts[GP].append(arguments.begin(), arguments.end());
}
auto getGenericTypeDecl = [&](ArchetypeType *archetype) -> ValueDecl * {
auto type = archetype->getInterfaceType();
if (auto *GTPT = type->getAs<GenericTypeParamType>())
return GTPT->getDecl();
if (auto *DMT = type->getAs<DependentMemberType>())
return DMT->getAssocType();
return nullptr;
};
bool diagnosed = false;
for (auto &conflict : conflicts) {
SourceLoc loc;
GenericTypeParamType *GP;
std::tie(GP, loc) = conflict.first;
auto conflictingArguments = conflict.second;
llvm::SmallString<64> arguments;
llvm::raw_svector_ostream OS(arguments);
interleave(
conflictingArguments,
[&](Type argType) {
OS << "'" << argType << "'";
if (auto *opaque = argType->getAs<OpaqueTypeArchetypeType>()) {
auto *decl = opaque->getDecl()->getNamingDecl();
OS << " (result type of '" << decl->getBaseName().userFacingName()
<< "')";
return;
}
if (auto archetype = argType->getAs<ArchetypeType>()) {
if (auto *GTD = getGenericTypeDecl(archetype))
OS << " (" << describeGenericType(GTD) << ")";
}
},
[&OS] { OS << " vs. "; });
DE.diagnose(loc, diag::conflicting_arguments_for_generic_parameter, GP,
OS.str());
diagnosed = true;
}
return diagnosed;
}
/// Diagnose ambiguity related to overloaded declarations where only
/// *some* of the overload choices have ephemeral pointer warnings/errors
/// associated with them. Such situations have be handled specifically
/// because ephemeral fixes do not affect the score.
///
/// If all of the overloads have ephemeral fixes associated with them
/// it's much easier to diagnose through notes associated with each fix.
static bool
diagnoseAmbiguityWithEphemeralPointers(ConstraintSystem &cs,
ArrayRef<Solution> solutions) {
unsigned numSolutionsWithFixes = 0;
for (const auto &solution : solutions) {
if (solution.Fixes.empty()) {
continue;
}
if (!llvm::all_of(solution.Fixes, [](const ConstraintFix *fix) {
return fix->getKind() == FixKind::TreatEphemeralAsNonEphemeral;
}))
return false;
numSolutionsWithFixes += 1;
}
// If all or no solutions have fixes for ephemeral pointers, let's
// let `diagnoseAmbiguityWithFixes` diagnose the problem.
if (numSolutionsWithFixes == 0 ||
numSolutionsWithFixes == solutions.size())
return false;
// If only some of the solutions have ephemeral pointer fixes
// let's let `diagnoseAmbiguity` diagnose the problem either
// with affected argument or related declaration e.g. function ref.
return cs.diagnoseAmbiguity(solutions);
}
static bool diagnoseAmbiguityWithContextualType(
ConstraintSystem &cs, SolutionDiff &solutionDiff,
ArrayRef<std::pair<const Solution *, const ConstraintFix *>> aggregateFix,
ArrayRef<Solution> solutions) {
// Diagnose only if contextual failure is associated with every solution.
if (aggregateFix.size() < solutions.size())
return false;
auto getResultType =
[](const std::pair<const Solution *, const ConstraintFix *> &entry)
-> Type {
auto &solution = *entry.first;
auto anchor = entry.second->getLocator()->getAnchor();
return solution.simplifyType(solution.getType(anchor));
};
auto resultType = getResultType(aggregateFix.front());
// If right-hand side of the conversion (result of the AST node)
// is the same across all of the solutions let's diagnose it as if
// it it as a single failure.
if (llvm::all_of(
aggregateFix,
[&](const std::pair<const Solution *, const ConstraintFix *> &entry) {
return resultType->isEqual(getResultType(entry));
})) {
auto &fix = aggregateFix.front();
return fix.second->diagnose(*fix.first, /*asNote=*/false);
}
// If result types are different it could only mean that this is an attempt
// to convert a reference to, or call of overloaded declaration to a
// particular type.
auto &solution = *aggregateFix.front().first;
auto *locator = aggregateFix.front().second->getLocator();
auto *calleeLocator = solution.getCalleeLocator(locator);
auto result =
llvm::find_if(solutionDiff.overloads,
[&calleeLocator](const SolutionDiff::OverloadDiff &entry) {
return entry.locator == calleeLocator;
});
if (result == solutionDiff.overloads.end())
return false;
auto &DE = cs.getASTContext().Diags;
auto anchor = locator->getAnchor();
auto name = result->choices.front().getName();
auto contextualTy = solution.getContextualType(anchor);
assert(contextualTy);
DE.diagnose(getLoc(anchor),
contextualTy->is<ProtocolType>()
? diag::no_overloads_have_result_type_conformance
: diag::no_candidates_match_result_type,
name.getBaseName().userFacingName(), contextualTy);
for (const auto &solution : solutions) {
auto overload = solution.getOverloadChoice(calleeLocator);
if (auto *decl = overload.choice.getDeclOrNull()) {
auto type = solution.simplifyType(overload.boundType);
if (isExpr<ApplyExpr>(anchor) || isExpr<SubscriptExpr>(anchor)) {
auto fnType = type->castTo<FunctionType>();
DE.diagnose(
decl,
contextualTy->is<ProtocolType>()
? diag::overload_result_type_does_not_conform
: diag::cannot_convert_candidate_result_to_contextual_type,
decl->getName(), fnType->getResult(), contextualTy);
} else {
DE.diagnose(decl, diag::found_candidate_type, type);
}
}
}
return true;
}
static bool diagnoseAmbiguity(
ConstraintSystem &cs, const SolutionDiff::OverloadDiff &ambiguity,
ArrayRef<std::pair<const Solution *, const ConstraintFix *>> aggregateFix,
ArrayRef<Solution> solutions) {
auto *locator = aggregateFix.front().second->getLocator();
auto anchor = aggregateFix.front().second->getAnchor();
auto &DE = cs.getASTContext().Diags;
llvm::SmallPtrSet<ValueDecl *, 4> localAmbiguity;
{
for (auto &entry : aggregateFix) {
const auto &solution = entry.first;
const auto &overload = solution->getOverloadChoice(ambiguity.locator);
auto *choice = overload.choice.getDeclOrNull();
// It's not possible to diagnose different kinds of overload choices.
if (!choice)
return false;
localAmbiguity.insert(choice);
}
}
if (localAmbiguity.empty())
return false;
// If all of the fixes are rooted in the same choice.
if (localAmbiguity.size() == 1) {
auto &primaryFix = aggregateFix.front();
return primaryFix.second->diagnose(*primaryFix.first);
}
{
auto fixKind = aggregateFix.front().second->getKind();
if (llvm::all_of(
aggregateFix, [&](const std::pair<const Solution *,
const ConstraintFix *> &entry) {
auto &fix = entry.second;
return fix->getKind() == fixKind && fix->getLocator() == locator;
})) {
auto *primaryFix = aggregateFix.front().second;
if (primaryFix->diagnoseForAmbiguity(aggregateFix))
return true;
}
}
auto *decl = *localAmbiguity.begin();
auto *commonCalleeLocator = ambiguity.locator;
bool diagnosed = true;
{
DiagnosticTransaction transaction(DE);
auto commonAnchor = commonCalleeLocator->getAnchor();
if (auto *callExpr = getAsExpr<CallExpr>(commonAnchor))
commonAnchor = callExpr->getDirectCallee();
const auto name = decl->getName();
// Emit an error message for the ambiguity.
if (locator->isForContextualType()) {
auto baseName = name.getBaseName();
DE.diagnose(getLoc(commonAnchor), diag::no_candidates_match_result_type,
baseName.userFacingName(),
cs.getContextualType(anchor, /*forConstraint=*/false));
} else if (name.isOperator()) {
auto *anchor = castToExpr(commonCalleeLocator->getAnchor());
// If operator is "applied" e.g. `1 + 2` there are tailored
// diagnostics in case of ambiguity, but if it's referenced
// e.g. `arr.sort(by: <)` it's better to produce generic error
// and a note per candidate.
if (auto *parentExpr = cs.getParentExpr(anchor)) {
if (auto *apply = dyn_cast<ApplyExpr>(parentExpr)) {
if (apply->getFn() == anchor) {
diagnoseOperatorAmbiguity(cs, name.getBaseIdentifier(), solutions,
commonCalleeLocator);
return true;
}
}
}
DE.diagnose(anchor->getLoc(), diag::no_overloads_match_exactly_in_call,
/*isApplication=*/false, decl->getDescriptiveKind(),
name.isSpecial(), name.getBaseName());
} else {
bool isApplication = llvm::any_of(solutions, [&](const auto &S) {
return llvm::any_of(S.argumentLists, [&](const auto &pair) {
return pair.first->getAnchor() == commonAnchor;
});
});
DE.diagnose(getLoc(commonAnchor),
diag::no_overloads_match_exactly_in_call, isApplication,
decl->getDescriptiveKind(), name.isSpecial(),
name.getBaseName());
}
// Produce candidate notes
SmallPtrSet<ValueDecl *, 4> distinctChoices;
llvm::SmallSet<CanType, 4> candidateTypes;
for (const auto &solution : solutions) {
auto overload = solution.getOverloadChoice(commonCalleeLocator);
auto *decl = overload.choice.getDecl();
auto type = solution.simplifyType(overload.adjustedOpenedType);
// Skip if we've already produced a note for this overload
if (!distinctChoices.insert(decl).second)
continue;
auto noteLoc =
decl->getLoc().isInvalid() ? getLoc(commonAnchor) : decl->getLoc();
if (solution.Fixes.size() == 1) {
diagnosed &=
solution.Fixes.front()->diagnose(solution, /*asNote*/ true);
} else if (llvm::all_of(solution.Fixes, [&](ConstraintFix *fix) {
return fix->getLocator()
->findLast<LocatorPathElt::ApplyArgument>()
.hasValue();
})) {
// All fixes have to do with arguments, so let's show the parameter
// lists.
//
// It's possible that function type is wrapped in an optional
// if it's from `@objc optional` method, so we need to ignore that.
auto *fn =
type->lookThroughAllOptionalTypes()->getAs<AnyFunctionType>();
assert(fn);
auto *argList =
solution.getArgumentList(solution.Fixes.front()->getLocator());
assert(argList);
if (fn->getNumParams() == 1 && argList->isUnary()) {
const auto &param = fn->getParams()[0];
auto argTy = solution.getResolvedType(argList->getUnaryExpr());
DE.diagnose(noteLoc, diag::candidate_has_invalid_argument_at_position,
solution.simplifyType(param.getPlainType()),
/*position=*/1, param.isInOut(), argTy);
} else {
DE.diagnose(noteLoc, diag::candidate_partial_match,
fn->getParamListAsString(fn->getParams()));
}
} else {
// Emit a general "found candidate" note
if (decl->getLoc().isInvalid()) {
if (candidateTypes.insert(type->getCanonicalType()).second)
DE.diagnose(getLoc(commonAnchor), diag::found_candidate_type, type);
} else {
DE.diagnose(noteLoc, diag::found_candidate);
}
}
}
// If not all of the fixes produced a note, we can't diagnose this.
if (!diagnosed)
transaction.abort();
}
return diagnosed;
}
using FixInContext = std::pair<const Solution *, const ConstraintFix *>;
// Attempts to diagnose function call ambiguities of types inferred for a result
// generic parameter from contextual type and a closure argument that
// conflicting infer a different type for the same argument. Example:
// func callit<T>(_ f: () -> T) -> T {
// f()
// }
//
// func context() -> Int {
// callit {
// print("hello")
// }
// }
// Where generic argument `T` can be inferred both as `Int` from contextual
// result and `Void` from the closure argument result.
static bool diagnoseContextualFunctionCallGenericAmbiguity(
ConstraintSystem &cs, ArrayRef<FixInContext> contextualFixes,
ArrayRef<FixInContext> allFixes) {
if (contextualFixes.empty())
return false;
auto contextualFix = contextualFixes.front();
if (!std::all_of(contextualFixes.begin() + 1, contextualFixes.end(),
[&contextualFix](FixInContext fix) {
return fix.second->getLocator() ==
contextualFix.second->getLocator();
}))
return false;
auto fixLocator = contextualFix.second->getLocator();
auto contextualAnchor = fixLocator->getAnchor();
auto *AE = getAsExpr<ApplyExpr>(contextualAnchor);
// All contextual failures anchored on the same function call.
if (!AE)
return false;
auto fnLocator = cs.getConstraintLocator(AE->getSemanticFn());
auto overload = contextualFix.first->getOverloadChoiceIfAvailable(fnLocator);
if (!overload)
return false;
auto applyFnType = overload->adjustedOpenedType->castTo<FunctionType>();
auto resultTypeVar = applyFnType->getResult()->getAs<TypeVariableType>();
if (!resultTypeVar)
return false;
auto *GP = resultTypeVar->getImpl().getGenericParameter();
if (!GP)
return false;
auto applyLoc =
cs.getConstraintLocator(AE, {LocatorPathElt::ApplyArgument()});
auto argMatching =
contextualFix.first->argumentMatchingChoices.find(applyLoc);
if (argMatching == contextualFix.first->argumentMatchingChoices.end()) {
return false;
}
auto *args = AE->getArgs();
llvm::SmallVector<ClosureExpr *, 2> closureArguments;
for (auto i : indices(*args)) {
auto *closure = getAsExpr<ClosureExpr>(args->getExpr(i));
if (!closure)
continue;
auto argParamMatch = argMatching->second.parameterBindings[i];
auto param = applyFnType->getParams()[argParamMatch.front()];
auto paramFnType = param.getPlainType()->getAs<FunctionType>();
if (!paramFnType)
continue;
if (cs.typeVarOccursInType(resultTypeVar, paramFnType->getResult()))
closureArguments.push_back(closure);
}
// If no closure result's involves the generic parameter, just bail because we
// won't find a conflict.
if (closureArguments.empty())
return false;
// At least one closure where result type involves the generic parameter.
// So let's try to collect the set of fixed types for the generic parameter
// from all the closure contextual fix/solutions and if there are more than
// one fixed type diagnose it.
llvm::SmallSetVector<Type, 4> genericParamInferredTypes;
for (auto &fix : contextualFixes)
genericParamInferredTypes.insert(fix.first->getFixedType(resultTypeVar));
if (llvm::all_of(allFixes, [&](FixInContext fix) {
auto fixLocator = fix.second->getLocator();
if (fixLocator->isForContextualType())
return true;
if (!(fix.second->getKind() == FixKind::IgnoreContextualType ||
fix.second->getKind() == FixKind::AllowTupleTypeMismatch))
return false;
auto anchor = fixLocator->getAnchor();
if (!(anchor == contextualAnchor ||
fixLocator->isLastElement<LocatorPathElt::ClosureResult>() ||
fixLocator->isLastElement<LocatorPathElt::ClosureBody>()))
return false;
genericParamInferredTypes.insert(
fix.first->getFixedType(resultTypeVar));
return true;
})) {
if (genericParamInferredTypes.size() != 2)
return false;
auto &DE = cs.getASTContext().Diags;
llvm::SmallString<64> arguments;
llvm::raw_svector_ostream OS(arguments);
interleave(
genericParamInferredTypes,
[&](Type argType) { OS << "'" << argType << "'"; },
[&OS] { OS << " vs. "; });
DE.diagnose(AE->getLoc(), diag::conflicting_arguments_for_generic_parameter,
GP, OS.str());
DE.diagnose(AE->getLoc(),
diag::generic_parameter_inferred_from_result_context, GP,
genericParamInferredTypes.back());
DE.diagnose(closureArguments.front()->getStartLoc(),
diag::generic_parameter_inferred_from_closure, GP,
genericParamInferredTypes.front());
return true;
}
return false;
}
bool ConstraintSystem::diagnoseAmbiguityWithFixes(
SmallVectorImpl<Solution> &solutions) {
if (solutions.empty())
return false;
SolutionDiff solutionDiff(solutions);
if (diagnoseConflictingGenericArguments(*this, solutionDiff, solutions))
return true;
if (auto bestScore = solverState->BestScore) {
solutions.erase(llvm::remove_if(solutions,
[&](const Solution &solution) {
return solution.getFixedScore() >
*bestScore;
}),
solutions.end());
if (llvm::all_of(solutions, [&](const Solution &solution) {
auto score = solution.getFixedScore();
return score.Data[SK_Fix] == 0 && solution.Fixes.empty();
}))
return false;
}
if (solutions.size() < 2)
return false;
if (diagnoseAmbiguityWithEphemeralPointers(*this, solutions))
return true;
if (isDebugMode()) {
auto &log = llvm::errs();
log << "--- Ambiguity: Considering #" << solutions.size()
<< " solutions with fixes ---\n";
int i = 0;
for (auto &solution : solutions) {
log << "\n--- Solution #" << i++ << "---\n";
solution.dump(log);
log << "\n";
}
}
// If there either no fixes at all or all of the are warnings,
// let's diagnose this as regular ambiguity.
if (llvm::all_of(solutions, [](const Solution &solution) {
return llvm::all_of(solution.Fixes, [](const ConstraintFix *fix) {
return !fix->isFatal();
});
})) {
return diagnoseAmbiguity(solutions);
}
// Algorithm is as follows:
//
// a. Aggregate all of the available fixes based on callee locator;
// b. For each ambiguous overload match aggregated fixes and diagnose;
// c. Discard all of the fixes which have been already considered
// as part of overload diagnostics;
// d. Diagnose remaining (uniqued based on kind + locator) fixes
// iff they appear in all of the solutions.
llvm::SmallSetVector<FixInContext, 4> fixes;
for (auto &solution : solutions) {
for (auto *fix : solution.Fixes) {
// If the fix doesn't affect the solution score, it is not the
// source of ambiguity or failures.
// Ignore warnings in favor of actual error fixes,
// because they are not the source of ambiguity/failures.
if (!fix->impact())
continue;
fixes.insert({&solution, fix});
}
}
llvm::MapVector<ConstraintLocator *, SmallVector<FixInContext, 4>>
fixesByCallee;
llvm::SmallVector<FixInContext, 4> contextualFixes;
for (const auto &entry : fixes) {
const auto &solution = *entry.first;
const auto *fix = entry.second;
auto *locator = fix->getLocator();
if (locator->isForContextualType()) {
contextualFixes.push_back({&solution, fix});
continue;
}
auto *calleeLocator = solution.getCalleeLocator(locator);
fixesByCallee[calleeLocator].push_back({&solution, fix});
}
bool diagnosed = false;
// All of the fixes which have been considered already.
llvm::SmallSetVector<FixInContext, 4> consideredFixes;
for (const auto &ambiguity : solutionDiff.overloads) {
auto fixes = fixesByCallee.find(ambiguity.locator);
if (fixes == fixesByCallee.end())
continue;
auto aggregate = fixes->second;
diagnosed |= ::diagnoseAmbiguity(*this, ambiguity, aggregate, solutions);
consideredFixes.insert(aggregate.begin(), aggregate.end());
}
if (diagnoseAmbiguityWithContextualType(*this, solutionDiff, contextualFixes,
solutions)) {
consideredFixes.insert(contextualFixes.begin(), contextualFixes.end());
diagnosed |= true;
}
// Remove all of the fixes which have been attached to ambiguous
// overload choices.
fixes.set_subtract(consideredFixes);
llvm::MapVector<std::pair<FixKind, ConstraintLocator *>,
SmallVector<FixInContext, 4>>
fixesByKind;
for (const auto &entry : fixes) {
const auto *fix = entry.second;
fixesByKind[{fix->getKind(), fix->getLocator()}].push_back(
{entry.first, fix});
}
// If leftover fix is contained in all of the solutions let's
// diagnose it as ambiguity.
for (const auto &entry : fixesByKind) {
if (llvm::all_of(solutions, [&](const Solution &solution) -> bool {
return llvm::any_of(
solution.Fixes, [&](const ConstraintFix *fix) -> bool {
return std::make_pair(fix->getKind(), fix->getLocator()) ==
entry.first;
});
})) {
auto &aggregate = entry.second;
diagnosed |= aggregate.front().second->diagnoseForAmbiguity(aggregate);
}
}
if (!diagnosed && diagnoseContextualFunctionCallGenericAmbiguity(
*this, contextualFixes, fixes.getArrayRef()))
return true;
return diagnosed;
}
/// Determine the number of distinct overload choices in the
/// provided set.
static unsigned countDistinctOverloads(ArrayRef<OverloadChoice> choices) {
llvm::SmallPtrSet<void *, 4> uniqueChoices;
unsigned result = 0;
for (auto choice : choices) {
if (uniqueChoices.insert(choice.getOpaqueChoiceSimple()).second)
++result;
}
return result;
}
/// Determine the name of the overload in a set of overload choices.
static DeclName getOverloadChoiceName(ArrayRef<OverloadChoice> choices) {
DeclName name;
for (auto choice : choices) {
if (!choice.isDecl())
continue;
const DeclName nextName = choice.getDecl()->getName();
if (!name) {
name = nextName;
continue;
}
if (name != nextName) {
// Assume all choices have the same base name and only differ in
// argument labels. This may not be a great assumption, but we don't
// really have a way to recover for diagnostics otherwise.
return name.getBaseName();
}
}
return name;
}
/// Extend the given index map with all of the subexpressions in the given
/// expression.
static void extendPreorderIndexMap(
Expr *expr, llvm::DenseMap<Expr *, unsigned> &indexMap) {
class RecordingTraversal : public ASTWalker {
public:
llvm::DenseMap<Expr *, unsigned> &IndexMap;
unsigned Index = 0;
explicit RecordingTraversal(llvm::DenseMap<Expr *, unsigned> &indexMap)
: IndexMap(indexMap) { }
PreWalkResult<Expr *> walkToExprPre(Expr *E) override {
IndexMap[E] = Index;
++Index;
return Action::Continue(E);
}
};
RecordingTraversal traversal(indexMap);
expr->walk(traversal);
}
bool ConstraintSystem::diagnoseAmbiguity(ArrayRef<Solution> solutions) {
// Produce a diff of the solutions.
SolutionDiff diff(solutions);
// Find the locators which have the largest numbers of distinct overloads.
Optional<unsigned> bestOverload;
// Overloads are scored by lexicographical comparison of (# of distinct
// overloads, depth, *reverse* of the index). N.B. - cannot be used for the
// reversing: the score version of index == 0 should be > than that of 1, but
// -0 == 0 < UINT_MAX == -1, whereas ~0 == UINT_MAX > UINT_MAX - 1 == ~1.
auto score = [](unsigned depth, unsigned index, unsigned distinctOverloads) {
return std::make_tuple(depth, ~index, distinctOverloads);
};
auto bestScore = score(0, std::numeric_limits<unsigned>::max(), 0);
// Get a map of expressions to their depths and post-order traversal indices.
// Heuristically, all other things being equal, we should complain about the
// ambiguous expression that (1) is deepest, (2) comes earliest in the
// expression, or (3) has the most overloads.
llvm::DenseMap<Expr *, unsigned> indexMap;
for (auto expr : InputExprs) {
extendPreorderIndexMap(expr, indexMap);
}
for (unsigned i = 0, n = diff.overloads.size(); i != n; ++i) {
auto &overload = diff.overloads[i];
auto *locator = overload.locator;
ASTNode anchor;
// Simplification of member locator would produce a base expression,
// this is what we want for diagnostics but not for comparisons here
// because base expression is located at a different depth which would
// lead to incorrect results if both reference and base expression are
// ambiguous e.g. `test[x].count` if both `[x]` and `count` are ambiguous
// than simplification of `count` would produce `[x]` which is incorrect.
if (locator->isLastElement<LocatorPathElt::Member>() ||
locator->isLastElement<LocatorPathElt::ConstructorMember>()) {
anchor = locator->getAnchor();
} else {
anchor = simplifyLocatorToAnchor(overload.locator);
}
// If we can't resolve the locator to an anchor with no path,
// we can't diagnose this well.
if (!anchor)
continue;
// Index and Depth is only applicable to expressions.
unsigned index = 0;
unsigned depth = 0;
if (auto *expr = getAsExpr(anchor)) {
auto it = indexMap.find(expr);
if (it == indexMap.end())
continue;
index = it->second;
auto optDepth = getExprDepth(expr);
if (!optDepth)
continue;
depth = *optDepth;
}
// If we don't have a name to hang on to, it'll be hard to diagnose this
// overload.
if (!getOverloadChoiceName(overload.choices))
continue;
unsigned distinctOverloads = countDistinctOverloads(overload.choices);
// We need at least two overloads to make this interesting.
if (distinctOverloads < 2)
continue;
// If we have more distinct overload choices for this locator than for
// prior locators, just keep this locator.
auto thisScore = score(depth, index, distinctOverloads);
if (thisScore > bestScore) {
bestScore = thisScore;
bestOverload = i;
continue;
}
// We have better results. Ignore this one.
}
// FIXME: Should be able to pick the best locator, e.g., based on some
// depth-first numbering of expressions.
if (bestOverload) {
auto &overload = diff.overloads[*bestOverload];
// FIXME: We would prefer to emit the name as written, but that information
// is not sufficiently centralized in the AST.
DeclNameRef name(getOverloadChoiceName(overload.choices));
auto anchor = simplifyLocatorToAnchor(overload.locator);
if (!anchor) {
// It's not clear that this is actually valid. Just use the overload's
// anchor for release builds, but assert so we can properly diagnose
// this case if it happens to be hit. Note that the overload will
// *always* be anchored, otherwise everything would be broken, ie. this
// assertion would be the least of our worries.
anchor = overload.locator->getAnchor();
assert(false && "locator could not be simplified to anchor");
}
// Emit the ambiguity diagnostic.
auto &DE = getASTContext().Diags;
DE.diagnose(getLoc(anchor),
name.isOperator() ? diag::ambiguous_operator_ref
: diag::ambiguous_decl_ref,
name);
TrailingClosureAmbiguityFailure failure(solutions, anchor,
overload.choices);
if (failure.diagnoseAsNote())
return true;
// Emit candidates. Use a SmallPtrSet to make sure only emit a particular
// candidate once. FIXME: Why is one candidate getting into the overload
// set multiple times? (See also tryDiagnoseTrailingClosureAmbiguity.)
SmallPtrSet<Decl *, 8> EmittedDecls;
for (auto choice : overload.choices) {
switch (choice.getKind()) {
case OverloadChoiceKind::Decl:
case OverloadChoiceKind::DeclViaDynamic:
case OverloadChoiceKind::DeclViaBridge:
case OverloadChoiceKind::DeclViaUnwrappedOptional:
// FIXME: show deduced types, etc, etc.
if (EmittedDecls.insert(choice.getDecl()).second)
DE.diagnose(choice.getDecl(), diag::found_candidate);
break;
case OverloadChoiceKind::KeyPathApplication:
case OverloadChoiceKind::DynamicMemberLookup:
case OverloadChoiceKind::KeyPathDynamicMemberLookup:
// Skip key path applications and dynamic member lookups, since we don't
// want them to noise up unrelated subscript diagnostics.
break;
case OverloadChoiceKind::TupleIndex:
// FIXME: Actually diagnose something here.
break;
}
}
return true;
}
// FIXME: If we inferred different types for literals (for example),
// could diagnose ambiguity that way as well.
return false;
}
ConstraintLocator *
constraints::simplifyLocator(ConstraintSystem &cs, ConstraintLocator *locator,
SourceRange &range) {
auto path = locator->getPath();
auto anchor = locator->getAnchor();
simplifyLocator(anchor, path, range);
// If we didn't simplify anything, just return the input.
if (anchor == locator->getAnchor() &&
path.size() == locator->getPath().size()) {
return locator;
}
// If the old locator didn't have any summary flags, neither will the
// simplified version, as it must contain a subset of the path elements.
if (locator->getSummaryFlags() == 0)
return cs.getConstraintLocator(anchor, path, /*summaryFlags*/ 0);
return cs.getConstraintLocator(anchor, path);
}
void constraints::simplifyLocator(ASTNode &anchor,
ArrayRef<LocatorPathElt> &path,
SourceRange &range) {
range = SourceRange();
while (!path.empty()) {
switch (path[0].getKind()) {
case ConstraintLocator::ApplyArgument: {
auto *anchorExpr = castToExpr(anchor);
// If the next element is an ApplyArgToParam, we can simplify by looking
// into the index expression.
if (path.size() < 2)
break;
auto elt = path[1].getAs<LocatorPathElt::ApplyArgToParam>();
if (!elt)
break;
// Extract application argument.
if (auto *args = anchorExpr->getArgs()) {
if (elt->getArgIdx() < args->size()) {
anchor = args->getExpr(elt->getArgIdx());
path = path.slice(2);
continue;
}
}
break;
}
case ConstraintLocator::ApplyArgToParam:
llvm_unreachable("Cannot appear without ApplyArgument");
case ConstraintLocator::DynamicCallable: {
path = path.slice(1);
continue;
}
case ConstraintLocator::ApplyFunction:
case ConstraintLocator::FunctionResult:
// Extract application function.
if (auto applyExpr = getAsExpr<ApplyExpr>(anchor)) {
anchor = applyExpr->getFn();
path = path.slice(1);
continue;
}
// The subscript itself is the function.
if (auto subscriptExpr = getAsExpr<SubscriptExpr>(anchor)) {
anchor = subscriptExpr;
path = path.slice(1);
continue;
}
// If the anchor is an unapplied decl ref, there's nothing to extract.
if (isExpr<DeclRefExpr>(anchor) || isExpr<OverloadedDeclRefExpr>(anchor)) {
path = path.slice(1);
continue;
}
break;
case ConstraintLocator::AutoclosureResult:
case ConstraintLocator::LValueConversion:
case ConstraintLocator::DynamicType:
case ConstraintLocator::UnresolvedMember:
case ConstraintLocator::ImplicitCallAsFunction:
// Arguments in autoclosure positions, lvalue and rvalue adjustments,
// unresolved members, and implicit callAsFunction references are
// implicit.
path = path.slice(1);
continue;
case ConstraintLocator::TupleType:
path = path.slice(1);
continue;
case ConstraintLocator::NamedTupleElement:
case ConstraintLocator::TupleElement: {
// Extract tuple element.
auto elt = path[0].castTo<LocatorPathElt::AnyTupleElement>();
unsigned index = elt.getIndex();
if (auto tupleExpr = getAsExpr<TupleExpr>(anchor)) {
if (index < tupleExpr->getNumElements()) {
anchor = tupleExpr->getElement(index);
path = path.slice(1);
continue;
}
}
if (auto *CE = getAsExpr<CollectionExpr>(anchor)) {
if (index < CE->getNumElements()) {
anchor = CE->getElement(index);
path = path.slice(1);
continue;
}
}
break;
}
case ConstraintLocator::ConstructorMember:
// - This is really an implicit 'init' MemberRef, so point at the base,
// i.e. the TypeExpr.
// - For re-declarations we'd get an overloaded reference
// with multiple choices for the same type.
if (isExpr<TypeExpr>(anchor) || isExpr<OverloadedDeclRefExpr>(anchor)) {
range = SourceRange();
path = path.slice(1);
continue;
}
LLVM_FALLTHROUGH;
case ConstraintLocator::Member:
case ConstraintLocator::MemberRefBase:
if (auto UDE = getAsExpr<UnresolvedDotExpr>(anchor)) {
range = UDE->getNameLoc().getSourceRange();
anchor = UDE->getBase();
path = path.slice(1);
continue;
}
if (anchor.is<Pattern *>()) {
path = path.slice(1);
continue;
}
break;
case ConstraintLocator::SubscriptMember:
if (isExpr<SubscriptExpr>(anchor)) {
path = path.slice(1);
continue;
}
break;
case ConstraintLocator::ClosureBody:
case ConstraintLocator::ClosureResult:
if (auto CE = getAsExpr<ClosureExpr>(anchor)) {
if (CE->hasSingleExpressionBody()) {
anchor = CE->getSingleExpressionBody();
path = path.slice(1);
continue;
}
}
break;
case ConstraintLocator::ContextualType:
// This was just for identifying purposes, strip it off.
path = path.slice(1);
continue;
case ConstraintLocator::KeyPathComponent: {
auto elt = path[0].castTo<LocatorPathElt::KeyPathComponent>();
// If the next element is an ApplyArgument, we can simplify by looking
// into the index expression.
if (path.size() < 3 ||
path[1].getKind() != ConstraintLocator::ApplyArgument)
break;
auto applyArgElt = path[2].getAs<LocatorPathElt::ApplyArgToParam>();
if (!applyArgElt)
break;
auto argIdx = applyArgElt->getArgIdx();
if (auto *kpe = getAsExpr<KeyPathExpr>(anchor)) {
auto component = kpe->getComponents()[elt.getIndex()];
auto *args = component.getSubscriptArgs();
assert(args && "Trying to apply a component without args?");
if (argIdx < args->size()) {
anchor = args->getExpr(argIdx);
path = path.slice(3);
continue;
}
}
break;
}
case ConstraintLocator::Condition: {
if (auto *condStmt = getAsStmt<LabeledConditionalStmt>(anchor)) {
anchor = &condStmt->getCond().front();
} else {
anchor = castToExpr<IfExpr>(anchor)->getCondExpr();
}
path = path.slice(1);
continue;
}
case ConstraintLocator::TernaryBranch: {
auto branch = path[0].castTo<LocatorPathElt::TernaryBranch>();
if (auto *ifStmt = getAsStmt<IfStmt>(anchor)) {
anchor =
branch.forThen() ? ifStmt->getThenStmt() : ifStmt->getElseStmt();
} else {
auto *ifExpr = castToExpr<IfExpr>(anchor);
anchor =
branch.forThen() ? ifExpr->getThenExpr() : ifExpr->getElseExpr();
}
path = path.slice(1);
continue;
}
case ConstraintLocator::KeyPathDynamicMember:
case ConstraintLocator::ImplicitDynamicMemberSubscript: {
// Key path dynamic member lookup should be completely transparent.
path = path.slice(1);
continue;
}
case ConstraintLocator::ArgumentAttribute: {
// At this point we should have already found argument expression
// this attribute belongs to, so we can leave this element in place
// because it points out exact location useful for diagnostics.
break;
}
case ConstraintLocator::ResultBuilderBodyResult: {
path = path.slice(1);
break;
}
case ConstraintLocator::UnresolvedMemberChainResult: {
auto *resultExpr = castToExpr<UnresolvedMemberChainResultExpr>(anchor);
anchor = resultExpr->getSubExpr();
path = path.slice(1);
continue;
}
case ConstraintLocator::SyntacticElement: {
auto bodyElt = path[0].castTo<LocatorPathElt::SyntacticElement>();
anchor = bodyElt.getElement();
path = path.slice(1);
continue;
}
case ConstraintLocator::PatternMatch: {
auto patternElt = path[0].castTo<LocatorPathElt::PatternMatch>();
anchor = patternElt.getPattern();
path = path.slice(1);
continue;
}
case ConstraintLocator::PackType:
case ConstraintLocator::ParentType:
case ConstraintLocator::KeyPathType:
case ConstraintLocator::InstanceType:
case ConstraintLocator::PlaceholderType:
case ConstraintLocator::SequenceElementType:
case ConstraintLocator::ConstructorMemberType:
case ConstraintLocator::ExistentialConstraintType:
case ConstraintLocator::ProtocolCompositionSuperclassType:
break;
case ConstraintLocator::GenericArgument:
case ConstraintLocator::FunctionArgument:
case ConstraintLocator::SynthesizedArgument:
break;
case ConstraintLocator::DynamicLookupResult:
case ConstraintLocator::KeyPathComponentResult:
break;
case ConstraintLocator::GenericParameter:
break;
case ConstraintLocator::OpenedGeneric:
case ConstraintLocator::OpenedOpaqueArchetype:
break;
case ConstraintLocator::KeyPathRoot:
case ConstraintLocator::KeyPathValue:
break;
case ConstraintLocator::ProtocolRequirement:
case ConstraintLocator::ConditionalRequirement:
case ConstraintLocator::ConformanceRequirement:
case ConstraintLocator::TypeParameterRequirement:
break;
case ConstraintLocator::PackElement:
break;
case ConstraintLocator::PatternBindingElement: {
auto pattern = path[0].castTo<LocatorPathElt::PatternBindingElement>();
auto *patternBinding = cast<PatternBindingDecl>(anchor.get<Decl *>());
anchor = patternBinding->getInit(pattern.getIndex());
// If this pattern is uninitialized, let's use it as anchor.
if (!anchor)
anchor = patternBinding->getPattern(pattern.getIndex());
path = path.slice(1);
continue;
}
case ConstraintLocator::NamedPatternDecl: {
auto pattern = cast<NamedPattern>(anchor.get<Pattern *>());
anchor = pattern->getDecl();
path = path.slice(1);
break;
}
case ConstraintLocator::AnyPatternDecl: {
// This element is just a marker for `_` pattern since it doesn't
// have a declaration. We need to make sure that it only appaears
// when anchored on `AnyPattern`.
assert(getAsPattern<AnyPattern>(anchor));
path = path.slice(1);
break;
}
case ConstraintLocator::ImplicitConversion:
break;
case ConstraintLocator::Witness:
case ConstraintLocator::WrappedValue:
case ConstraintLocator::OptionalPayload:
case ConstraintLocator::ImplicitlyUnwrappedDisjunctionChoice:
break;
}
// If we get here, we couldn't simplify the path further.
break;
}
}
ASTNode constraints::simplifyLocatorToAnchor(ConstraintLocator *locator) {
if (!locator)
return nullptr;
auto anchor = locator->getAnchor();
if (!anchor)
return {};
SourceRange range;
auto path = locator->getPath();
simplifyLocator(anchor, path, range);
// We only want the new anchor if all the path elements have been simplified
// away.
return path.empty() ? anchor : nullptr;
}
Expr *constraints::getArgumentExpr(ASTNode node, unsigned index) {
auto *expr = getAsExpr(node);
if (!expr)
return nullptr;
auto *argList = expr->getArgs();
if (!argList)
return nullptr;
if (index >= argList->size())
return nullptr;
return argList->getExpr(index);
}
bool constraints::isAutoClosureArgument(Expr *argExpr) {
if (!argExpr)
return false;
if (auto *DRE = dyn_cast<DeclRefExpr>(argExpr)) {
if (auto *param = dyn_cast<ParamDecl>(DRE->getDecl()))
return param->isAutoClosure();
}
return false;
}
bool constraints::hasAppliedSelf(ConstraintSystem &cs,
const OverloadChoice &choice) {
return hasAppliedSelf(choice, [&cs](Type type) -> Type {
return cs.getFixedTypeRecursive(type, /*wantRValue=*/true);
});
}
bool constraints::hasAppliedSelf(const OverloadChoice &choice,
llvm::function_ref<Type(Type)> getFixedType) {
auto *decl = choice.getDeclOrNull();
if (!decl)
return false;
auto baseType = choice.getBaseType();
if (baseType)
baseType = getFixedType(baseType)->getRValueType();
// In most cases where we reference a declaration with a curried self
// parameter, it gets dropped from the type of the reference.
return decl->hasCurriedSelf() &&
doesMemberRefApplyCurriedSelf(baseType, decl);
}
/// Check whether given type conforms to `RawRepresentable` protocol
/// and return the witness type.
Type constraints::isRawRepresentable(ConstraintSystem &cs, Type type) {
auto *DC = cs.DC;
auto rawReprType = TypeChecker::getProtocol(
cs.getASTContext(), SourceLoc(), KnownProtocolKind::RawRepresentable);
if (!rawReprType)
return Type();
auto conformance = TypeChecker::conformsToProtocol(type, rawReprType,
DC->getParentModule());
if (conformance.isInvalid())
return Type();
return conformance.getTypeWitnessByName(type, cs.getASTContext().Id_RawValue);
}
void ConstraintSystem::generateConstraints(
SmallVectorImpl<Constraint *> &constraints, Type type,
ArrayRef<OverloadChoice> choices, DeclContext *useDC,
ConstraintLocator *locator, Optional<unsigned> favoredIndex,
bool requiresFix,
llvm::function_ref<ConstraintFix *(unsigned, const OverloadChoice &)>
getFix) {
auto recordChoice = [&](SmallVectorImpl<Constraint *> &choices,
unsigned index, const OverloadChoice &overload,
bool isFavored = false) {
auto *fix = getFix(index, overload);
// If fix is required but it couldn't be determined, this
// choice has be filtered out.
if (requiresFix && !fix)
return;
auto *choice = fix ? Constraint::createFixedChoice(*this, type, overload,
useDC, fix, locator)
: Constraint::createBindOverload(*this, type, overload,
useDC, locator);
if (isFavored)
choice->setFavored();
choices.push_back(choice);
};
if (favoredIndex) {
const auto &choice = choices[*favoredIndex];
assert(
(!choice.isDecl() || !isDeclUnavailable(choice.getDecl(), locator)) &&
"Cannot make unavailable decl favored!");
recordChoice(constraints, *favoredIndex, choice, /*isFavored=*/true);
}
for (auto index : indices(choices)) {
if (favoredIndex && (*favoredIndex == index))
continue;
recordChoice(constraints, index, choices[index]);
}
}
ConstraintLocator *
ConstraintSystem::getArgumentInfoLocator(ConstraintLocator *locator) {
auto anchor = locator->getAnchor();
// An empty locator which code completion uses for member references.
if (anchor.isNull() && locator->getPath().empty())
return nullptr;
if (locator->findLast<LocatorPathElt::ImplicitConversion>())
return locator;
// Applies and unresolved member exprs can have callee locators that are
// dependent on the type of their function, which may not have been resolved
// yet. Therefore we need to handle them specially.
if (auto *apply = getAsExpr<ApplyExpr>(anchor)) {
auto *fnExpr = getArgumentLabelTargetExpr(apply->getFn());
return getConstraintLocator(fnExpr);
}
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
// original call-site, which we can get by stripping away the
// KeyPathDynamicMember elements.
auto iter = path.begin();
if (locator->findFirst<LocatorPathElt::KeyPathDynamicMember>(iter)) {
ArrayRef<LocatorPathElt> newPath(path.begin(), iter);
return getConstraintLocator(anchor, newPath);
}
}
return getCalleeLocator(locator);
}
ArgumentList *ConstraintSystem::getArgumentList(ConstraintLocator *locator) {
if (!locator)
return nullptr;
if (auto *infoLocator = getArgumentInfoLocator(locator)) {
auto known = ArgumentLists.find(infoLocator);
if (known != ArgumentLists.end())
return known->second;
}
return nullptr;
}
void ConstraintSystem::associateArgumentList(ConstraintLocator *locator,
ArgumentList *args) {
assert(locator && locator->getAnchor());
auto *argInfoLoc = getArgumentInfoLocator(locator);
auto inserted = ArgumentLists.insert({argInfoLoc, args}).second;
assert(inserted && "Multiple argument lists at locator?");
(void)inserted;
}
ArgumentList *Solution::getArgumentList(ConstraintLocator *locator) const {
if (!locator)
return nullptr;
if (auto *infoLocator = constraintSystem->getArgumentInfoLocator(locator)) {
auto known = argumentLists.find(infoLocator);
if (known != argumentLists.end())
return known->second;
}
return nullptr;
}
#ifndef NDEBUG
/// 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;
}
#endif
Type Solution::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.
auto fixed = simplifyType(tvt);
return resolveInterfaceType(fixed->mapTypeOutOfContext());
}
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>
Solution::getFunctionArgApplyInfo(ConstraintLocator *locator) const {
// It's only valid to use `&` in argument positions, but we need
// to figure out exactly where it was used.
if (auto *argExpr = getAsExpr<InOutExpr>(locator->getAnchor())) {
auto *argLoc = getConstraintSystem().getArgumentLocator(argExpr);
if (!argLoc)
return None;
locator = argLoc;
}
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;
#ifndef NDEBUG
auto nextIter = iter + 1;
assert(!locator->findLast<LocatorPathElt::ApplyArgToParam>(nextIter) &&
"Multiple ApplyArgToParam components?");
#endif
// 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);
auto *argExpr = castToExpr(simplifyLocatorToAnchor(argLocator));
// If we were unable to simplify down to the argument expression, we don't
// know what this is.
if (!argExpr)
return None;
auto *argList = getArgumentList(argLocator);
if (!argList)
return None;
Optional<OverloadChoice> choice;
Type rawFnType;
auto *calleeLocator = getCalleeLocator(argLocator);
if (auto overload = getOverloadChoiceIfAvailable(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->adjustedOpenedType;
} else {
// If we didn't resolve an overload for the callee, we should be dealing
// with a call of an arbitrary function expr.
auto *call = castToExpr<CallExpr>(anchor);
rawFnType = getType(call->getFn());
// If callee couldn't be resolved due to expression
// issues e.g. it's a reference to an invalid member
// let's just return here.
if (simplifyType(rawFnType)->is<UnresolvedType>())
return None;
// A tuple construction is spelled in the AST as a function call, but
// is really more like a tuple conversion.
if (auto metaTy = simplifyType(rawFnType)->getAs<MetatypeType>()) {
if (metaTy->getInstanceType()->is<TupleType>())
return None;
}
assert(!shouldHaveDirectCalleeOverload(call) &&
"Should we have resolved a callee for this?");
}
// 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(
*choice, [this](Type type) -> Type { return simplifyType(type); }))
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::get(argList, argExpr, argIdx,
simplifyType(getType(argExpr)), paramIdx,
fnInterfaceType, fnType, callee);
}
bool constraints::isKnownKeyPathType(Type type) {
return type->isKeyPath() || type->isWritableKeyPath() ||
type->isReferenceWritableKeyPath() || type->isPartialKeyPath() ||
type->isAnyKeyPath();
}
bool constraints::hasExplicitResult(ClosureExpr *closure) {
auto &ctx = closure->getASTContext();
return evaluateOrDefault(ctx.evaluator,
ClosureHasExplicitResultRequest{closure}, false);
}
Type constraints::getConcreteReplacementForProtocolSelfType(ValueDecl *member) {
auto *DC = member->getDeclContext();
if (!DC->getSelfProtocolDecl())
return Type();
GenericSignature signature;
if (auto *genericContext = member->getAsGenericContext()) {
signature = genericContext->getGenericSignature();
} else {
signature = DC->getGenericSignatureOfContext();
}
auto selfTy = DC->getProtocolSelfType();
return signature->getConcreteType(selfTy);
}
static bool isOperator(Expr *expr, StringRef expectedName) {
auto name = getOperatorName(expr);
return name ? name->is(expectedName) : false;
}
Optional<Identifier> constraints::getOperatorName(Expr *expr) {
ValueDecl *choice = nullptr;
if (auto *ODRE = dyn_cast_or_null<OverloadedDeclRefExpr>(expr)) {
choice = ODRE->getDecls().front();
} else if (auto *DRE = dyn_cast_or_null<DeclRefExpr>(expr)) {
choice = DRE->getDecl();
} else {
return None;
}
if (auto *FD = dyn_cast_or_null<AbstractFunctionDecl>(choice))
return FD->getBaseIdentifier();
return None;
}
bool constraints::isPatternMatchingOperator(ASTNode node) {
auto *expr = getAsExpr(node);
if (!expr) return false;
return isOperator(expr, "~=");
}
bool constraints::isStandardComparisonOperator(ASTNode node) {
auto *expr = getAsExpr(node);
if (!expr) return false;
if (auto opName = getOperatorName(expr)) {
return opName->isStandardComparisonOperator();
}
return false;
}
ConstraintLocator *ConstraintSystem::getArgumentLocator(Expr *expr) {
auto *application = getParentExpr(expr);
if (!application)
return nullptr;
// Drop all of the semantically insignificant exprs that might be wrapping an
// argument e.g. `test(((42)))`
while (application->getSemanticsProvidingExpr() == expr) {
application = getParentExpr(application);
if (!application)
return nullptr;
}
ArgumentList *argList = application->getArgs();
if (!argList && !isa<KeyPathExpr>(application))
return nullptr;
ConstraintLocator *loc = nullptr;
if (auto *KP = dyn_cast<KeyPathExpr>(application)) {
auto idx = KP->findComponentWithSubscriptArg(expr);
if (!idx)
return nullptr;
loc = getConstraintLocator(KP, {LocatorPathElt::KeyPathComponent(*idx)});
argList = KP->getComponents()[*idx].getSubscriptArgs();
} else {
loc = getConstraintLocator(application);
}
assert(argList);
auto argIdx = argList->findArgumentExpr(expr);
if (!argIdx)
return nullptr;
ParameterTypeFlags flags;
flags = flags.withInOut(argList->get(*argIdx).isInOut());
return getConstraintLocator(
loc, {LocatorPathElt::ApplyArgument(),
LocatorPathElt::ApplyArgToParam(*argIdx, *argIdx, flags)});
}
bool constraints::isOperatorArgument(ConstraintLocator *locator,
StringRef expectedOperator) {
if (!locator->findLast<LocatorPathElt::ApplyArgToParam>())
return false;
if (auto *AE = getAsExpr<ApplyExpr>(locator->getAnchor())) {
if (isa<PrefixUnaryExpr>(AE) || isa<BinaryExpr>(AE) ||
isa<PostfixUnaryExpr>(AE))
return expectedOperator.empty() ||
isOperator(AE->getFn(), expectedOperator);
}
return false;
}
bool constraints::isArgumentOfPatternMatchingOperator(
ConstraintLocator *locator) {
auto *binaryOp = getAsExpr<BinaryExpr>(locator->getAnchor());
if (!(binaryOp && binaryOp->isImplicit()))
return false;
return isPatternMatchingOperator(binaryOp->getFn());
}
bool constraints::isArgumentOfReferenceEqualityOperator(
ConstraintLocator *locator) {
return isOperatorArgument(locator, "===") ||
isOperatorArgument(locator, "!==");
}
bool ConstraintSystem::isArgumentOfImportedDecl(
ConstraintLocatorBuilder locator) {
SmallVector<LocatorPathElt, 4> path;
auto anchor = locator.getLocatorParts(path);
if (path.empty())
return false;
while (!path.empty()) {
const auto &last = path.back();
// Drop all of the `optional payload` or `generic argument`
// locator elements at the end of the path, they came from
// either value-to-optional promotion or optional-to-optional
// conversion.
if (last.is<LocatorPathElt::OptionalPayload>() ||
last.is<LocatorPathElt::GenericArgument>()) {
path.pop_back();
continue;
}
break;
}
auto *application = getCalleeLocator(getConstraintLocator(anchor, path));
auto overload = findSelectedOverloadFor(application);
if (!(overload && overload->choice.isDecl()))
return false;
auto *choice = overload->choice.getDecl();
return choice->hasClangNode();
}
ConversionEphemeralness
ConstraintSystem::isConversionEphemeral(ConversionRestrictionKind conversion,
ConstraintLocatorBuilder locator) {
switch (conversion) {
case ConversionRestrictionKind::ArrayToPointer:
case ConversionRestrictionKind::StringToPointer:
// Always ephemeral.
return ConversionEphemeralness::Ephemeral;
case ConversionRestrictionKind::InoutToPointer:
case ConversionRestrictionKind::InoutToCPointer: {
// Ephemeral, except if the expression is a reference to a global or
// static stored variable, or a directly accessed stored property on such a
// variable.
auto isDirectlyAccessedStoredVar = [&](ValueDecl *decl) -> bool {
auto *asd = dyn_cast_or_null<AbstractStorageDecl>(decl);
if (!asd)
return false;
// Check what access strategy is used for a read-write access. It must be
// direct-to-storage in order for the conversion to be non-ephemeral.
auto access = asd->getAccessStrategy(
AccessSemantics::Ordinary, AccessKind::ReadWrite,
DC->getParentModule(), DC->getResilienceExpansion());
return access.getKind() == AccessStrategy::Storage;
};
SourceRange range;
auto *argLoc = simplifyLocator(*this, getConstraintLocator(locator), range);
auto *subExpr =
castToExpr(argLoc->getAnchor())->getSemanticsProvidingExpr();
// Look through an InOutExpr if we have one. This is usually the case, but
// might not be if e.g we're applying an 'add missing &' fix.
if (auto *ioe = dyn_cast<InOutExpr>(subExpr))
subExpr = ioe->getSubExpr();
while (true) {
subExpr = subExpr->getSemanticsProvidingExpr();
// Look through force unwraps, which can be modelled as physical lvalue
// components.
if (auto *fve = dyn_cast<ForceValueExpr>(subExpr)) {
subExpr = fve->getSubExpr();
continue;
}
// Look through a member reference if it's directly accessed.
if (auto *ude = dyn_cast<UnresolvedDotExpr>(subExpr)) {
auto overload = findSelectedOverloadFor(ude);
// If we didn't find an overload, it hasn't been resolved yet.
if (!overload)
return ConversionEphemeralness::Unresolved;
// Tuple indices are always non-ephemeral.
auto *base = ude->getBase();
if (overload->choice.getKind() == OverloadChoiceKind::TupleIndex) {
subExpr = base;
continue;
}
// If we don't have a directly accessed declaration associated with the
// choice, it's ephemeral.
auto *member = overload->choice.getDeclOrNull();
if (!isDirectlyAccessedStoredVar(member))
return ConversionEphemeralness::Ephemeral;
// If we found a static member, the conversion is non-ephemeral. We can
// stop iterating as there's nothing interesting about the base.
if (member->isStatic())
return ConversionEphemeralness::NonEphemeral;
// For an instance member, the base must be an @lvalue struct type.
if (auto *lvt = simplifyType(getType(base))->getAs<LValueType>()) {
auto *nominal = lvt->getObjectType()->getAnyNominal();
if (isa_and_nonnull<StructDecl>(nominal)) {
subExpr = base;
continue;
}
}
return ConversionEphemeralness::Ephemeral;
}
break;
}
auto getBaseEphemeralness =
[&](ValueDecl *base) -> ConversionEphemeralness {
// We must have a base decl that's directly accessed.
if (!isDirectlyAccessedStoredVar(base))
return ConversionEphemeralness::Ephemeral;
// The base decl must either be static or global in order for it to be
// non-ephemeral.
if (base->isStatic() || base->getDeclContext()->isModuleScopeContext()) {
return ConversionEphemeralness::NonEphemeral;
} else {
return ConversionEphemeralness::Ephemeral;
}
};
// Fast path: We have a direct decl ref.
if (auto *dre = dyn_cast<DeclRefExpr>(subExpr))
return getBaseEphemeralness(dre->getDecl());
// Otherwise, try to find an overload for the base.
if (auto baseOverload = findSelectedOverloadFor(subExpr))
return getBaseEphemeralness(baseOverload->choice.getDeclOrNull());
// If we didn't find a base overload for a unresolved member or overloaded
// decl, it hasn't been resolved yet.
if (isa<UnresolvedMemberExpr>(subExpr) ||
isa<OverloadedDeclRefExpr>(subExpr))
return ConversionEphemeralness::Unresolved;
// Otherwise, we don't know what we're dealing with. Default to ephemeral.
return ConversionEphemeralness::Ephemeral;
}
case ConversionRestrictionKind::DeepEquality:
case ConversionRestrictionKind::Superclass:
case ConversionRestrictionKind::Existential:
case ConversionRestrictionKind::MetatypeToExistentialMetatype:
case ConversionRestrictionKind::ExistentialMetatypeToMetatype:
case ConversionRestrictionKind::ValueToOptional:
case ConversionRestrictionKind::OptionalToOptional:
case ConversionRestrictionKind::ClassMetatypeToAnyObject:
case ConversionRestrictionKind::ExistentialMetatypeToAnyObject:
case ConversionRestrictionKind::ProtocolMetatypeToProtocolClass:
case ConversionRestrictionKind::PointerToPointer:
case ConversionRestrictionKind::PointerToCPointer:
case ConversionRestrictionKind::ArrayUpcast:
case ConversionRestrictionKind::DictionaryUpcast:
case ConversionRestrictionKind::SetUpcast:
case ConversionRestrictionKind::HashableToAnyHashable:
case ConversionRestrictionKind::CFTollFreeBridgeToObjC:
case ConversionRestrictionKind::ObjCTollFreeBridgeToCF:
case ConversionRestrictionKind::CGFloatToDouble:
case ConversionRestrictionKind::DoubleToCGFloat:
case ConversionRestrictionKind::ReifyPackToType:
// @_nonEphemeral has no effect on these conversions, so treat them as all
// being non-ephemeral in order to allow their passing to an @_nonEphemeral
// parameter.
return ConversionEphemeralness::NonEphemeral;
}
llvm_unreachable("invalid conversion restriction kind");
}
Expr *ConstraintSystem::buildAutoClosureExpr(Expr *expr,
FunctionType *closureType,
DeclContext *ClosureContext,
bool isDefaultWrappedValue,
bool isAsyncLetWrapper) {
auto &Context = DC->getASTContext();
bool isInDefaultArgumentContext = false;
if (auto *init = dyn_cast<Initializer>(DC)) {
auto initKind = init->getInitializerKind();
isInDefaultArgumentContext =
initKind == InitializerKind::DefaultArgument ||
(initKind == InitializerKind::PatternBinding && isDefaultWrappedValue);
}
auto info = closureType->getExtInfo();
auto newClosureType = closureType;
if (isInDefaultArgumentContext && info.isNoEscape())
newClosureType = closureType->withExtInfo(info.withNoEscape(false))
->castTo<FunctionType>();
auto *closure = new (Context)
AutoClosureExpr(expr, newClosureType,
AutoClosureExpr::InvalidDiscriminator, ClosureContext);
closure->setParameterList(ParameterList::createEmpty(Context));
if (isAsyncLetWrapper)
closure->setThunkKind(AutoClosureExpr::Kind::AsyncLet);
Expr *result = closure;
if (!newClosureType->isEqual(closureType)) {
assert(isInDefaultArgumentContext);
assert(newClosureType
->withExtInfo(newClosureType->getExtInfo().withNoEscape(true))
->isEqual(closureType));
result = new (Context) FunctionConversionExpr(closure, closureType);
}
cacheExprTypes(result);
return result;
}
Expr *ConstraintSystem::buildTypeErasedExpr(Expr *expr, DeclContext *dc,
Type contextualType,
ContextualTypePurpose purpose) {
if (!(purpose == CTP_ReturnStmt || purpose == CTP_ReturnSingleExpr))
return expr;
auto *decl = dyn_cast_or_null<ValueDecl>(dc->getAsDecl());
if (!decl ||
(!Context.LangOpts.hasFeature(Feature::OpaqueTypeErasure) &&
!(decl->isDynamic() || decl->getDynamicallyReplacedDecl())))
return expr;
auto *opaque = contextualType->getAs<OpaqueTypeArchetypeType>();
if (!opaque)
return expr;
auto protocols = opaque->getConformsTo();
if (protocols.size() != 1)
return expr;
auto *PD = protocols.front();
auto *attr = PD->getAttrs().getAttribute<TypeEraserAttr>();
if (!attr)
return expr;
auto typeEraser = attr->getResolvedType(PD);
assert(typeEraser && "Failed to resolve eraser type!");
auto &ctx = dc->getASTContext();
auto *argList = ArgumentList::forImplicitSingle(ctx, ctx.Id_erasing, expr);
return CallExpr::createImplicit(
ctx, TypeExpr::createImplicit(typeEraser, ctx), argList);
}
/// If an UnresolvedDotExpr, SubscriptMember, etc has been resolved by the
/// constraint system, return the decl that it references.
ValueDecl *ConstraintSystem::findResolvedMemberRef(ConstraintLocator *locator) {
// See if we have a resolution for this member.
auto overload = findSelectedOverloadFor(locator);
if (!overload)
return nullptr;
// We only want to handle the simplest decl binding.
auto choice = overload->choice;
if (choice.getKind() != OverloadChoiceKind::Decl)
return nullptr;
return choice.getDecl();
}
void SolutionApplicationTargetsKey::dump() const { dump(llvm::errs()); }
void SolutionApplicationTargetsKey::dump(raw_ostream &OS) const {
switch (kind) {
case Kind::empty:
OS << "<empty>\n";
return;
case Kind::tombstone:
OS << "<tombstone>\n";
return;
case Kind::stmtCondElement:
// TODO: Implement a proper dump function for StmtConditionElement
OS << "statement condition element\n";
return;
case Kind::expr:
case Kind::closure:
storage.expr->dump(OS);
return;
case Kind::stmt:
storage.stmt->dump(OS);
return;
case Kind::pattern:
storage.pattern->dump(OS);
return;
case Kind::patternBindingEntry:
OS << "pattern binding entry " << storage.patternBindingEntry.index
<< " in\n";
storage.patternBindingEntry.patternBinding->dump(OS);
return;
case Kind::varDecl:
storage.varDecl->dump(OS);
return;
case Kind::functionRef:
OS << "<function>\n";
storage.functionRef->printContext(OS);
return;
}
llvm_unreachable("invalid statement kind");
}
SolutionApplicationTarget::SolutionApplicationTarget(
Expr *expr, DeclContext *dc, ContextualTypePurpose contextualPurpose,
TypeLoc convertType, bool isDiscarded) {
// Verify that a purpose was specified if a convertType was. Note that it is
// ok to have a purpose without a convertType (which is used for call
// return types).
assert((!convertType.getType() || contextualPurpose != CTP_Unused) &&
"Purpose for conversion type was not specified");
// Take a look at the conversion type to check to make sure it is sensible.
if (auto type = convertType.getType()) {
// If we're asked to convert to an UnresolvedType, then ignore the request.
// This happens when CSDiags nukes a type.
if (type->is<UnresolvedType>() ||
(type->is<MetatypeType>() && type->hasUnresolvedType())) {
convertType = TypeLoc();
contextualPurpose = CTP_Unused;
}
}
kind = Kind::expression;
expression.expression = expr;
expression.dc = dc;
expression.contextualPurpose = contextualPurpose;
expression.convertType = convertType;
expression.pattern = nullptr;
expression.propertyWrapper.wrappedVar = nullptr;
expression.propertyWrapper.innermostWrappedValueInit = nullptr;
expression.propertyWrapper.hasInitialWrappedValue = false;
expression.isDiscarded = isDiscarded;
expression.bindPatternVarsOneWay = false;
expression.initialization.patternBinding = nullptr;
expression.initialization.patternBindingIndex = 0;
}
void SolutionApplicationTarget::maybeApplyPropertyWrapper() {
assert(kind == Kind::expression);
assert(expression.contextualPurpose == CTP_Initialization);
VarDecl *singleVar;
if (auto *pattern = expression.pattern) {
singleVar = pattern->getSingleVar();
} else {
singleVar = expression.propertyWrapper.wrappedVar;
}
if (!singleVar)
return;
auto wrapperAttrs = singleVar->getAttachedPropertyWrappers();
if (wrapperAttrs.empty())
return;
// If the outermost property wrapper is directly initialized, form the
// call.
auto &ctx = singleVar->getASTContext();
auto outermostWrapperAttr = wrapperAttrs.front();
Expr *backingInitializer;
if (Expr *initializer = expression.expression) {
if (!isa<PropertyWrapperValuePlaceholderExpr>(initializer)) {
expression.propertyWrapper.hasInitialWrappedValue = true;
}
// Form init(wrappedValue:) call(s).
Expr *wrappedInitializer = buildPropertyWrapperInitCall(
singleVar, Type(), initializer, PropertyWrapperInitKind::WrappedValue,
[&](ApplyExpr *innermostInit) {
expression.propertyWrapper.innermostWrappedValueInit = innermostInit;
});
if (!wrappedInitializer)
return;
backingInitializer = wrappedInitializer;
} else {
Type outermostWrapperType =
singleVar->getAttachedPropertyWrapperType(0);
if (!outermostWrapperType)
return;
bool isImplicit = false;
// Retrieve the outermost wrapper argument. If there isn't one, we're
// performing default initialization.
auto outermostArgs = outermostWrapperAttr->getArgs();
if (!outermostArgs) {
SourceLoc fakeParenLoc = outermostWrapperAttr->getRange().End;
outermostArgs = ArgumentList::createImplicit(ctx, fakeParenLoc, {},
fakeParenLoc);
isImplicit = true;
}
SourceLoc typeLoc;
if (auto *repr = outermostWrapperAttr->getTypeRepr()) {
typeLoc = repr->getLoc();
}
auto typeExpr =
TypeExpr::createImplicitHack(typeLoc, outermostWrapperType, ctx);
backingInitializer = CallExpr::create(ctx, typeExpr, outermostArgs,
/*implicit*/ isImplicit);
}
wrapperAttrs[0]->setSemanticInit(backingInitializer);
// Note that we have applied to property wrapper, so we can adjust
// the initializer type later.
expression.propertyWrapper.wrappedVar = singleVar;
expression.expression = backingInitializer;
expression.convertType = {outermostWrapperAttr->getTypeRepr(),
outermostWrapperAttr->getType()};
}
SolutionApplicationTarget SolutionApplicationTarget::forInitialization(
Expr *initializer, DeclContext *dc, Type patternType, Pattern *pattern,
bool bindPatternVarsOneWay) {
// Determine the contextual type for the initialization.
TypeLoc contextualType;
if (!(isa<OptionalSomePattern>(pattern) && !pattern->isImplicit()) &&
patternType && !patternType->is<UnresolvedType>()) {
contextualType = TypeLoc::withoutLoc(patternType);
// Only provide a TypeLoc if it makes sense to allow diagnostics.
if (auto *typedPattern = dyn_cast<TypedPattern>(pattern)) {
const Pattern *inner = typedPattern->getSemanticsProvidingPattern();
if (isa<NamedPattern>(inner) || isa<AnyPattern>(inner)) {
contextualType = TypeLoc(typedPattern->getTypeRepr());
if (typedPattern->hasType())
contextualType.setType(typedPattern->getType());
else
contextualType.setType(patternType);
}
}
}
SolutionApplicationTarget target(
initializer, dc, CTP_Initialization, contextualType,
/*isDiscarded=*/false);
target.expression.pattern = pattern;
target.expression.bindPatternVarsOneWay = bindPatternVarsOneWay;
target.maybeApplyPropertyWrapper();
return target;
}
SolutionApplicationTarget SolutionApplicationTarget::forInitialization(
Expr *initializer, DeclContext *dc, Type patternType,
PatternBindingDecl *patternBinding, unsigned patternBindingIndex,
bool bindPatternVarsOneWay) {
auto result = forInitialization(
initializer, dc, patternType,
patternBinding->getPattern(patternBindingIndex), bindPatternVarsOneWay);
result.expression.initialization.patternBinding = patternBinding;
result.expression.initialization.patternBindingIndex = patternBindingIndex;
return result;
}
SolutionApplicationTarget
SolutionApplicationTarget::forForEachStmt(ForEachStmt *stmt, DeclContext *dc,
bool bindPatternVarsOneWay) {
SolutionApplicationTarget target(
stmt, dc, bindPatternVarsOneWay || bool(stmt->getWhere()));
return target;
}
SolutionApplicationTarget
SolutionApplicationTarget::forPropertyWrapperInitializer(
VarDecl *wrappedVar, DeclContext *dc, Expr *initializer) {
SolutionApplicationTarget target(
initializer, dc, CTP_Initialization, wrappedVar->getType(),
/*isDiscarded=*/false);
target.expression.propertyWrapper.wrappedVar = wrappedVar;
if (auto *patternBinding = wrappedVar->getParentPatternBinding()) {
auto index = patternBinding->getPatternEntryIndexForVarDecl(wrappedVar);
target.expression.initialization.patternBinding = patternBinding;
target.expression.initialization.patternBindingIndex = index;
target.expression.pattern = patternBinding->getPattern(index);
}
target.maybeApplyPropertyWrapper();
return target;
}
ContextualPattern
SolutionApplicationTarget::getContextualPattern() const {
if (kind == Kind::uninitializedVar) {
assert(patternBinding);
return ContextualPattern::forPatternBindingDecl(patternBinding,
uninitializedVar.index);
}
if (isForEachStmt()) {
return ContextualPattern::forRawPattern(forEachStmt.pattern,
forEachStmt.dc);
}
assert(kind == Kind::expression);
assert(expression.contextualPurpose == CTP_Initialization);
if (expression.contextualPurpose == CTP_Initialization &&
expression.initialization.patternBinding) {
return ContextualPattern::forPatternBindingDecl(
expression.initialization.patternBinding,
expression.initialization.patternBindingIndex);
}
return ContextualPattern::forRawPattern(expression.pattern, expression.dc);
}
bool SolutionApplicationTarget::infersOpaqueReturnType() const {
assert(kind == Kind::expression);
switch (expression.contextualPurpose) {
case CTP_Initialization:
case CTP_ReturnStmt:
case CTP_ReturnSingleExpr:
if (Type convertType = expression.convertType.getType())
return convertType->hasOpaqueArchetype();
return false;
default:
return false;
}
}
bool SolutionApplicationTarget::contextualTypeIsOnlyAHint() const {
assert(kind == Kind::expression);
switch (expression.contextualPurpose) {
case CTP_Initialization:
return !infersOpaqueReturnType() && !isOptionalSomePatternInit();
case CTP_ForEachStmt:
case CTP_ForEachSequence:
return true;
case CTP_Unused:
case CTP_ReturnStmt:
case CTP_ReturnSingleExpr:
case CTP_YieldByValue:
case CTP_YieldByReference:
case CTP_CaseStmt:
case CTP_ThrowStmt:
case CTP_EnumCaseRawValue:
case CTP_DefaultParameter:
case CTP_AutoclosureDefaultParameter:
case CTP_CalleeResult:
case CTP_CallArgument:
case CTP_ClosureResult:
case CTP_ArrayElement:
case CTP_DictionaryKey:
case CTP_DictionaryValue:
case CTP_CoerceOperand:
case CTP_AssignSource:
case CTP_SubscriptAssignSource:
case CTP_Condition:
case CTP_WrappedProperty:
case CTP_ComposedPropertyWrapper:
case CTP_CannotFail:
case CTP_ExprPattern:
return false;
}
llvm_unreachable("invalid contextual type");
}
/// Given a specific expression and the remnants of the failed constraint
/// system, produce a specific diagnostic.
///
/// This is guaranteed to always emit an error message.
///
void ConstraintSystem::diagnoseFailureFor(SolutionApplicationTarget target) {
setPhase(ConstraintSystemPhase::Diagnostics);
SWIFT_DEFER { setPhase(ConstraintSystemPhase::Finalization); };
auto &DE = getASTContext().Diags;
// If constraint system is in invalid state always produce
// a fallback diagnostic that asks to file a bug.
if (inInvalidState()) {
DE.diagnose(target.getLoc(), diag::failed_to_produce_diagnostic);
return;
}
if (auto expr = target.getAsExpr()) {
if (auto *assignment = dyn_cast<AssignExpr>(expr)) {
if (isa<DiscardAssignmentExpr>(assignment->getDest()))
expr = assignment->getSrc();
}
// Look through RebindSelfInConstructorExpr to avoid weird Sema issues.
if (auto *RB = dyn_cast<RebindSelfInConstructorExpr>(expr))
expr = RB->getSubExpr();
// Unresolved/Anonymous ClosureExprs are common enough that we should give
// them tailored diagnostics.
if (auto *closure = dyn_cast<ClosureExpr>(expr->getValueProvidingExpr())) {
DE.diagnose(closure->getLoc(), diag::cannot_infer_closure_type)
.highlight(closure->getSourceRange());
return;
}
// If no one could find a problem with this expression or constraint system,
// then it must be well-formed... but is ambiguous. Handle this by
// diagnostic various cases that come up.
DE.diagnose(expr->getLoc(), diag::type_of_expression_is_ambiguous)
.highlight(expr->getSourceRange());
} else if (auto *wrappedVar = target.getAsUninitializedWrappedVar()) {
auto *outerWrapper = wrappedVar->getOutermostAttachedPropertyWrapper();
Type propertyType = wrappedVar->getInterfaceType();
Type wrapperType = outerWrapper->getType();
// Emit the property wrapper fallback diagnostic
wrappedVar->diagnose(diag::property_wrapper_incompatible_property,
propertyType, wrapperType);
if (auto nominal = wrapperType->getAnyNominal()) {
nominal->diagnose(diag::property_wrapper_declared_here,
nominal->getName());
}
} else if (auto *var = target.getAsUninitializedVar()) {
DE.diagnose(target.getLoc(), diag::failed_to_produce_diagnostic);
} else if (target.isForEachStmt()) {
DE.diagnose(target.getLoc(), diag::failed_to_produce_diagnostic);
} else {
// Emit a poor fallback message.
DE.diagnose(target.getAsFunction()->getLoc(),
diag::failed_to_produce_diagnostic);
}
}
bool ConstraintSystem::isDeclUnavailable(const Decl *D,
ConstraintLocator *locator) const {
// First check whether this declaration is universally unavailable.
if (D->getAttrs().isUnavailable(getASTContext()))
return true;
return TypeChecker::isDeclarationUnavailable(D, DC, [&] {
SourceLoc loc;
if (locator) {
if (auto anchor = locator->getAnchor())
loc = getLoc(anchor);
}
return TypeChecker::overApproximateAvailabilityAtLocation(loc, DC);
});
}
bool ConstraintSystem::isConformanceUnavailable(ProtocolConformanceRef conformance,
ConstraintLocator *locator) const {
if (!conformance.isConcrete())
return false;
auto *concrete = conformance.getConcrete();
auto *rootConf = concrete->getRootConformance();
auto *ext = dyn_cast<ExtensionDecl>(rootConf->getDeclContext());
if (ext == nullptr)
return false;
return isDeclUnavailable(ext, locator);
}
/// If we aren't certain that we've emitted a diagnostic, emit a fallback
/// diagnostic.
void ConstraintSystem::maybeProduceFallbackDiagnostic(
SolutionApplicationTarget target) const {
if (Options.contains(ConstraintSystemFlags::SuppressDiagnostics))
return;
// Before producing fatal error here, let's check if there are any "error"
// diagnostics already emitted or waiting to be emitted. Because they are
// a better indication of the problem.
ASTContext &ctx = getASTContext();
if (ctx.Diags.hadAnyError() || ctx.hasDelayedConformanceErrors())
return;
ctx.Diags.diagnose(target.getLoc(), diag::failed_to_produce_diagnostic);
}
/// A protocol member accessed with an existential value might have generic
/// constraints that require the ability to spell an opened archetype in order
/// to be satisfied. Such are
/// - superclass requirements, when the object is a non-'Self'-rooted type
/// parameter, and the subject is dependent on 'Self', e.g. U : G<Self.A>
/// - same-type requirements, when one side is dependent on 'Self', and the
/// other is a non-'Self'-rooted type parameter, e.g. U.Element == Self.
///
/// Because opened archetypes are not part of the surface language, these
/// constraints render the member inaccessible.
static bool doesMemberHaveUnfulfillableConstraintsWithExistentialBase(
Type baseTy, const ValueDecl *member) {
const auto sig =
member->getInnermostDeclContext()->getGenericSignatureOfContext();
// Fast path: the member is generic only over 'Self'.
if (sig.getGenericParams().size() == 1) {
return false;
}
class IsDependentOnSelfInBaseTypeContextWalker : public TypeWalker {
CanGenericSignature Sig;
public:
explicit IsDependentOnSelfInBaseTypeContextWalker(CanGenericSignature Sig)
: Sig(Sig) {}
Action walkToTypePre(Type ty) override {
if (!ty->isTypeParameter()) {
return Action::Continue;
}
if (ty->getRootGenericParam()->getDepth() > 0) {
return Action::SkipChildren;
}
if (!Sig->isValidTypeParameter(ty)) {
return Action::SkipChildren;
}
const auto concreteTy = Sig->getConcreteType(ty);
if (concreteTy && !concreteTy->hasTypeParameter()) {
return Action::SkipChildren;
}
return Action::Stop;
}
} isDependentOnSelfWalker(member->getASTContext().getOpenedExistentialSignature(
baseTy, GenericSignature()));
for (const auto &req : sig.getRequirements()) {
switch (req.getKind()) {
case RequirementKind::SameCount:
llvm_unreachable("Same-count requirement not supported here");
case RequirementKind::Superclass: {
if (req.getFirstType()->getRootGenericParam()->getDepth() > 0 &&
req.getSecondType().walk(isDependentOnSelfWalker)) {
return true;
}
break;
}
case RequirementKind::SameType: {
const auto isNonSelfRootedTypeParam = [](Type ty) {
return ty->isTypeParameter() &&
ty->getRootGenericParam()->getDepth() > 0;
};
if ((isNonSelfRootedTypeParam(req.getFirstType()) &&
req.getSecondType().walk(isDependentOnSelfWalker)) ||
(isNonSelfRootedTypeParam(req.getSecondType()) &&
req.getFirstType().walk(isDependentOnSelfWalker))) {
return true;
}
break;
}
case RequirementKind::Conformance:
case RequirementKind::Layout:
break;
}
}
return false;
}
bool ConstraintSystem::isMemberAvailableOnExistential(
Type baseTy, const ValueDecl *member) const {
assert(member->getDeclContext()->getSelfProtocolDecl());
// If the type of the member references 'Self' or a 'Self'-rooted associated
// type in non-covariant position, we cannot reference the member.
//
// N.B. We pass the module context because this check does not care about the
// the actual signature of the opened archetype in context, rather it cares
// about whether you can "hold" `baseTy.member` properly in the abstract.
const auto info = member->findExistentialSelfReferences(
baseTy,
/*treatNonResultCovariantSelfAsInvariant=*/false);
if (info.selfRef > TypePosition::Covariant ||
info.assocTypeRef > TypePosition::Covariant) {
return false;
}
// FIXME: Appropriately diagnose assignments instead.
if (auto *const storageDecl = dyn_cast<AbstractStorageDecl>(member)) {
if (info.hasCovariantSelfResult && storageDecl->supportsMutation())
return false;
}
if (doesMemberHaveUnfulfillableConstraintsWithExistentialBase(baseTy,
member)) {
return false;
}
return true;
}
SourceLoc constraints::getLoc(ASTNode anchor) {
if (auto *E = anchor.dyn_cast<Expr *>()) {
return E->getLoc();
} else if (auto *T = anchor.dyn_cast<TypeRepr *>()) {
return T->getLoc();
} else if (auto *V = anchor.dyn_cast<Decl *>()) {
if (auto VD = dyn_cast<VarDecl>(V))
return VD->getNameLoc();
return anchor.getStartLoc();
} else if (auto *S = anchor.dyn_cast<Stmt *>()) {
return S->getStartLoc();
} else if (auto *P = anchor.dyn_cast<Pattern *>()) {
return P->getLoc();
} else if (auto *C = anchor.dyn_cast<StmtConditionElement *>()) {
return C->getStartLoc();
} else {
auto *I = anchor.get<CaseLabelItem *>();
return I->getStartLoc();
}
}
SourceRange constraints::getSourceRange(ASTNode anchor) {
return anchor.getSourceRange();
}
static Optional<Requirement> getRequirement(ConstraintSystem &cs,
ConstraintLocator *reqLocator) {
auto reqLoc = reqLocator->getLastElementAs<LocatorPathElt::AnyRequirement>();
if (!reqLoc)
return None;
if (reqLoc->isConditionalRequirement()) {
auto conformanceRef =
reqLocator->findLast<LocatorPathElt::ConformanceRequirement>();
assert(conformanceRef && "Invalid locator for a conditional requirement");
auto conformance = conformanceRef->getConformance();
return conformance->getConditionalRequirements()[reqLoc->getIndex()];
}
if (auto openedGeneric =
reqLocator->findLast<LocatorPathElt::OpenedGeneric>()) {
auto signature = openedGeneric->getSignature();
return signature.getRequirements()[reqLoc->getIndex()];
}
return None;
}
static Optional<std::pair<GenericTypeParamType *, RequirementKind>>
getRequirementInfo(ConstraintSystem &cs, ConstraintLocator *reqLocator) {
auto requirement = getRequirement(cs, reqLocator);
if (!requirement)
return None;
auto *GP = requirement->getFirstType()->getAs<GenericTypeParamType>();
if (!GP)
return None;
auto path = reqLocator->getPath();
auto iter = path.rbegin();
auto openedGeneric =
reqLocator->findLast<LocatorPathElt::OpenedGeneric>(iter);
assert(openedGeneric);
(void)openedGeneric;
auto newPath = path.drop_back(iter - path.rbegin() + 1);
auto *baseLoc = cs.getConstraintLocator(reqLocator->getAnchor(), newPath);
auto substitutions = cs.getOpenedTypes(baseLoc);
auto replacement =
llvm::find_if(substitutions, [&GP](const OpenedType &entry) {
auto *typeVar = entry.second;
return typeVar->getImpl().getGenericParameter() == GP;
});
if (replacement == substitutions.end())
return None;
auto *repr = cs.getRepresentative(replacement->second);
return std::make_pair(repr->getImpl().getGenericParameter(),
requirement->getKind());
}
bool ConstraintSystem::isFixedRequirement(ConstraintLocator *reqLocator,
Type requirementTy) {
if (auto reqInfo = getRequirementInfo(*this, reqLocator)) {
auto *GP = reqInfo->first;
auto reqKind = static_cast<unsigned>(reqInfo->second);
return FixedRequirements.count(
std::make_tuple(GP, reqKind, requirementTy.getPointer()));
}
return false;
}
void ConstraintSystem::recordFixedRequirement(ConstraintLocator *reqLocator,
Type requirementTy) {
if (auto reqInfo = getRequirementInfo(*this, reqLocator)) {
auto *GP = reqInfo->first;
auto reqKind = static_cast<unsigned>(reqInfo->second);
FixedRequirements.insert(
std::make_tuple(GP, reqKind, requirementTy.getPointer()));
}
}
// Replace any error types encountered with placeholders.
Type ConstraintSystem::getVarType(const VarDecl *var) {
auto type = var->getType();
// If this declaration is used as part of a code completion
// expression, solver needs to glance over the fact that
// it might be invalid to avoid failing constraint generation
// and produce completion results.
if (!isForCodeCompletion())
return type;
return type.transform([&](Type type) {
if (!type->is<ErrorType>())
return type;
return PlaceholderType::get(Context, const_cast<VarDecl *>(var));
});
}
bool ConstraintSystem::isReadOnlyKeyPathComponent(
const AbstractStorageDecl *storage, SourceLoc referenceLoc) {
// See whether key paths can store to this component. (Key paths don't
// get any special power from being formed in certain contexts, such
// as the ability to assign to `let`s in initialization contexts, so
// we pass null for the DC to `isSettable` here.)
if (!getASTContext().isSwiftVersionAtLeast(5)) {
// As a source-compatibility measure, continue to allow
// WritableKeyPaths to be formed in the same conditions we did
// in previous releases even if we should not be able to set
// the value in this context.
if (!storage->isSettableInSwift(DC)) {
// A non-settable component makes the key path read-only, unless
// a reference-writable component shows up later.
return true;
}
} else if (!storage->isSettableInSwift(nullptr) ||
!storage->isSetterAccessibleFrom(DC)) {
// A non-settable component makes the key path read-only, unless
// a reference-writable component shows up later.
return true;
}
// If the setter is unavailable, then the keypath ought to be read-only
// in this context.
if (auto setter = storage->getOpaqueAccessor(AccessorKind::Set)) {
ExportContext where = ExportContext::forFunctionBody(DC, referenceLoc);
auto maybeUnavail =
TypeChecker::checkDeclarationAvailability(setter, where);
if (maybeUnavail.hasValue()) {
return true;
}
}
return false;
}
bool ConstraintSystem::isArgumentGenericFunction(Type argType, Expr *argExpr) {
// Only makes sense if the argument type involves type variables somehow.
if (!argType->hasTypeVariable())
return false;
// Have we bound an overload for the argument already?
if (argExpr) {
auto locator = getConstraintLocator(argExpr);
auto knownOverloadBinding = ResolvedOverloads.find(locator);
if (knownOverloadBinding != ResolvedOverloads.end()) {
// If the overload choice is a generic function, then we have a generic
// function reference.
auto choice = knownOverloadBinding->second;
if (auto func = dyn_cast_or_null<AbstractFunctionDecl>(
choice.choice.getDeclOrNull())) {
if (func->isGeneric())
return true;
}
return false;
}
}
// We might have a type variable referring to an overload set.
auto argTypeVar = argType->getAs<TypeVariableType>();
if (!argTypeVar)
return false;
auto disjunction = getUnboundBindOverloadDisjunction(argTypeVar);
if (!disjunction)
return false;
for (auto constraint : disjunction->getNestedConstraints()) {
auto *decl = constraint->getOverloadChoice().getDeclOrNull();
if (!decl)
continue;
if (auto func = dyn_cast<AbstractFunctionDecl>(decl))
if (func->isGeneric())
return true;
}
return false;
}
bool ConstraintSystem::participatesInInference(ClosureExpr *closure) const {
if (closure->hasSingleExpressionBody())
return true;
if (Options.contains(ConstraintSystemFlags::LeaveClosureBodyUnchecked))
return false;
if (closure->hasEmptyBody())
return false;
// If body is nested in a parent that has a function builder applied,
// let's prevent inference until result builders.
return !isInResultBuilderContext(closure);
}
TypeVarBindingProducer::TypeVarBindingProducer(BindingSet &bindings)
: BindingProducer(bindings.getConstraintSystem(),
bindings.getTypeVariable()->getImpl().getLocator()),
TypeVar(bindings.getTypeVariable()), CanBeNil(bindings.canBeNil()) {
if (bindings.isDirectHole()) {
auto *locator = getLocator();
// If this type variable is associated with a code completion token
// and it failed to infer any bindings let's adjust holes's locator
// to point to a code completion token to avoid attempting to "fix"
// this problem since its rooted in the fact that constraint system
// is under-constrained.
if (bindings.getAssociatedCodeCompletionToken()) {
locator =
CS.getConstraintLocator(bindings.getAssociatedCodeCompletionToken());
}
Bindings.push_back(Binding::forHole(TypeVar, locator));
return;
}
// A binding to `Any` which should always be considered as a last resort.
Optional<Binding> Any;
auto addBinding = [&](const Binding &binding) {
// Adjust optionality of existing bindings based on presence of
// `ExpressibleByNilLiteral` requirement.
if (requiresOptionalAdjustment(binding)) {
Bindings.push_back(
binding.withType(OptionalType::get(binding.BindingType)));
} else if (binding.BindingType->isAny()) {
Any.emplace(binding);
} else {
Bindings.push_back(binding);
}
};
for (const auto &binding : bindings.Bindings) {
addBinding(binding);
}
// Infer defaults based on "uncovered" literal protocol requirements.
for (const auto &info : bindings.Literals) {
const auto &literal = info.second;
if (!literal.viableAsBinding())
continue;
// We need to figure out whether this is a direct conformance
// requirement or inferred transitive one to identify binding
// kind correctly.
addBinding({literal.getDefaultType(),
literal.isDirectRequirement() ? BindingKind::Subtypes
: BindingKind::Supertypes,
literal.getSource()});
}
// Let's always consider `Any` to be a last resort binding because
// it's always better to infer concrete type and erase it if required
// by the context.
if (Any) {
Bindings.push_back(*Any);
}
{
bool noBindings = Bindings.empty();
for (const auto &entry : bindings.Defaults) {
auto *constraint = entry.second;
if (noBindings) {
// If there are no direct or transitive bindings to attempt
// let's add defaults to the list right away.
Bindings.push_back(getDefaultBinding(constraint));
} else {
// Otherwise let's delay attempting default bindings
// until all of the direct & transitive bindings and
// their derivatives have been attempted.
DelayedDefaults.push_back(constraint);
}
}
}
}
bool TypeVarBindingProducer::requiresOptionalAdjustment(
const Binding &binding) const {
// If type variable can't be `nil` then adjustment is
// not required.
if (!CanBeNil)
return false;
if (binding.Kind == BindingKind::Supertypes) {
auto type = binding.BindingType->getRValueType();
// If the type doesn't conform to ExpressibleByNilLiteral,
// produce an optional of that type as a potential binding. We
// overwrite the binding in place because the non-optional type
// will fail to type-check against the nil-literal conformance.
auto *proto = CS.getASTContext().getProtocol(
KnownProtocolKind::ExpressibleByNilLiteral);
return !proto->getParentModule()->lookupConformance(type, proto);
} else if (binding.isDefaultableBinding() && binding.BindingType->isAny()) {
return true;
}
return false;
}
PotentialBinding
TypeVarBindingProducer::getDefaultBinding(Constraint *constraint) const {
assert(constraint->getKind() == ConstraintKind::Defaultable ||
constraint->getKind() == ConstraintKind::DefaultClosureType);
auto type = constraint->getSecondType();
Binding binding{type, BindingKind::Exact, constraint};
return requiresOptionalAdjustment(binding)
? binding.withType(OptionalType::get(type))
: binding;
}
ValueDecl *constraints::getOverloadChoiceDecl(Constraint *choice) {
if (choice->getKind() != ConstraintKind::BindOverload)
return nullptr;
return choice->getOverloadChoice().getDeclOrNull();
}
bool constraints::isOperatorDisjunction(Constraint *disjunction) {
assert(disjunction->getKind() == ConstraintKind::Disjunction);
auto choices = disjunction->getNestedConstraints();
assert(!choices.empty());
auto *decl = getOverloadChoiceDecl(choices.front());
return decl ? decl->isOperator() : false;
}
ASTNode constraints::findAsyncNode(ClosureExpr *closure) {
auto *body = closure->getBody();
if (!body)
return ASTNode();
return body->findAsyncNode();
}