blob: 09b6655ab3747cfbf7816cce52e4a38522b972b8 [file] [log] [blame]
//===--- CSApply.cpp - Constraint Application -----------------------------===//
//
// 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 application of a solution to a constraint
// system to a particular expression, resulting in a
// fully-type-checked expression.
//
//===----------------------------------------------------------------------===//
#include "CSDiagnostics.h"
#include "CodeSynthesis.h"
#include "MiscDiagnostics.h"
#include "TypeCheckProtocol.h"
#include "TypeCheckType.h"
#include "swift/AST/ASTVisitor.h"
#include "swift/AST/ASTWalker.h"
#include "swift/AST/ClangModuleLoader.h"
#include "swift/AST/ExistentialLayout.h"
#include "swift/AST/GenericEnvironment.h"
#include "swift/AST/GenericSignature.h"
#include "swift/AST/Initializer.h"
#include "swift/AST/OperatorNameLookup.h"
#include "swift/AST/ParameterList.h"
#include "swift/AST/ProtocolConformance.h"
#include "swift/AST/SubstitutionMap.h"
#include "swift/Basic/StringExtras.h"
#include "swift/Sema/ConstraintSystem.h"
#include "swift/Sema/SolutionResult.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Mangle.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Sema/Sema.h"
#include "clang/Sema/Template.h"
#include "clang/Sema/TemplateDeduction.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/SaveAndRestore.h"
using namespace swift;
using namespace constraints;
/// Retrieve the fixed type for the given type variable.
Type Solution::getFixedType(TypeVariableType *typeVar) const {
auto knownBinding = typeBindings.find(typeVar);
assert(knownBinding != typeBindings.end());
return knownBinding->second;
}
/// Determine whether the given type is an opened AnyObject.
///
/// This comes up in computeSubstitutions() when accessing
/// members via dynamic lookup.
static bool isOpenedAnyObject(Type type) {
auto archetype = type->getAs<OpenedArchetypeType>();
if (!archetype)
return false;
return archetype->getOpenedExistentialType()->isAnyObject();
}
SubstitutionMap
Solution::computeSubstitutions(GenericSignature sig,
ConstraintLocator *locator) const {
if (sig.isNull())
return SubstitutionMap();
// Gather the substitutions from dependent types to concrete types.
auto openedTypes = OpenedTypes.find(locator);
// If we have a member reference on an existential, there are no
// opened types or substitutions.
if (openedTypes == OpenedTypes.end())
return SubstitutionMap();
TypeSubstitutionMap subs;
for (const auto &opened : openedTypes->second)
subs[opened.first] = getFixedType(opened.second);
auto lookupConformanceFn =
[&](CanType original, Type replacement,
ProtocolDecl *protoType) -> ProtocolConformanceRef {
if (replacement->hasError() ||
isOpenedAnyObject(replacement) ||
replacement->is<GenericTypeParamType>()) {
return ProtocolConformanceRef(protoType);
}
// FIXME: Retrieve the conformance from the solution itself.
return TypeChecker::conformsToProtocol(replacement, protoType,
getConstraintSystem().DC);
};
return SubstitutionMap::get(sig,
QueryTypeSubstitutionMap{subs},
lookupConformanceFn);
}
static ConcreteDeclRef generateDeclRefForSpecializedCXXFunctionTemplate(
ASTContext &ctx, AbstractFunctionDecl *oldDecl, SubstitutionMap subst,
clang::FunctionDecl *specialized) {
// Create a new ParameterList with the substituted type.
auto oldFnType =
cast<GenericFunctionType>(oldDecl->getInterfaceType().getPointer());
auto newFnType = oldFnType->substGenericArgs(subst);
// The constructor type is a function type as follows:
// (CType.Type) -> (Generic) -> CType
// And a method's function type is as follows:
// (inout CType) -> (Generic) -> Void
// In either case, we only want the result of that function type because that
// is the function type with the generic params that need to be substituted:
// (Generic) -> CType
if (isa<ConstructorDecl>(oldDecl) || oldDecl->isInstanceMember())
newFnType = cast<FunctionType>(newFnType->getResult().getPointer());
SmallVector<ParamDecl *, 4> newParams;
unsigned i = 0;
for (auto paramTy : newFnType->getParams()) {
auto *oldParamDecl = oldDecl->getParameters()->get(i);
auto *newParamDecl =
ParamDecl::cloneWithoutType(oldDecl->getASTContext(), oldParamDecl);
newParamDecl->setInterfaceType(paramTy.getParameterType());
newParams.push_back(newParamDecl);
(void)++i;
}
auto *newParamList =
ParameterList::create(ctx, SourceLoc(), newParams, SourceLoc());
if (isa<ConstructorDecl>(oldDecl)) {
DeclName ctorName(ctx, DeclBaseName::createConstructor(), newParamList);
auto newCtorDecl = ConstructorDecl::createImported(
ctx, specialized, ctorName, oldDecl->getLoc(), /*failable=*/false,
/*failabilityLoc=*/SourceLoc(), /*throws=*/false,
/*throwsLoc=*/SourceLoc(), newParamList, /*genericParams=*/nullptr,
oldDecl->getDeclContext());
return ConcreteDeclRef(newCtorDecl);
}
// Generate a name for the specialized function.
std::string newNameStr;
llvm::raw_string_ostream buffer(newNameStr);
clang::MangleContext *mangler =
specialized->getASTContext().createMangleContext();
mangler->mangleName(specialized, buffer);
buffer.flush();
// Add all parameters as empty parameters.
auto newName = DeclName(
ctx, DeclName(ctx.getIdentifier(newNameStr)).getBaseName(), newParamList);
auto newFnDecl = FuncDecl::createImported(
ctx, oldDecl->getLoc(), newName, oldDecl->getNameLoc(),
/*Async=*/false, oldDecl->hasThrows(), newParamList,
newFnType->getResult(), /*GenericParams=*/nullptr,
oldDecl->getDeclContext(), specialized);
newFnDecl->setSelfAccessKind(cast<FuncDecl>(oldDecl)->getSelfAccessKind());
return ConcreteDeclRef(newFnDecl);
}
ConcreteDeclRef
Solution::resolveConcreteDeclRef(ValueDecl *decl,
ConstraintLocator *locator) const {
if (!decl)
return ConcreteDeclRef();
// Get the generic signatue of the decl and compute the substitutions.
auto sig = decl->getInnermostDeclContext()->getGenericSignatureOfContext();
auto subst = computeSubstitutions(sig, locator);
// If this is a C++ function template, get it's specialization for the given
// substitution map and update the decl accordingly.
if (decl->getClangDecl() &&
isa<clang::FunctionTemplateDecl>(decl->getClangDecl())) {
auto *newFn =
decl->getASTContext()
.getClangModuleLoader()
->instantiateCXXFunctionTemplate(
decl->getASTContext(),
const_cast<clang::FunctionTemplateDecl *>(
cast<clang::FunctionTemplateDecl>(decl->getClangDecl())),
subst);
return generateDeclRefForSpecializedCXXFunctionTemplate(
decl->getASTContext(), cast<AbstractFunctionDecl>(decl), subst, newFn);
}
return ConcreteDeclRef(decl, subst);
}
ConstraintLocator *Solution::getCalleeLocator(ConstraintLocator *locator,
bool lookThroughApply) const {
auto &cs = getConstraintSystem();
return cs.getCalleeLocator(
locator, lookThroughApply,
[&](Expr *expr) -> Type { return getType(expr); },
[&](Type type) -> Type { return simplifyType(type)->getRValueType(); },
[&](ConstraintLocator *locator) -> Optional<SelectedOverload> {
return getOverloadChoiceIfAvailable(locator);
});
}
ConstraintLocator *
Solution::getConstraintLocator(ASTNode anchor,
ArrayRef<LocatorPathElt> path) const {
auto &cs = getConstraintSystem();
return cs.getConstraintLocator(anchor, path);
}
ConstraintLocator *
Solution::getConstraintLocator(ConstraintLocator *base,
ArrayRef<LocatorPathElt> path) const {
auto &cs = getConstraintSystem();
return cs.getConstraintLocator(base, path);
}
/// Return the implicit access kind for a MemberRefExpr with the
/// specified base and member in the specified DeclContext.
static AccessSemantics
getImplicitMemberReferenceAccessSemantics(Expr *base, VarDecl *member,
DeclContext *DC) {
// Check whether this is a member access on 'self'.
bool isAccessOnSelf = false;
if (auto *baseDRE = dyn_cast<DeclRefExpr>(base->getValueProvidingExpr()))
if (auto *baseVar = dyn_cast<VarDecl>(baseDRE->getDecl()))
isAccessOnSelf = baseVar->isSelfParameter();
// If the value is always directly accessed from this context, do it.
return member->getAccessSemanticsFromContext(DC, isAccessOnSelf);
}
/// This extends functionality of `Expr::isTypeReference` with
/// support for `UnresolvedDotExpr` and `UnresolvedMemberExpr`.
/// This method could be used on not yet fully type-checked AST.
bool ConstraintSystem::isTypeReference(Expr *E) {
return E->isTypeReference(
[&](Expr *E) -> Type { return simplifyType(getType(E)); },
[&](Expr *E) -> Decl * {
if (auto *UDE = dyn_cast<UnresolvedDotExpr>(E)) {
return findResolvedMemberRef(
getConstraintLocator(UDE, ConstraintLocator::Member));
}
if (auto *UME = dyn_cast<UnresolvedMemberExpr>(E)) {
return findResolvedMemberRef(
getConstraintLocator(UME, ConstraintLocator::UnresolvedMember));
}
if (isa<OverloadSetRefExpr>(E))
return findResolvedMemberRef(
getConstraintLocator(const_cast<Expr *>(E)));
return nullptr;
});
}
bool Solution::isTypeReference(Expr *E) const {
return E->isTypeReference(
[&](Expr *expr) -> Type { return simplifyType(getType(expr)); },
[&](Expr *expr) -> Decl * {
ConstraintLocator *locator = nullptr;
if (auto *UDE = dyn_cast<UnresolvedDotExpr>(E)) {
locator = getConstraintLocator(UDE, {ConstraintLocator::Member});
}
if (auto *UME = dyn_cast<UnresolvedMemberExpr>(E)) {
locator =
getConstraintLocator(UME, {ConstraintLocator::UnresolvedMember});
}
if (isa<OverloadSetRefExpr>(E))
locator = getConstraintLocator(const_cast<Expr *>(E));
if (locator) {
if (auto selectedOverload = getOverloadChoiceIfAvailable(locator)) {
const auto &choice = selectedOverload->choice;
return choice.getDeclOrNull();
}
}
return nullptr;
});
}
bool ConstraintSystem::isStaticallyDerivedMetatype(Expr *E) {
return E->isStaticallyDerivedMetatype(
[&](Expr *E) -> Type { return simplifyType(getType(E)); },
[&](Expr *E) -> bool { return isTypeReference(E); });
}
bool Solution::isStaticallyDerivedMetatype(Expr *E) const {
return E->isStaticallyDerivedMetatype(
[&](Expr *E) -> Type { return simplifyType(getType(E)); },
[&](Expr *E) -> bool { return isTypeReference(E); });
}
Type ConstraintSystem::getInstanceType(TypeExpr *E) {
if (!hasType(E))
return Type();
if (auto metaType = getType(E)->getAs<MetatypeType>())
return metaType->getInstanceType();
return ErrorType::get(getType(E)->getASTContext());
}
Type ConstraintSystem::getResultType(const AbstractClosureExpr *E) {
return E->getResultType([&](Expr *E) -> Type { return getType(E); });
}
static bool buildObjCKeyPathString(KeyPathExpr *E,
llvm::SmallVectorImpl<char> &buf) {
for (auto &component : E->getComponents()) {
switch (component.getKind()) {
case KeyPathExpr::Component::Kind::OptionalChain:
case KeyPathExpr::Component::Kind::OptionalForce:
case KeyPathExpr::Component::Kind::OptionalWrap:
// KVC propagates nulls, so these don't affect the key path string.
continue;
case KeyPathExpr::Component::Kind::Identity:
// The identity component can be elided from the KVC string (unless it's
// the only component, in which case we use @"self").
continue;
case KeyPathExpr::Component::Kind::Property: {
// Property references must be to @objc properties.
// TODO: If we added special properties matching KVC operators like '@sum',
// '@count', etc. those could be mapped too.
auto property = cast<VarDecl>(component.getDeclRef().getDecl());
if (!property->isObjC())
return false;
if (!buf.empty()) {
buf.push_back('.');
}
auto objcName = property->getObjCPropertyName().str();
buf.append(objcName.begin(), objcName.end());
continue;
}
case KeyPathExpr::Component::Kind::TupleElement:
case KeyPathExpr::Component::Kind::Subscript:
// Subscripts and tuples aren't generally represented in KVC.
// TODO: There are some subscript forms we could map to KVC, such as
// when indexing a Dictionary or NSDictionary by string, or when applying
// a mapping subscript operation to Array/Set or NSArray/NSSet.
return false;
case KeyPathExpr::Component::Kind::Invalid:
case KeyPathExpr::Component::Kind::UnresolvedProperty:
case KeyPathExpr::Component::Kind::UnresolvedSubscript:
// Don't bother building the key path string if the key path didn't even
// resolve.
return false;
case KeyPathExpr::Component::Kind::DictionaryKey:
llvm_unreachable("DictionaryKey only valid in #keyPath expressions.");
return false;
}
}
// If there are no non-identity components, this is the "self" key.
if (buf.empty()) {
auto self = StringRef("self");
buf.append(self.begin(), self.end());
}
return true;
}
namespace {
/// Rewrites an expression by applying the solution of a constraint
/// system to that expression.
class ExprRewriter : public ExprVisitor<ExprRewriter, Expr *> {
public:
ConstraintSystem &cs;
DeclContext *dc;
Solution &solution;
Optional<SolutionApplicationTarget> target;
bool SuppressDiagnostics;
/// Coerce the given tuple to another tuple type.
///
/// \param expr The expression we're converting.
///
/// \param fromTuple The tuple type we're converting from, which is the same
/// as \c expr->getType().
///
/// \param toTuple The tuple type we're converting to.
///
/// \param locator Locator describing where this tuple conversion occurs.
///
/// \param sources The sources of each of the elements to be used in the
/// resulting tuple, as provided by \c computeTupleShuffle.
Expr *coerceTupleToTuple(Expr *expr, TupleType *fromTuple,
TupleType *toTuple,
ConstraintLocatorBuilder locator,
ArrayRef<unsigned> sources);
/// Coerce a subclass, class-constrained archetype, class-constrained
/// existential or to a superclass type.
///
/// Also supports metatypes of the above.
///
/// \param expr The expression to be coerced.
/// \param toType The type to which the expression will be coerced.
///
/// \return The coerced expression, whose type will be equivalent to
/// \c toType.
Expr *coerceSuperclass(Expr *expr, Type toType);
/// Coerce the given value to existential type.
///
/// The following conversions are supported:
/// - concrete to existential
/// - existential to existential
/// - concrete metatype to existential metatype
/// - existential metatype to existential metatype
///
/// \param expr The expression to be coerced.
/// \param toType The type to which the expression will be coerced.
///
/// \return The coerced expression, whose type will be equivalent to
/// \c toType.
Expr *coerceExistential(Expr *expr, Type toType);
/// Coerce an expression of (possibly unchecked) optional
/// type to have a different (possibly unchecked) optional type.
Expr *coerceOptionalToOptional(Expr *expr, Type toType,
ConstraintLocatorBuilder locator,
Optional<Pattern*> typeFromPattern = None);
/// Coerce an expression of implicitly unwrapped optional type to its
/// underlying value type, in the correct way for an implicit
/// look-through.
Expr *coerceImplicitlyUnwrappedOptionalToValue(Expr *expr, Type objTy);
/// Peephole an array upcast.
void peepholeArrayUpcast(ArrayExpr *expr, Type toType, bool bridged,
Type elementType,
ConstraintLocatorBuilder locator);
/// Peephole a dictionary upcast.
void peepholeDictionaryUpcast(DictionaryExpr *expr, Type toType,
bool bridged, Type keyType,
Type valueType,
ConstraintLocatorBuilder locator);
/// Try to peephole the collection upcast, eliminating the need for
/// a separate collection-upcast expression.
///
/// \returns true if the peephole operation succeeded, in which case
/// \c expr already subsumes the upcast.
bool peepholeCollectionUpcast(Expr *expr, Type toType, bool bridged,
ConstraintLocatorBuilder locator);
/// Build a collection upcast expression.
///
/// \param bridged Whether this is a bridging conversion, meaning that the
/// element types themselves are bridged (vs. simply coerced).
Expr *buildCollectionUpcastExpr(Expr *expr, Type toType,
bool bridged,
ConstraintLocatorBuilder locator);
/// Build the expression that performs a bridging operation from the
/// given expression to the given \c toType.
Expr *buildObjCBridgeExpr(Expr *expr, Type toType,
ConstraintLocatorBuilder locator);
static Type getBaseType(AnyFunctionType *fnType,
bool wantsRValueInstanceType = true) {
auto params = fnType->getParams();
assert(params.size() == 1);
const auto &base = params.front();
if (wantsRValueInstanceType)
return base.getPlainType()->getMetatypeInstanceType();
return base.getOldType();
}
/// Check whether it is possible to have an ObjC key path string for the keypath expression
/// and set the key path string, if yes
void checkAndSetObjCKeyPathString(KeyPathExpr *keyPath) {
if (cs.getASTContext().LangOpts.EnableObjCInterop) {
SmallString<64> compatStringBuf;
if (buildObjCKeyPathString(keyPath, compatStringBuf)) {
auto stringCopy = cs.getASTContext().AllocateCopy<char>(compatStringBuf.begin(),
compatStringBuf.end());
auto stringExpr = new (cs.getASTContext()) StringLiteralExpr(
StringRef(stringCopy, compatStringBuf.size()),
SourceRange(),
/*implicit*/ true);
cs.setType(
stringExpr,
cs.getASTContext().getStringDecl()->getDeclaredInterfaceType());
keyPath->setObjCStringLiteralExpr(stringExpr);
}
}
}
// Returns None if the AST does not contain enough information to recover
// substitutions; this is different from an Optional(SubstitutionMap()),
// indicating a valid call to a non-generic operator.
Optional<SubstitutionMap>
getOperatorSubstitutions(ValueDecl *witness, Type refType) {
// We have to recover substitutions in this hacky way because
// the AST does not retain enough information to devirtualize
// calls like this.
auto witnessType = witness->getInterfaceType();
// Compute the substitutions.
auto *gft = witnessType->getAs<GenericFunctionType>();
if (gft == nullptr) {
if (refType->isEqual(witnessType))
return SubstitutionMap();
return None;
}
auto sig = gft->getGenericSignature();
auto *env = sig->getGenericEnvironment();
witnessType = FunctionType::get(gft->getParams(),
gft->getResult(),
gft->getExtInfo());
witnessType = env->mapTypeIntoContext(witnessType);
TypeSubstitutionMap subs;
auto substType = witnessType->substituteBindingsTo(
refType,
[&](ArchetypeType *origType, CanType substType,
ArchetypeType*, ArrayRef<ProtocolConformanceRef>) -> CanType {
if (auto gpType = dyn_cast<GenericTypeParamType>(
origType->getInterfaceType()->getCanonicalType()))
subs[gpType] = substType;
return substType;
});
// If substitution failed, it means that the protocol requirement type
// and the witness type did not match up. The only time that this
// should happen is when the witness is defined in a base class and
// the actual call uses a derived class. For example,
//
// protocol P { func +(lhs: Self, rhs: Self) }
// class Base : P { func +(lhs: Base, rhs: Base) {} }
// class Derived : Base {}
//
// If we enter this code path with two operands of type Derived,
// we know we're calling the protocol requirement P.+, with a
// substituted type of (Derived, Derived) -> (). But the type of
// the witness is (Base, Base) -> (). Just bail out and make a
// witness method call in this rare case; SIL mandatory optimizations
// will likely devirtualize it anyway.
if (!substType)
return None;
return SubstitutionMap::get(sig,
QueryTypeSubstitutionMap{subs},
LookUpConformanceInModule(cs.DC->getParentModule()));
}
public:
/// Build a reference to the given declaration.
Expr *buildDeclRef(SelectedOverload overload, DeclNameLoc loc,
ConstraintLocatorBuilder locator, bool implicit) {
auto choice = overload.choice;
assert(choice.getKind() != OverloadChoiceKind::DeclViaDynamic);
auto *decl = choice.getDecl();
auto fullType = simplifyType(overload.openedFullType);
// Determine the declaration selected for this overloaded reference.
auto &ctx = cs.getASTContext();
auto semantics = decl->getAccessSemanticsFromContext(cs.DC,
/*isAccessOnSelf*/false);
// If this is a member of a nominal type, build a reference to the
// member with an implied base type.
if (decl->getDeclContext()->isTypeContext() && isa<FuncDecl>(decl)) {
assert(cast<FuncDecl>(decl)->isOperator() && "Must be an operator");
auto baseTy = getBaseType(fullType->castTo<FunctionType>());
// Handle operator requirements found in protocols.
if (auto proto = dyn_cast<ProtocolDecl>(decl->getDeclContext())) {
bool isCurried = shouldBuildCurryThunk(choice, /*baseIsInstance=*/false);
// If we have a concrete conformance, build a call to the witness.
//
// FIXME: This is awful. We should be able to handle this as a call to
// the protocol requirement with Self == the concrete type, and SILGen
// (or later) can devirtualize as appropriate.
auto conformance =
TypeChecker::conformsToProtocol(baseTy, proto, cs.DC);
if (conformance.isConcrete()) {
if (auto witness = conformance.getConcrete()->getWitnessDecl(decl)) {
bool isMemberOperator = witness->getDeclContext()->isTypeContext();
if (!isMemberOperator || !isCurried) {
// The fullType was computed by substituting the protocol
// requirement so it always has a (Self) -> ... curried
// application. Strip it off if the witness was a top-level
// function.
Type refType;
if (isMemberOperator)
refType = fullType;
else
refType = fullType->castTo<AnyFunctionType>()->getResult();
// Build the AST for the call to the witness.
auto subMap = getOperatorSubstitutions(witness, refType);
if (subMap) {
ConcreteDeclRef witnessRef(witness, *subMap);
auto declRefExpr = new (ctx) DeclRefExpr(witnessRef, loc,
/*Implicit=*/false);
declRefExpr->setFunctionRefKind(choice.getFunctionRefKind());
cs.setType(declRefExpr, refType);
Expr *refExpr;
if (isMemberOperator) {
// If the operator is a type member, add the implicit
// (Self) -> ... call.
Expr *base =
TypeExpr::createImplicitHack(loc.getBaseNameLoc(), baseTy,
ctx);
cs.setType(base, MetatypeType::get(baseTy));
refExpr = new (ctx) DotSyntaxCallExpr(declRefExpr,
SourceLoc(), base);
auto refType = fullType->castTo<FunctionType>()->getResult();
cs.setType(refExpr, refType);
} else {
refExpr = declRefExpr;
}
return forceUnwrapIfExpected(refExpr, choice, locator);
}
}
}
}
}
// Build a reference to the member.
Expr *base =
TypeExpr::createImplicitHack(loc.getBaseNameLoc(), baseTy, ctx);
cs.cacheExprTypes(base);
return buildMemberRef(base, SourceLoc(), overload, loc, locator,
locator, implicit, semantics);
}
if (isa<TypeDecl>(decl) && !isa<ModuleDecl>(decl)) {
auto typeExpr = TypeExpr::createImplicitHack(
loc.getBaseNameLoc(), fullType->getMetatypeInstanceType(), ctx);
cs.cacheType(typeExpr);
return typeExpr;
}
auto ref = resolveConcreteDeclRef(decl, locator);
auto declRefExpr =
new (ctx) DeclRefExpr(ref, loc, implicit, semantics, fullType);
cs.cacheType(declRefExpr);
declRefExpr->setFunctionRefKind(choice.getFunctionRefKind());
return forceUnwrapIfExpected(declRefExpr, choice, locator);
}
/// Describes an opened existential that has not yet been closed.
struct OpenedExistential {
/// The archetype describing this opened existential.
OpenedArchetypeType *Archetype;
/// The existential value being opened.
Expr *ExistentialValue;
/// The opaque value (of archetype type) stored within the
/// existential.
OpaqueValueExpr *OpaqueValue;
/// The depth of this currently-opened existential. Once the
/// depth of the expression stack is equal to this value, the
/// existential can be closed.
unsigned Depth;
};
/// A stack of opened existentials that have not yet been closed.
/// Ordered by decreasing depth.
llvm::SmallVector<OpenedExistential, 2> OpenedExistentials;
/// A stack of expressions being walked, used to compute existential depth.
llvm::SmallVector<Expr *, 8> ExprStack;
/// A map of apply exprs to their callee locators. This is necessary
/// because after rewriting an apply's function expr, its callee locator
/// will no longer be equivalent to the one stored in the solution.
llvm::DenseMap<ApplyExpr *, ConstraintLocator *> CalleeLocators;
/// A cache of decl references with their contextual substitutions for a
/// given callee locator.
llvm::DenseMap<ConstraintLocator *, ConcreteDeclRef> CachedConcreteRefs;
/// Resolves the contextual substitutions for a reference to a declaration
/// at a given locator. This should be preferred to
/// Solution::resolveConcreteDeclRef as it caches the result.
ConcreteDeclRef
resolveConcreteDeclRef(ValueDecl *decl, ConstraintLocatorBuilder locator) {
if (!decl)
return ConcreteDeclRef();
// Cache the resulting concrete reference. Ideally this would be done on
// Solution, however unfortunately that would require a const_cast which
// would be undefined behaviour if we ever had a `const Solution`.
auto *loc = getConstraintSystem().getConstraintLocator(locator);
auto &ref = CachedConcreteRefs[loc];
if (!ref)
ref = solution.resolveConcreteDeclRef(decl, loc);
return ref;
}
/// Members which are AbstractFunctionDecls but not FuncDecls cannot
/// mutate self.
bool isNonMutatingMember(ValueDecl *member) {
if (!isa<AbstractFunctionDecl>(member))
return false;
return !isa<FuncDecl>(member) || !cast<FuncDecl>(member)->isMutating();
}
/// If the expression might be a dynamic method call, return the base
/// value for the call.
Expr *getBaseExpr(Expr *expr) {
// Keep going up as long as this expression is the parent's base.
if (auto unresolvedDot = dyn_cast<UnresolvedDotExpr>(expr)) {
return unresolvedDot->getBase();
// Remaining cases should only come up when we're re-typechecking.
// FIXME: really it would be much better if Sema had stricter phase
// separation.
} else if (auto dotSyntax = dyn_cast<DotSyntaxCallExpr>(expr)) {
return dotSyntax->getArg();
} else if (auto ctorRef = dyn_cast<ConstructorRefCallExpr>(expr)) {
return ctorRef->getArg();
} else if (auto apply = dyn_cast<ApplyExpr>(expr)) {
return apply->getFn();
} else if (auto lookupRef = dyn_cast<LookupExpr>(expr)) {
return lookupRef->getBase();
} else if (auto load = dyn_cast<LoadExpr>(expr)) {
return load->getSubExpr();
} else if (auto inout = dyn_cast<InOutExpr>(expr)) {
return inout->getSubExpr();
} else if (auto force = dyn_cast<ForceValueExpr>(expr)) {
return force->getSubExpr();
} else {
return nullptr;
}
}
/// Calculates the nesting depth of the current application.
unsigned getArgCount(unsigned maxArgCount) {
// FIXME: Walking over the ExprStack to figure out the number of argument
// lists being applied is brittle. We should instead be checking
// hasAppliedSelf to figure out if the self param is applied, and looking
// at the FunctionRefKind to see if the parameter list is applied.
unsigned e = ExprStack.size();
unsigned argCount;
// Starting from the current expression, count up if the expression is
// equal to its parent expression's base.
Expr *prev = ExprStack.back();
for (argCount = 1; argCount < maxArgCount && argCount < e; ++argCount) {
Expr *result = ExprStack[e - argCount - 1];
Expr *base = getBaseExpr(result);
if (base != prev)
break;
prev = result;
}
return argCount;
}
/// Open an existential value into a new, opaque value of
/// archetype type.
///
/// \param base An expression of existential type whose value will
/// be opened.
///
/// \param archetype The archetype that describes the opened existential
/// type.
///
/// \param member The member that is being referenced on the existential
/// type.
///
/// \returns An OpaqueValueExpr that provides a reference to the value
/// stored within the expression or its metatype (if the base was a
/// metatype).
Expr *openExistentialReference(Expr *base, OpenedArchetypeType *archetype,
ValueDecl *member) {
assert(archetype && "archetype not already opened?");
// Dig out the base type.
Type baseTy = cs.getType(base);
// Look through lvalues.
bool isLValue = false;
if (auto lvalueTy = baseTy->getAs<LValueType>()) {
isLValue = true;
baseTy = lvalueTy->getObjectType();
}
// Look through metatypes.
bool isMetatype = false;
if (auto metaTy = baseTy->getAs<AnyMetatypeType>()) {
isMetatype = true;
baseTy = metaTy->getInstanceType();
}
assert(baseTy->isAnyExistentialType() && "Type must be existential");
// If the base was an lvalue but it will only be treated as an
// rvalue, turn the base into an rvalue now. This results in
// better SILGen.
if (isLValue &&
(isNonMutatingMember(member) ||
member->getDeclContext()->getDeclaredInterfaceType()
->hasReferenceSemantics())) {
base = cs.coerceToRValue(base);
isLValue = false;
}
// Determine the number of applications that need to occur before
// we can close this existential, and record it.
unsigned maxArgCount = member->getNumCurryLevels();
unsigned depth = ExprStack.size() - getArgCount(maxArgCount);
// Invalid case -- direct call of a metatype. Has one less argument
// application because there's no ".init".
if (isa<ApplyExpr>(ExprStack.back()))
depth++;
// Create the opaque opened value. If we started with a
// metatype, it's a metatype.
Type opaqueType = archetype;
if (isMetatype)
opaqueType = MetatypeType::get(opaqueType);
if (isLValue)
opaqueType = LValueType::get(opaqueType);
ASTContext &ctx = cs.getASTContext();
auto archetypeVal =
new (ctx) OpaqueValueExpr(base->getSourceRange(), opaqueType);
cs.cacheType(archetypeVal);
// Record the opened existential.
OpenedExistentials.push_back({archetype, base, archetypeVal, depth});
return archetypeVal;
}
/// Trying to close the active existential, if there is one.
bool closeExistential(Expr *&result, ConstraintLocatorBuilder locator,
bool force=false) {
if (OpenedExistentials.empty())
return false;
auto &record = OpenedExistentials.back();
assert(record.Depth <= ExprStack.size());
if (!force && record.Depth < ExprStack.size() - 1)
return false;
// If we had a return type of 'Self', erase it.
Type resultTy;
resultTy = cs.getType(result);
if (resultTy->hasOpenedExistential(record.Archetype)) {
Type erasedTy = resultTy->eraseOpenedExistential(record.Archetype);
auto range = result->getSourceRange();
result = coerceToType(result, erasedTy, locator);
// FIXME: Implement missing tuple-to-tuple conversion
if (result == nullptr) {
result = new (cs.getASTContext()) ErrorExpr(range);
cs.setType(result, erasedTy);
// The opaque value is no longer reachable in an AST walk as
// a result of the result above being replaced with an
// ErrorExpr, but there is code expecting to have a type set
// on it. Since we no longer have a reachable reference,
// we'll null this out.
record.OpaqueValue = nullptr;
}
}
// Form the open-existential expression.
result = new (cs.getASTContext()) OpenExistentialExpr(
record.ExistentialValue,
record.OpaqueValue,
result, cs.getType(result));
cs.cacheType(result);
OpenedExistentials.pop_back();
return true;
}
/// Determines if a partially-applied member reference should be
/// converted into a fully-applied member reference with a pair of
/// closures.
bool shouldBuildCurryThunk(OverloadChoice choice,
bool baseIsInstance) {
ValueDecl *member = choice.getDecl();
auto isDynamic = choice.getKind() == OverloadChoiceKind::DeclViaDynamic;
// FIXME: We should finish plumbing this through for dynamic
// lookup as well.
if (isDynamic || member->getAttrs().hasAttribute<OptionalAttr>())
return false;
// If we're inside a selector expression, don't build the thunk.
// Were not actually going to emit the member reference, just
// look at the AST.
for (auto expr : ExprStack)
if (isa<ObjCSelectorExpr>(expr))
return false;
// Unbound instance method references always build a thunk, even if
// we apply the arguments (eg, SomeClass.method(self)(a)), to avoid
// representational issues.
if (!baseIsInstance && member->isInstanceMember())
return true;
// Figure out how many argument lists we need.
unsigned maxArgCount = member->getNumCurryLevels();
unsigned argCount = [&]() -> unsigned {
Expr *prev = ExprStack.back();
// FIXME: Representational gunk because "T(...)" is really
// "T.init(...)" -- pretend it has two argument lists like
// a real '.' call.
if (isa<ConstructorDecl>(member) &&
isa<CallExpr>(prev) &&
isa<TypeExpr>(cast<CallExpr>(prev)->getFn())) {
assert(maxArgCount == 2);
return 2;
}
// Similarly, ".foo(...)" really applies two argument lists.
if (isa<CallExpr>(prev) &&
isa<UnresolvedMemberExpr>(cast<CallExpr>(prev)->getFn()))
return 2;
return getArgCount(maxArgCount);
}();
// If we have fewer argument lists than expected, build a thunk.
if (argCount < maxArgCount)
return true;
return false;
}
AutoClosureExpr *buildCurryThunk(ValueDecl *member,
FunctionType *selfFnTy,
Expr *selfParamRef,
Expr *ref,
ConstraintLocatorBuilder locator) {
auto &context = cs.getASTContext();
OptionSet<ParameterList::CloneFlags> options
= (ParameterList::Implicit |
ParameterList::NamedArguments);
auto *params = getParameterList(member)->clone(context, options);
for (auto idx : indices(*params)) {
auto *param = params->get(idx);
auto arg = selfFnTy->getParams()[idx];
param->setInterfaceType(
arg.getParameterType()->mapTypeOutOfContext());
param->setSpecifier(
ParamDecl::getParameterSpecifierForValueOwnership(
arg.getValueOwnership()));
}
auto resultTy = selfFnTy->getResult();
auto discriminator = AutoClosureExpr::InvalidDiscriminator;
auto closure =
new (context) AutoClosureExpr(/*set body later*/nullptr, resultTy,
discriminator, cs.DC);
closure->setParameterList(params);
closure->setType(selfFnTy);
closure->setThunkKind(AutoClosureExpr::Kind::SingleCurryThunk);
cs.cacheType(closure);
auto refTy = cs.getType(ref)->castTo<FunctionType>();
auto calleeParams = refTy->getResult()->castTo<FunctionType>()->getParams();
auto calleeResultTy = refTy->getResult()->castTo<FunctionType>()->getResult();
auto selfParam = refTy->getParams()[0];
auto selfParamTy = selfParam.getPlainType();
Expr *selfOpenedRef = selfParamRef;
// If the 'self' parameter has non-trivial ownership, adjust the
// argument accordingly.
switch (selfParam.getValueOwnership()) {
case ValueOwnership::Default:
case ValueOwnership::InOut:
break;
case ValueOwnership::Owned:
case ValueOwnership::Shared:
auto selfArgTy = ParenType::get(context,
selfParam.getPlainType(),
selfParam.getParameterFlags());
selfOpenedRef->setType(selfArgTy);
cs.cacheType(selfOpenedRef);
break;
}
if (selfParamTy->hasOpenedExistential()) {
// If we're opening an existential:
// - the type of 'ref' inside the closure is written in terms of the
// open existental archetype
// - the type of the closure, 'selfFnTy' is written in terms of the
// erased existential bounds
if (selfParam.isInOut())
selfParamTy = LValueType::get(selfParamTy);
selfOpenedRef =
new (context) OpaqueValueExpr(SourceLoc(), selfParamTy);
cs.cacheType(selfOpenedRef);
}
// (Self) -> ...
ApplyExpr *selfCall = new (context) DotSyntaxCallExpr(
ref, SourceLoc(), selfOpenedRef);
selfCall->setType(refTy->getResult());
cs.cacheType(selfCall);
if (selfParamRef->isSuperExpr())
selfCall->setIsSuper(true);
// Pass all the closure parameters to the call.
SmallVector<Identifier, 4> labels;
SmallVector<SourceLoc, 4> labelLocs;
SmallVector<Expr *, 4> args;
for (auto idx : indices(*params)) {
auto *param = params->get(idx);
auto calleeParamType = calleeParams[idx].getParameterType();
auto type = param->getType();
Expr *paramRef =
new (context) DeclRefExpr(param, DeclNameLoc(), /*implicit*/ true);
paramRef->setType(
param->isInOut()
? LValueType::get(type)
: type);
cs.cacheType(paramRef);
paramRef = coerceToType(
paramRef,
param->isInOut()
? LValueType::get(calleeParamType)
: calleeParamType,
locator);
if (param->isInOut()) {
paramRef =
new (context) InOutExpr(SourceLoc(), paramRef, calleeParamType,
/*implicit=*/true);
cs.cacheType(paramRef);
} else if (param->isVariadic()) {
paramRef =
new (context) VarargExpansionExpr(paramRef, /*implicit*/ true);
paramRef->setType(calleeParamType);
cs.cacheType(paramRef);
}
args.push_back(paramRef);
labels.push_back(calleeParams[idx].getLabel());
labelLocs.push_back(SourceLoc());
}
Expr *closureArg;
if (args.size() == 1 &&
labels[0].empty() &&
!calleeParams[0].getParameterFlags().isVariadic()) {
closureArg = new (context) ParenExpr(SourceLoc(), args[0], SourceLoc(),
/*hasTrailingClosure=*/false);
closureArg->setImplicit();
} else {
closureArg = TupleExpr::create(context, SourceLoc(), args, labels, labelLocs,
SourceLoc(), /*hasTrailingClosure=*/false,
/*implicit=*/true);
}
auto argTy = AnyFunctionType::composeInput(context, calleeParams,
/*canonical*/false);
closureArg->setType(argTy);
cs.cacheType(closureArg);
// (Self) -> (Args...) -> ...
auto *closureCall =
CallExpr::create(context, selfCall, closureArg, { }, { },
/*hasTrailingClosure=*/false,
/*implicit=*/true);
closureCall->setType(calleeResultTy);
cs.cacheType(closureCall);
Expr *closureBody = closureCall;
closureBody = coerceToType(closureCall, resultTy, locator);
if (selfFnTy->getExtInfo().isThrowing()) {
closureBody = new (context) TryExpr(closureBody->getStartLoc(), closureBody,
cs.getType(closureBody),
/*implicit=*/true);
cs.cacheType(closureBody);
}
if (selfParam.getPlainType()->hasOpenedExistential()) {
closureBody =
new (context) OpenExistentialExpr(
selfParamRef, cast<OpaqueValueExpr>(selfOpenedRef),
closureBody, resultTy);
cs.cacheType(closureBody);
}
closure->setBody(closureBody);
return closure;
}
/// Build a new member reference with the given base and member.
Expr *buildMemberRef(Expr *base, SourceLoc dotLoc,
SelectedOverload overload, DeclNameLoc memberLoc,
ConstraintLocatorBuilder locator,
ConstraintLocatorBuilder memberLocator, bool Implicit,
AccessSemantics semantics) {
auto choice = overload.choice;
auto openedType = overload.openedType;
ValueDecl *member = choice.getDecl();
auto &context = cs.getASTContext();
bool isSuper = base->isSuperExpr();
// The formal type of the 'self' value for the call.
Type baseTy = cs.getType(base)->getRValueType();
// Figure out the actual base type, and whether we have an instance of
// that type or its metatype.
bool baseIsInstance = true;
bool isExistentialMetatype = false;
if (auto baseMeta = baseTy->getAs<AnyMetatypeType>()) {
baseIsInstance = false;
isExistentialMetatype = baseMeta->is<ExistentialMetatypeType>();
baseTy = baseMeta->getInstanceType();
}
// Build a member reference.
auto memberRef = resolveConcreteDeclRef(member, memberLocator);
// If we're referring to a member type, it's just a type
// reference.
if (auto *TD = dyn_cast<TypeDecl>(member)) {
Type refType = simplifyType(openedType);
auto ref = TypeExpr::createForDecl(memberLoc, TD, cs.DC);
cs.setType(ref, refType);
auto *result = new (context) DotSyntaxBaseIgnoredExpr(
base, dotLoc, ref, refType);
cs.setType(result, refType);
return result;
}
auto refTy = simplifyType(overload.openedFullType);
// If we're referring to the member of a module, it's just a simple
// reference.
if (baseTy->is<ModuleType>()) {
assert(semantics == AccessSemantics::Ordinary &&
"Direct property access doesn't make sense for this");
auto ref = new (context) DeclRefExpr(memberRef, memberLoc, Implicit);
cs.setType(ref, refTy);
ref->setFunctionRefKind(choice.getFunctionRefKind());
auto *DSBI = cs.cacheType(new (context) DotSyntaxBaseIgnoredExpr(
base, dotLoc, ref, cs.getType(ref)));
return forceUnwrapIfExpected(DSBI, choice, memberLocator);
}
bool isUnboundInstanceMember =
(!baseIsInstance && member->isInstanceMember());
bool isPartialApplication = shouldBuildCurryThunk(choice, baseIsInstance);
// The formal type of the 'self' value for the member's declaration.
Type containerTy = getBaseType(refTy->castTo<FunctionType>());
// If we have an opened existential, selfTy and baseTy will both be
// the same opened existential type.
Type selfTy = containerTy;
// If we opened up an existential when referencing this member, update
// the base accordingly.
bool openedExistential = false;
// For a partial application, we have to open the existential inside
// the thunk itself.
auto knownOpened = solution.OpenedExistentialTypes.find(
getConstraintSystem().getConstraintLocator(
memberLocator));
if (knownOpened != solution.OpenedExistentialTypes.end()) {
// Determine if we're going to have an OpenExistentialExpr around
// this member reference.
//
// If we have a partial application of a protocol method, we open
// the existential in the curry thunk, instead of opening it here,
// because we won't have a 'self' value until the curry thunk is
// applied.
//
// However, a partial application of a class method on a subclass
// existential does need to open the existential, so that it can be
// upcast to the appropriate class reference type.
if (!isPartialApplication || !containerTy->hasOpenedExistential()) {
// Open the existential before performing the member reference.
base = openExistentialReference(base, knownOpened->second, member);
baseTy = knownOpened->second;
selfTy = baseTy;
openedExistential = true;
} else {
// Erase opened existentials from the type of the thunk; we're
// going to open the existential inside the thunk's body.
containerTy = containerTy->eraseOpenedExistential(knownOpened->second);
selfTy = containerTy;
}
}
// References to properties with accessors and storage usually go
// through the accessors, but sometimes are direct.
if (auto *VD = dyn_cast<VarDecl>(member)) {
if (semantics == AccessSemantics::Ordinary)
semantics = getImplicitMemberReferenceAccessSemantics(base, VD, dc);
}
auto isDynamic = choice.getKind() == OverloadChoiceKind::DeclViaDynamic;
if (baseIsInstance) {
// Convert the base to the appropriate container type, turning it
// into an lvalue if required.
// If the base is already an lvalue with the right base type, we can
// pass it as an inout qualified type.
auto selfParamTy = isDynamic ? selfTy : containerTy;
if (selfTy->isEqual(baseTy))
if (cs.getType(base)->is<LValueType>())
selfParamTy = InOutType::get(selfTy);
base = coerceSelfArgumentToType(
base, selfParamTy, member,
locator.withPathElement(ConstraintLocator::MemberRefBase));
} else {
if (!isExistentialMetatype || openedExistential) {
// Convert the base to an rvalue of the appropriate metatype.
base = coerceToType(base,
MetatypeType::get(
isDynamic ? selfTy : containerTy),
locator.withPathElement(
ConstraintLocator::MemberRefBase));
}
if (!base)
return nullptr;
base = cs.coerceToRValue(base);
}
assert(base && "Unable to convert base?");
// Handle dynamic references.
if (isDynamic || member->getAttrs().hasAttribute<OptionalAttr>()) {
base = cs.coerceToRValue(base);
Expr *ref = new (context) DynamicMemberRefExpr(base, dotLoc, memberRef,
memberLoc);
ref->setImplicit(Implicit);
// FIXME: FunctionRefKind
// Compute the type of the reference.
Type refType = simplifyType(openedType);
// If the base was an opened existential, erase the opened
// existential.
if (openedExistential) {
refType = refType->eraseOpenedExistential(
baseTy->castTo<OpenedArchetypeType>());
}
cs.setType(ref, refType);
closeExistential(ref, locator, /*force=*/openedExistential);
// If this attribute was inferred based on deprecated Swift 3 rules,
// complain.
if (auto attr = member->getAttrs().getAttribute<ObjCAttr>()) {
if (attr->isSwift3Inferred() &&
context.LangOpts.WarnSwift3ObjCInference ==
Swift3ObjCInferenceWarnings::Minimal) {
context.Diags.diagnose(
memberLoc, diag::expr_dynamic_lookup_swift3_objc_inference,
member->getDescriptiveKind(), member->getName(),
member->getDeclContext()->getSelfNominalTypeDecl()->getName());
context.Diags
.diagnose(member, diag::make_decl_objc,
member->getDescriptiveKind())
.fixItInsert(member->getAttributeInsertionLoc(false), "@objc ");
}
}
if (isDynamic) {
// Rewrite for implicit unwrapping if the solution requires it.
auto *dynamicLocator =
cs.getConstraintLocator(memberLocator.withPathElement(
ConstraintLocator::DynamicLookupResult));
if (solution.getDisjunctionChoice(dynamicLocator)) {
auto *forceValue =
new (context) ForceValueExpr(ref, ref->getEndLoc());
auto optTy = cs.getType(forceValue->getSubExpr());
cs.setType(forceValue, optTy->getOptionalObjectType());
ref = forceValue;
}
}
// We also need to handle the implicitly unwrap of the result
// of the called function if that's the type checking solution
// we ended up with.
return forceUnwrapIfExpected(
ref, choice, memberLocator,
member->getAttrs().hasAttribute<OptionalAttr>());
}
// For properties, build member references.
if (auto *varDecl = dyn_cast<VarDecl>(member)) {
if (isUnboundInstanceMember) {
assert(memberLocator.getBaseLocator() &&
cs.UnevaluatedRootExprs.count(
getAsExpr(memberLocator.getBaseLocator()->getAnchor())) &&
"Attempt to reference an instance member of a metatype");
auto baseInstanceTy = cs.getType(base)
->getInOutObjectType()->getMetatypeInstanceType();
base = new (context) UnevaluatedInstanceExpr(base, baseInstanceTy);
cs.cacheType(base);
base->setImplicit();
}
auto hasDynamicSelf =
varDecl->getValueInterfaceType()->hasDynamicSelfType();
auto memberRefExpr
= new (context) MemberRefExpr(base, dotLoc, memberRef,
memberLoc, Implicit, semantics);
memberRefExpr->setIsSuper(isSuper);
if (hasDynamicSelf)
refTy = refTy->replaceCovariantResultType(containerTy, 1);
cs.setType(memberRefExpr, refTy->castTo<FunctionType>()->getResult());
Expr *result = memberRefExpr;
closeExistential(result, locator);
if (hasDynamicSelf) {
if (!baseTy->isEqual(containerTy)) {
result = new (context) CovariantReturnConversionExpr(
result, simplifyType(openedType));
cs.cacheType(result);
}
}
return forceUnwrapIfExpected(result, choice, memberLocator);
}
if (member->getInterfaceType()->hasDynamicSelfType())
refTy = refTy->replaceCovariantResultType(containerTy, 2);
// Handle all other references.
auto declRefExpr = new (context) DeclRefExpr(memberRef, memberLoc,
Implicit, semantics);
declRefExpr->setFunctionRefKind(choice.getFunctionRefKind());
declRefExpr->setType(refTy);
cs.setType(declRefExpr, refTy);
Expr *ref = declRefExpr;
if (isPartialApplication) {
auto curryThunkTy = refTy->castTo<FunctionType>();
// A partial application thunk consists of two nested closures:
//
// { self in { args... in self.method(args...) } }
//
// If the reference has an applied 'self', eg 'let fn = foo.method',
// the outermost closure is wrapped inside a single ApplyExpr:
//
// { self in { args... in self.method(args...) } }(foo)
//
// This is done instead of just hoising the expression 'foo' up
// into the closure, which would change evaluation order.
//
// However, for a super method reference, eg, 'let fn = super.foo',
// the base expression is always a SuperRefExpr, possibly wrapped
// by an upcast. Since SILGen expects super method calls to have a
// very specific shape, we only emit a single closure here and
// capture the original SuperRefExpr, since its evaluation does not
// have side effects, instead of abstracting out a 'self' parameter.
if (isSuper) {
auto selfFnTy = curryThunkTy->getResult()->castTo<FunctionType>();
auto closure = buildCurryThunk(member, selfFnTy, base, ref,
memberLocator);
// Skip the code below -- we're not building an extra level of
// call by applying the 'super', instead the closure we just
// built is the curried reference.
return closure;
}
// Another case where we want to build a single closure is when
// we have a partial application of a constructor on a statically-
// derived metatype value. Again, there are no order of evaluation
// concerns here, and keeping the call and base together in the AST
// improves SILGen.
if (isa<ConstructorDecl>(member) &&
cs.isStaticallyDerivedMetatype(base)) {
auto selfFnTy = curryThunkTy->getResult()->castTo<FunctionType>();
// Add a useless ".self" to avoid downstream diagnostics.
base = new (context) DotSelfExpr(base, SourceLoc(), base->getEndLoc(),
cs.getType(base));
cs.setType(base, base->getType());
auto closure = buildCurryThunk(member, selfFnTy, base, ref,
memberLocator);
// Skip the code below -- we're not building an extra level of
// call by applying the metatype instead the closure we just
// built is the curried reference.
return closure;
}
// Check if we need to open an existential stored inside 'self'.
auto knownOpened = solution.OpenedExistentialTypes.find(
getConstraintSystem().getConstraintLocator(
memberLocator));
if (knownOpened != solution.OpenedExistentialTypes.end()) {
curryThunkTy =
curryThunkTy->eraseOpenedExistential(knownOpened->second)
->castTo<FunctionType>();
}
auto discriminator = AutoClosureExpr::InvalidDiscriminator;
// The outer closure.
//
// let outerClosure = "{ self in \(closure) }"
auto selfParam = curryThunkTy->getParams()[0];
auto selfParamDecl = new (context) ParamDecl(
SourceLoc(),
/*argument label*/ SourceLoc(), Identifier(),
/*parameter name*/ SourceLoc(), context.Id_self,
cs.DC);
auto selfParamTy = selfParam.getPlainType();
bool isLValue = selfParam.isInOut();
selfParamDecl->setInterfaceType(selfParamTy->mapTypeOutOfContext());
selfParamDecl->setSpecifier(
ParamDecl::getParameterSpecifierForValueOwnership(
selfParam.getValueOwnership()));
auto *outerParams =
ParameterList::create(context, SourceLoc(), selfParamDecl,
SourceLoc());
// The inner closure.
//
// let closure = "{ args... in self.member(args...) }"
auto selfFnTy = curryThunkTy->getResult()->castTo<FunctionType>();
Expr *selfParamRef =
new (context) DeclRefExpr(selfParamDecl, DeclNameLoc(),
/*implicit=*/true);
selfParamRef->setType(
isLValue ? LValueType::get(selfParamTy) : selfParamTy);
cs.cacheType(selfParamRef);
if (isLValue) {
selfParamRef =
new (context) InOutExpr(SourceLoc(), selfParamRef, selfParamTy,
/*implicit=*/true);
cs.cacheType(selfParamRef);
}
auto closure = buildCurryThunk(member, selfFnTy, selfParamRef, ref,
memberLocator);
auto outerClosure =
new (context) AutoClosureExpr(closure, selfFnTy,
discriminator, cs.DC);
outerClosure->setThunkKind(AutoClosureExpr::Kind::DoubleCurryThunk);
outerClosure->setParameterList(outerParams);
outerClosure->setType(curryThunkTy);
cs.cacheType(outerClosure);
// Replace the DeclRefExpr with a closure expression which SILGen
// knows how to emit.
ref = outerClosure;
}
// If this is a method whose result type is dynamic Self, or a
// construction, replace the result type with the actual object type.
if (!member->getDeclContext()->getSelfProtocolDecl()) {
if (auto func = dyn_cast<AbstractFunctionDecl>(member)) {
if (func->hasDynamicSelfResult() &&
!baseTy->getOptionalObjectType()) {
if (!baseTy->isEqual(containerTy)) {
auto dynamicSelfFnType = refTy->replaceCovariantResultType(baseTy, 2);
ref = new (context) CovariantFunctionConversionExpr(ref,
dynamicSelfFnType);
cs.cacheType(ref);
}
}
}
}
ApplyExpr *apply;
if (isa<ConstructorDecl>(member)) {
// FIXME: Provide type annotation.
ref = forceUnwrapIfExpected(ref, choice, memberLocator);
apply = new (context) ConstructorRefCallExpr(ref, base);
} else if (isUnboundInstanceMember) {
auto refType = cs.simplifyType(openedType);
if (!cs.getType(ref)->isEqual(refType)) {
ref = new (context) FunctionConversionExpr(ref, refType);
cs.cacheType(ref);
}
// Reference to an unbound instance method.
Expr *result = new (context) DotSyntaxBaseIgnoredExpr(base, dotLoc,
ref,
cs.getType(ref));
cs.cacheType(result);
closeExistential(result, locator, /*force=*/openedExistential);
return forceUnwrapIfExpected(result, choice, memberLocator);
} else {
assert((!baseIsInstance || member->isInstanceMember()) &&
"can't call a static method on an instance");
ref = forceUnwrapIfExpected(ref, choice, memberLocator);
apply = new (context) DotSyntaxCallExpr(ref, dotLoc, base);
if (Implicit) {
apply->setImplicit();
}
}
return finishApply(apply, openedType, locator, memberLocator);
}
/// Convert the given literal expression via a protocol pair.
///
/// This routine handles the two-step literal conversion process used
/// by integer, float, character, extended grapheme cluster, and string
/// literals. The first step uses \c builtinProtocol while the second
/// step uses \c protocol.
///
/// \param literal The literal expression.
///
/// \param type The literal type. This type conforms to \c protocol,
/// and may also conform to \c builtinProtocol.
///
/// \param protocol The protocol that describes the literal requirement.
///
/// \param literalType The name of the associated type in \c protocol that
/// describes the argument type of the conversion function (\c
/// literalFuncName).
///
/// \param literalFuncName The name of the conversion function requirement
/// in \c protocol.
///
/// \param builtinProtocol The "builtin" form of the protocol, which
/// always takes builtin types and can only be properly implemented
/// by standard library types. If \c type does not conform to this
/// protocol, it's literal type will.
///
/// \param builtinLiteralFuncName The name of the conversion function
/// requirement in \c builtinProtocol.
///
/// \param brokenProtocolDiag The diagnostic to emit if the protocol
/// is broken.
///
/// \param brokenBuiltinProtocolDiag The diagnostic to emit if the builtin
/// protocol is broken.
///
/// \returns the converted literal expression.
Expr *convertLiteralInPlace(LiteralExpr *literal, Type type,
ProtocolDecl *protocol, Identifier literalType,
DeclName literalFuncName,
ProtocolDecl *builtinProtocol,
DeclName builtinLiteralFuncName,
Diag<> brokenProtocolDiag,
Diag<> brokenBuiltinProtocolDiag);
/// Finish a function application by performing the appropriate
/// conversions on the function and argument expressions and setting
/// the resulting type.
///
/// \param apply The function application to finish type-checking, which
/// may be a newly-built expression.
///
/// \param openedType The "opened" type this expression had during
/// type checking, which will be used to specialize the resulting,
/// type-checked expression appropriately.
///
/// \param locator The locator for the original expression.
///
/// \param calleeLocator The locator that identifies the apply's callee.
Expr *finishApply(ApplyExpr *apply, Type openedType,
ConstraintLocatorBuilder locator,
ConstraintLocatorBuilder calleeLocator);
/// Build the function and argument for a `@dynamicCallable` application.
std::pair</*fn*/ Expr *, /*arg*/ Expr *>
buildDynamicCallable(ApplyExpr *apply, SelectedOverload selected,
FuncDecl *method, AnyFunctionType *methodType,
ConstraintLocatorBuilder applyFunctionLoc);
private:
/// Simplify the given type by substituting all occurrences of
/// type variables for their fixed types.
Type simplifyType(Type type) {
return solution.simplifyType(type);
}
public:
/// Coerce the given expression to the given type.
///
/// This operation cannot fail.
///
/// \param expr The expression to coerce.
/// \param toType The type to coerce the expression to.
/// \param locator Locator used to describe where in this expression we are.
/// \param typeFromPattern Optionally, the caller can specify the pattern
/// from where the toType is derived, so that we can deliver better fixit.
///
/// \returns the coerced expression, which will have type \c ToType.
Expr *coerceToType(Expr *expr, Type toType,
ConstraintLocatorBuilder locator,
Optional<Pattern*> typeFromPattern = None);
/// Coerce the given expression (which is the argument to a call) to
/// the given parameter type.
///
/// This operation cannot fail.
///
/// \param arg The argument expression.
/// \param funcType The function type.
/// \param callee The callee for the function being applied.
/// \param apply The ApplyExpr that forms the call.
/// \param argLabels The argument labels provided for the call.
/// \param locator Locator used to describe where in this expression we are.
///
/// \returns the coerced expression, which will have type \c ToType.
Expr *
coerceCallArguments(Expr *arg, AnyFunctionType *funcType,
ConcreteDeclRef callee, ApplyExpr *apply,
ArrayRef<Identifier> argLabels,
ConstraintLocatorBuilder locator);
/// Coerce the given 'self' argument (e.g., for the base of a
/// member expression) to the given type.
///
/// \param expr The expression to coerce.
///
/// \param baseTy The base type
///
/// \param member The member being accessed.
///
/// \param locator Locator used to describe where in this expression we are.
Expr *coerceSelfArgumentToType(Expr *expr,
Type baseTy, ValueDecl *member,
ConstraintLocatorBuilder locator);
private:
/// Build a new subscript.
///
/// \param base The base of the subscript.
/// \param index The index of the subscript.
/// \param locator The locator used to refer to the subscript.
/// \param isImplicit Whether this is an implicit subscript.
Expr *buildSubscript(Expr *base, Expr *index,
ArrayRef<Identifier> argLabels,
bool hasTrailingClosure,
ConstraintLocatorBuilder locator, bool isImplicit,
AccessSemantics semantics,
const SelectedOverload &selected) {
// Build the new subscript.
auto newSubscript = buildSubscriptHelper(base, index, argLabels,
selected, hasTrailingClosure,
locator, isImplicit, semantics);
if (selected.choice.getKind() == OverloadChoiceKind::DeclViaDynamic) {
// Rewrite for implicit unwrapping if the solution requires it.
auto *dynamicLocator = cs.getConstraintLocator(
locator, {ConstraintLocator::SubscriptMember,
ConstraintLocator::DynamicLookupResult});
if (solution.getDisjunctionChoice(dynamicLocator)) {
auto *forceValue = new (cs.getASTContext())
ForceValueExpr(newSubscript, newSubscript->getEndLoc());
auto optTy = cs.getType(forceValue->getSubExpr());
cs.setType(forceValue, optTy->getOptionalObjectType());
newSubscript = forceValue;
}
}
if (selected.choice.isDecl()) {
auto locatorKind = ConstraintLocator::SubscriptMember;
if (selected.choice.getKind() ==
OverloadChoiceKind::DynamicMemberLookup)
locatorKind = ConstraintLocator::Member;
if (selected.choice.getKind() ==
OverloadChoiceKind::KeyPathDynamicMemberLookup &&
!isExpr<SubscriptExpr>(locator.getAnchor()))
locatorKind = ConstraintLocator::Member;
newSubscript =
forceUnwrapIfExpected(newSubscript, selected.choice,
locator.withPathElement(locatorKind));
}
return newSubscript;
}
Expr *buildSubscriptHelper(Expr *base, Expr *index,
ArrayRef<Identifier> argLabels,
const SelectedOverload &selected,
bool hasTrailingClosure,
ConstraintLocatorBuilder locator,
bool isImplicit, AccessSemantics semantics) {
auto choice = selected.choice;
auto &ctx = cs.getASTContext();
// Apply a key path if we have one.
if (choice.getKind() == OverloadChoiceKind::KeyPathApplication) {
auto applicationTy =
simplifyType(selected.openedType)->castTo<FunctionType>();
index = cs.coerceToRValue(index);
// The index argument should be (keyPath: KeyPath<Root, Value>).
// Dig the key path expression out of the arguments.
auto indexKP = cast<TupleExpr>(index)->getElement(0);
auto keyPathExprTy = cs.getType(indexKP);
auto keyPathTy = applicationTy->getParams().front().getOldType();
Type valueTy;
Type baseTy;
bool resultIsLValue;
if (auto nom = keyPathTy->getAs<NominalType>()) {
// AnyKeyPath is <T> rvalue T -> rvalue Any?
if (nom->getDecl() == cs.getASTContext().getAnyKeyPathDecl()) {
valueTy = ProtocolCompositionType::get(cs.getASTContext(), {},
/*explicit anyobject*/ false);
valueTy = OptionalType::get(valueTy);
resultIsLValue = false;
base = cs.coerceToRValue(base);
baseTy = cs.getType(base);
// We don't really want to attempt AnyKeyPath application
// if we know a more specific key path type is being applied.
if (!keyPathTy->isEqual(keyPathExprTy)) {
ctx.Diags
.diagnose(base->getLoc(),
diag::expr_smart_keypath_application_type_mismatch,
keyPathExprTy, baseTy)
.highlight(index->getSourceRange());
}
} else {
llvm_unreachable("unknown key path class!");
}
} else {
auto keyPathBGT = keyPathTy->castTo<BoundGenericType>();
baseTy = keyPathBGT->getGenericArgs()[0];
// Coerce the index to the key path's type
indexKP = coerceToType(indexKP, keyPathTy, locator);
// Coerce the base to the key path's expected base type.
if (!baseTy->isEqual(cs.getType(base)->getRValueType()))
base = coerceToType(base, baseTy, locator);
if (keyPathBGT->getDecl()
== cs.getASTContext().getPartialKeyPathDecl()) {
// PartialKeyPath<T> is rvalue T -> rvalue Any
valueTy = ProtocolCompositionType::get(cs.getASTContext(), {},
/*explicit anyobject*/ false);
resultIsLValue = false;
base = cs.coerceToRValue(base);
} else {
// *KeyPath<T, U> is T -> U, with rvalueness based on mutability
// of base and keypath
valueTy = keyPathBGT->getGenericArgs()[1];
// The result may be an lvalue based on the base and key path kind.
if (keyPathBGT->getDecl() == cs.getASTContext().getKeyPathDecl()) {
resultIsLValue = false;
base = cs.coerceToRValue(base);
} else if (keyPathBGT->getDecl() ==
cs.getASTContext().getWritableKeyPathDecl()) {
resultIsLValue = cs.getType(base)->hasLValueType();
} else if (keyPathBGT->getDecl() ==
cs.getASTContext().getReferenceWritableKeyPathDecl()) {
resultIsLValue = true;
base = cs.coerceToRValue(base);
} else {
llvm_unreachable("unknown key path class!");
}
}
}
if (resultIsLValue)
valueTy = LValueType::get(valueTy);
auto keyPathAp = new (cs.getASTContext())
KeyPathApplicationExpr(base, index->getStartLoc(), indexKP,
index->getEndLoc(), valueTy,
base->isImplicit() && index->isImplicit());
cs.setType(keyPathAp, valueTy);
return keyPathAp;
}
auto subscript = cast<SubscriptDecl>(choice.getDecl());
auto baseTy = cs.getType(base)->getRValueType();
bool baseIsInstance = true;
if (auto baseMeta = baseTy->getAs<AnyMetatypeType>()) {
baseIsInstance = false;
baseTy = baseMeta->getInstanceType();
}
// Check whether the base is 'super'.
bool isSuper = base->isSuperExpr();
// Use the correct locator kind based on the subscript kind.
auto locatorKind = ConstraintLocator::SubscriptMember;
if (choice.getKind() == OverloadChoiceKind::DynamicMemberLookup)
locatorKind = ConstraintLocator::Member;
if (choice.getKind() == OverloadChoiceKind::KeyPathDynamicMemberLookup) {
locatorKind = isExpr<SubscriptExpr>(locator.getAnchor())
? ConstraintLocator::SubscriptMember
: ConstraintLocator::Member;
}
// If we opened up an existential when performing the subscript, open
// the base accordingly.
auto memberLoc = locator.withPathElement(locatorKind);
auto knownOpened = solution.OpenedExistentialTypes.find(
cs.getConstraintLocator(memberLoc));
if (knownOpened != solution.OpenedExistentialTypes.end()) {
base = openExistentialReference(base, knownOpened->second, subscript);
baseTy = knownOpened->second;
}
// Compute the concrete reference to the subscript.
auto subscriptRef = resolveConcreteDeclRef(subscript, memberLoc);
// Coerce the index argument.
auto openedFullFnType = simplifyType(selected.openedFullType)
->castTo<FunctionType>();
auto fullSubscriptTy = openedFullFnType->getResult()
->castTo<FunctionType>();
index = coerceCallArguments(index, fullSubscriptTy, subscriptRef, nullptr,
argLabels,
locator.withPathElement(
ConstraintLocator::ApplyArgument));
if (!index)
return nullptr;
auto getType = [&](Expr *E) -> Type { return cs.getType(E); };
// Handle dynamic lookup.
if (choice.getKind() == OverloadChoiceKind::DeclViaDynamic ||
subscript->getAttrs().hasAttribute<OptionalAttr>()) {
base = coerceSelfArgumentToType(base, baseTy, subscript, locator);
if (!base)
return nullptr;
// TODO: diagnose if semantics != AccessSemantics::Ordinary?
auto subscriptExpr = DynamicSubscriptExpr::create(
ctx, base, index, subscriptRef, isImplicit, getType);
auto resultTy = simplifyType(selected.openedType)
->castTo<FunctionType>()
->getResult();
assert(!selected.openedFullType->hasOpenedExistential()
&& "open existential archetype in AnyObject subscript type?");
cs.setType(subscriptExpr, resultTy);
Expr *result = subscriptExpr;
closeExistential(result, locator);
return result;
}
// Convert the base.
auto openedBaseType =
getBaseType(openedFullFnType, /*wantsRValue*/ false);
auto containerTy = solution.simplifyType(openedBaseType);
if (baseIsInstance) {
base = coerceSelfArgumentToType(
base, containerTy, subscript,
locator.withPathElement(ConstraintLocator::MemberRefBase));
} else {
base = coerceToType(base,
MetatypeType::get(containerTy),
locator.withPathElement(
ConstraintLocator::MemberRefBase));
if (!base)
return nullptr;
base = cs.coerceToRValue(base);
}
if (!base)
return nullptr;
// Form the subscript expression.
auto subscriptExpr = SubscriptExpr::create(
ctx, base, index, subscriptRef, isImplicit, semantics, getType);
cs.setType(subscriptExpr, fullSubscriptTy->getResult());
subscriptExpr->setIsSuper(isSuper);
Expr *result = subscriptExpr;
closeExistential(result, locator);
if (subscript->getElementInterfaceType()->hasDynamicSelfType()) {
auto dynamicSelfFnType =
openedFullFnType->replaceCovariantResultType(baseTy, 2);
result =
new (ctx) CovariantReturnConversionExpr(result, dynamicSelfFnType);
cs.cacheType(result);
cs.setType(result, simplifyType(baseTy));
}
return result;
}
/// Build a new reference to another constructor.
Expr *buildOtherConstructorRef(Type openedFullType,
ConcreteDeclRef ref, Expr *base,
DeclNameLoc loc,
ConstraintLocatorBuilder locator,
bool implicit) {
auto &ctx = cs.getASTContext();
// The constructor was opened with the allocating type, not the
// initializer type. Map the former into the latter.
auto resultTy = solution.simplifyType(openedFullType);
auto selfTy = getBaseType(resultTy->castTo<FunctionType>());
// Also replace the result type with the base type, so that calls
// to constructors defined in a superclass will know to cast the
// result to the derived type.
resultTy = resultTy->replaceCovariantResultType(selfTy, 2);
ParameterTypeFlags flags;
if (!selfTy->hasReferenceSemantics())
flags = flags.withInOut(true);
auto selfParam = AnyFunctionType::Param(selfTy, Identifier(), flags);
resultTy = FunctionType::get({selfParam},
resultTy->castTo<FunctionType>()->getResult(),
resultTy->castTo<FunctionType>()->getExtInfo());
// Build the constructor reference.
Expr *ctorRef = cs.cacheType(
new (ctx) OtherConstructorDeclRefExpr(ref, loc, implicit, resultTy));
// Wrap in covariant `Self` return if needed.
if (selfTy->hasReferenceSemantics()) {
auto covariantTy = resultTy->replaceCovariantResultType(
cs.getType(base)->getWithoutSpecifierType(), 2);
if (!covariantTy->isEqual(resultTy))
ctorRef = cs.cacheType(
new (ctx) CovariantFunctionConversionExpr(ctorRef, covariantTy));
}
return ctorRef;
}
/// Build an implicit argument for keypath based dynamic lookup,
/// which consists of KeyPath expression and a single component.
///
/// \param keyPathTy The type of the keypath argument.
/// \param dotLoc The location of the '.' preceding member name.
/// \param memberLoc The locator to be associated with new argument.
Expr *buildKeyPathDynamicMemberIndexExpr(BoundGenericType *keyPathTy,
SourceLoc dotLoc,
ConstraintLocator *memberLoc) {
auto &ctx = cs.getASTContext();
auto *anchor = getAsExpr(memberLoc->getAnchor());
SmallVector<KeyPathExpr::Component, 2> components;
// Let's create a KeyPath expression and fill in "parsed path"
// after component is built.
auto *keyPath = new (ctx) KeyPathExpr(/*backslashLoc=*/dotLoc,
/*parsedRoot=*/nullptr,
/*parsedPath=*/anchor,
/*hasLeadingDot=*/false,
/*isImplicit=*/true);
// Type of the keypath expression we are forming is known
// in advance, so let's set it right away.
keyPath->setType(keyPathTy);
cs.cacheType(keyPath);
auto *componentLoc = cs.getConstraintLocator(
memberLoc,
LocatorPathElt::KeyPathDynamicMember(keyPathTy->getAnyNominal()));
auto overload = solution.getOverloadChoice(componentLoc);
// Looks like there is a chain of implicit `subscript(dynamicMember:)`
// calls necessary to resolve a member reference.
switch (overload.choice.getKind()) {
case OverloadChoiceKind::DynamicMemberLookup:
case OverloadChoiceKind::KeyPathDynamicMemberLookup: {
buildKeyPathSubscriptComponent(overload, dotLoc, /*indexExpr=*/nullptr,
ctx.Id_dynamicMember, componentLoc,
components);
keyPath->resolveComponents(ctx, components);
cs.cacheExprTypes(keyPath);
return keyPath;
}
default:
break;
}
// We can't reuse existing expression because type-check
// based diagnostics could hold the reference to original AST.
Expr *componentExpr = nullptr;
auto *dotExpr = new (ctx) KeyPathDotExpr(dotLoc);
// Determines whether this index is built to be used for
// one of the existing keypath components e.g. `\Lens<[Int]>.count`
// instead of a regular expression e.g. `lens[0]`.
bool forKeyPathComponent = false;
// Looks like keypath dynamic member lookup was used inside
// of a keypath expression e.g. `\Lens<[Int]>.count` where
// `count` is referenced using dynamic lookup.
if (auto *KPE = dyn_cast<KeyPathExpr>(anchor)) {
auto kpElt = memberLoc->findFirst<LocatorPathElt::KeyPathComponent>();
assert(kpElt && "no keypath component node");
auto &origComponent = KPE->getComponents()[kpElt->getIndex()];
using ComponentKind = KeyPathExpr::Component::Kind;
if (origComponent.getKind() == ComponentKind::UnresolvedProperty) {
anchor = new (ctx) UnresolvedDotExpr(
dotExpr, dotLoc, origComponent.getUnresolvedDeclName(),
DeclNameLoc(origComponent.getLoc()),
/*Implicit=*/true);
} else if (origComponent.getKind() ==
ComponentKind::UnresolvedSubscript) {
anchor = SubscriptExpr::create(
ctx, dotExpr, origComponent.getIndexExpr(), ConcreteDeclRef(),
/*implicit=*/true, AccessSemantics::Ordinary,
[&](Expr *expr) { return simplifyType(cs.getType(expr)); });
} else {
return nullptr;
}
anchor->setType(simplifyType(overload.openedType));
cs.cacheType(anchor);
forKeyPathComponent = true;
}
if (auto *UDE = dyn_cast<UnresolvedDotExpr>(anchor)) {
componentExpr =
forKeyPathComponent
? UDE
: new (ctx) UnresolvedDotExpr(dotExpr, dotLoc, UDE->getName(),
UDE->getNameLoc(),
/*Implicit=*/true);
buildKeyPathPropertyComponent(overload, UDE->getLoc(), componentLoc,
components);
} else if (auto *SE = dyn_cast<SubscriptExpr>(anchor)) {
componentExpr = SE;
// If this is not for a keypath component, we have to copy
// original subscript expression because expression based
// diagnostics might have a reference to it, so it couldn't
// be modified.
if (!forKeyPathComponent) {
SmallVector<Expr *, 4> arguments;
if (auto *TE = dyn_cast<TupleExpr>(SE->getIndex())) {
auto args = TE->getElements();
arguments.append(args.begin(), args.end());
} else {
arguments.push_back(SE->getIndex()->getSemanticsProvidingExpr());
}
SmallVector<TrailingClosure, 2> trailingClosures;
if (SE->hasTrailingClosure()) {
auto *closure = arguments.back();
trailingClosures.push_back({closure});
}
componentExpr = SubscriptExpr::create(
ctx, dotExpr, SE->getStartLoc(), arguments,
SE->getArgumentLabels(), SE->getArgumentLabelLocs(),
SE->getEndLoc(), trailingClosures,
SE->hasDecl() ? SE->getDecl() : ConcreteDeclRef(),
/*implicit=*/true, SE->getAccessSemantics());
}
buildKeyPathSubscriptComponent(overload, SE->getLoc(), SE->getIndex(),
SE->getArgumentLabels(), componentLoc,
components);
} else {
return nullptr;
}
assert(componentExpr);
Type ty = simplifyType(cs.getType(anchor));
componentExpr->setType(ty);
cs.cacheType(componentExpr);
keyPath->setParsedPath(componentExpr);
keyPath->resolveComponents(ctx, components);
cs.cacheExprTypes(keyPath);
// See whether there's an equivalent ObjC key path string we can produce
// for interop purposes.
checkAndSetObjCKeyPathString(keyPath);
return keyPath;
}
/// Bridge the given value (which is an error type) to NSError.
Expr *bridgeErrorToObjectiveC(Expr *value) {
auto &ctx = cs.getASTContext();
auto nsErrorType = ctx.getNSErrorType();
assert(nsErrorType && "Missing NSError?");
auto result = new (ctx) BridgeToObjCExpr(value, nsErrorType);
return cs.cacheType(result);
}
/// Bridge the given value to its corresponding Objective-C object
/// type.
///
/// This routine should only be used for bridging value types.
///
/// \param value The value to be bridged.
Expr *bridgeToObjectiveC(Expr *value, Type objcType) {
auto result = new (cs.getASTContext()) BridgeToObjCExpr(value, objcType);
return cs.cacheType(result);
}
/// Bridge the given object from Objective-C to its value type.
///
/// This routine should only be used for bridging value types.
///
/// \param object The object, whose type should already be of the type
/// that the value type bridges through.
///
/// \param valueType The value type to which we are bridging.
///
/// \param conditional Whether the bridging should be conditional. If false,
/// uses forced bridging.
///
/// \returns a value of type \c valueType (optional if \c conditional) that
/// stores the bridged result or (when \c conditional) an empty optional if
/// conditional bridging fails.
Expr *bridgeFromObjectiveC(Expr *object, Type valueType, bool conditional) {
auto &ctx = cs.getASTContext();
if (!conditional) {
auto result = new (ctx) BridgeFromObjCExpr(object, valueType);
return cs.cacheType(result);
}
// Find the _BridgedToObjectiveC protocol.
auto bridgedProto =
ctx.getProtocol(KnownProtocolKind::ObjectiveCBridgeable);
// Try to find the conformance of the value type to _BridgedToObjectiveC.
auto bridgedToObjectiveCConformance
= TypeChecker::conformsToProtocol(valueType,
bridgedProto,
cs.DC);
FuncDecl *fn = nullptr;
if (bridgedToObjectiveCConformance) {
assert(bridgedToObjectiveCConformance.getConditionalRequirements()
.empty() &&
"cannot conditionally conform to _BridgedToObjectiveC");
// The conformance to _BridgedToObjectiveC is statically known.
// Retrieve the bridging operation to be used if a static conformance
// to _BridgedToObjectiveC can be proven.
fn = conditional ? ctx.getConditionallyBridgeFromObjectiveCBridgeable()
: ctx.getForceBridgeFromObjectiveCBridgeable();
} else {
// Retrieve the bridging operation to be used if a static conformance
// to _BridgedToObjectiveC cannot be proven.
fn = conditional ? ctx.getConditionallyBridgeFromObjectiveC()
: ctx.getForceBridgeFromObjectiveC();
}
if (!fn) {
ctx.Diags.diagnose(object->getLoc(), diag::missing_bridging_function,
conditional);
return nullptr;
}
// Form a reference to the function. The bridging operations are generic,
// so we need to form substitutions and compute the resulting type.
auto genericSig = fn->getGenericSignature();
auto subMap = SubstitutionMap::get(
genericSig,
[&](SubstitutableType *type) -> Type {
assert(type->isEqual(genericSig->getGenericParams()[0]));
return valueType;
},
[&](CanType origType, Type replacementType,
ProtocolDecl *protoType) -> ProtocolConformanceRef {
assert(bridgedToObjectiveCConformance);
return bridgedToObjectiveCConformance;
});
ConcreteDeclRef fnSpecRef(fn, subMap);
auto resultType = OptionalType::get(valueType);
auto result = new (ctx)
ConditionalBridgeFromObjCExpr(object, resultType, fnSpecRef);
return cs.cacheType(result);
}
/// Bridge the given object from Objective-C to its value type.
///
/// This routine should only be used for bridging value types.
///
/// \param object The object, whose type should already be of the type
/// that the value type bridges through.
///
/// \param valueType The value type to which we are bridging.
///
/// \returns a value of type \c valueType that stores the bridged result.
Expr *forceBridgeFromObjectiveC(Expr *object, Type valueType) {
return bridgeFromObjectiveC(object, valueType, false);
}
public:
ExprRewriter(ConstraintSystem &cs, Solution &solution,
Optional<SolutionApplicationTarget> target,
bool suppressDiagnostics)
: cs(cs), dc(cs.DC), solution(solution), target(target),
SuppressDiagnostics(suppressDiagnostics) {}
ConstraintSystem &getConstraintSystem() const { return cs; }
/// Simplify the expression type and return the expression.
///
/// This routine is used for 'simple' expressions that only need their
/// types simplified, with no further computation.
Expr *simplifyExprType(Expr *expr) {
auto toType = simplifyType(cs.getType(expr));
cs.setType(expr, toType);
return expr;
}
Expr *visitErrorExpr(ErrorExpr *expr) {
// Do nothing with error expressions.
return expr;
}
Expr *visitCodeCompletionExpr(CodeCompletionExpr *expr) {
// Do nothing with code completion expressions.
auto toType = simplifyType(cs.getType(expr));
cs.setType(expr, toType);
return expr;
}
Expr *handleIntegerLiteralExpr(LiteralExpr *expr) {
// If the literal has been assigned a builtin integer type,
// don't mess with it.
if (cs.getType(expr)->is<AnyBuiltinIntegerType>())
return expr;
auto &ctx = cs.getASTContext();
ProtocolDecl *protocol = TypeChecker::getProtocol(
cs.getASTContext(), expr->getLoc(),
KnownProtocolKind::ExpressibleByIntegerLiteral);
ProtocolDecl *builtinProtocol = TypeChecker::getProtocol(
cs.getASTContext(), expr->getLoc(),
KnownProtocolKind::ExpressibleByBuiltinIntegerLiteral);
// For type-sugar reasons, prefer the spelling of the default literal
// type.
auto type = simplifyType(cs.getType(expr));
if (auto defaultType = TypeChecker::getDefaultType(protocol, dc)) {
if (defaultType->isEqual(type))
type = defaultType;
}
if (auto floatProtocol = TypeChecker::getProtocol(
cs.getASTContext(), expr->getLoc(),
KnownProtocolKind::ExpressibleByFloatLiteral)) {
if (auto defaultFloatType =
TypeChecker::getDefaultType(floatProtocol, dc)) {
if (defaultFloatType->isEqual(type))
type = defaultFloatType;
}
}
DeclName initName(ctx, DeclBaseName::createConstructor(),
{ctx.Id_integerLiteral});
DeclName builtinInitName(ctx, DeclBaseName::createConstructor(),
{ctx.Id_builtinIntegerLiteral});
auto *result = convertLiteralInPlace(
expr, type, protocol, ctx.Id_IntegerLiteralType, initName,
builtinProtocol, builtinInitName, diag::integer_literal_broken_proto,
diag::builtin_integer_literal_broken_proto);
if (result) {
// TODO: It seems that callers expect this to have types assigned...
result->setType(cs.getType(result));
}
return result;
}
Expr *visitNilLiteralExpr(NilLiteralExpr *expr) {
auto type = simplifyType(cs.getType(expr));
// By far the most common 'nil' literal is for Optional<T>.none.
// We don't have to look up the witness in this case since SILGen
// knows how to lower it directly.
if (auto objectType = type->getOptionalObjectType()) {
cs.setType(expr, type);
return expr;
}
auto &ctx = cs.getASTContext();
auto *protocol = TypeChecker::getProtocol(
ctx, expr->getLoc(), KnownProtocolKind::ExpressibleByNilLiteral);
// For type-sugar reasons, prefer the spelling of the default literal
// type.
if (auto defaultType = TypeChecker::getDefaultType(protocol, dc)) {
if (defaultType->isEqual(type))
type = defaultType;
}
DeclName initName(ctx, DeclBaseName::createConstructor(),
{ctx.Id_nilLiteral});
return convertLiteralInPlace(expr, type, protocol,
Identifier(), initName,
nullptr,
Identifier(),
diag::nil_literal_broken_proto,
diag::nil_literal_broken_proto);
}
Expr *visitIntegerLiteralExpr(IntegerLiteralExpr *expr) {
return handleIntegerLiteralExpr(expr);
}
Expr *visitFloatLiteralExpr(FloatLiteralExpr *expr) {
// If the literal has been assigned a builtin float type,
// don't mess with it.
if (cs.getType(expr)->is<BuiltinFloatType>())
return expr;
auto &ctx = cs.getASTContext();
ProtocolDecl *protocol = TypeChecker::getProtocol(
cs.getASTContext(), expr->getLoc(),
KnownProtocolKind::ExpressibleByFloatLiteral);
ProtocolDecl *builtinProtocol = TypeChecker::getProtocol(
cs.getASTContext(), expr->getLoc(),
KnownProtocolKind::ExpressibleByBuiltinFloatLiteral);
// For type-sugar reasons, prefer the spelling of the default literal
// type.
auto type = simplifyType(cs.getType(expr));
if (auto defaultType = TypeChecker::getDefaultType(protocol, dc)) {
if (defaultType->isEqual(type))
type = defaultType;
}
// Get the _MaxBuiltinFloatType decl, or look for it if it's not cached.
auto maxFloatTypeDecl = ctx.get_MaxBuiltinFloatTypeDecl();
// Presence of this declaration has been validated in CSGen.
assert(maxFloatTypeDecl);
auto maxType = maxFloatTypeDecl->getUnderlyingType();
DeclName initName(ctx, DeclBaseName::createConstructor(),
{ctx.Id_floatLiteral});
DeclName builtinInitName(ctx, DeclBaseName::createConstructor(),
{ctx.Id_builtinFloatLiteral});
expr->setBuiltinType(maxType);
return convertLiteralInPlace(
expr, type, protocol, ctx.Id_FloatLiteralType, initName,
builtinProtocol, builtinInitName, diag::float_literal_broken_proto,
diag::builtin_float_literal_broken_proto);
}
Expr *visitBooleanLiteralExpr(BooleanLiteralExpr *expr) {
if (cs.getType(expr) && cs.getType(expr)->is<BuiltinIntegerType>())
return expr;
auto &ctx = cs.getASTContext();
ProtocolDecl *protocol = TypeChecker::getProtocol(
cs.getASTContext(), expr->getLoc(),
KnownProtocolKind::ExpressibleByBooleanLiteral);
ProtocolDecl *builtinProtocol = TypeChecker::getProtocol(
cs.getASTContext(), expr->getLoc(),
KnownProtocolKind::ExpressibleByBuiltinBooleanLiteral);
if (!protocol || !builtinProtocol)
return nullptr;
auto type = simplifyType(cs.getType(expr));
DeclName initName(ctx, DeclBaseName::createConstructor(),
{ctx.Id_booleanLiteral});
DeclName builtinInitName(ctx, DeclBaseName::createConstructor(),
{ctx.Id_builtinBooleanLiteral});
return convertLiteralInPlace(
expr, type, protocol, ctx.Id_BooleanLiteralType, initName,
builtinProtocol, builtinInitName, diag::boolean_literal_broken_proto,
diag::builtin_boolean_literal_broken_proto);
}
Expr *handleStringLiteralExpr(LiteralExpr *expr) {
auto stringLiteral = dyn_cast<StringLiteralExpr>(expr);
auto magicLiteral = dyn_cast<MagicIdentifierLiteralExpr>(expr);
assert(bool(stringLiteral) != bool(magicLiteral) &&
"literal must be either a string literal or a magic literal");
auto type = simplifyType(cs.getType(expr));
auto &ctx = cs.getASTContext();
bool isStringLiteral = true;
bool isGraphemeClusterLiteral = false;
ProtocolDecl *protocol = TypeChecker::getProtocol(
ctx, expr->getLoc(), KnownProtocolKind::ExpressibleByStringLiteral);
if (!TypeChecker::conformsToProtocol(type, protocol, cs.DC)) {
// If the type does not conform to ExpressibleByStringLiteral, it should
// be ExpressibleByExtendedGraphemeClusterLiteral.
protocol = TypeChecker::getProtocol(
cs.getASTContext(), expr->getLoc(),
KnownProtocolKind::ExpressibleByExtendedGraphemeClusterLiteral);
isStringLiteral = false;
isGraphemeClusterLiteral = true;
}
if (!TypeChecker::conformsToProtocol(type, protocol, cs.DC)) {
// ... or it should be ExpressibleByUnicodeScalarLiteral.
protocol = TypeChecker::getProtocol(
cs.getASTContext(), expr->getLoc(),
KnownProtocolKind::ExpressibleByUnicodeScalarLiteral);
isStringLiteral = false;
isGraphemeClusterLiteral = false;
}
// For type-sugar reasons, prefer the spelling of the default literal
// type.
if (auto defaultType = TypeChecker::getDefaultType(protocol, dc)) {
if (defaultType->isEqual(type))
type = defaultType;
}
ProtocolDecl *builtinProtocol;
Identifier literalType;
DeclName literalFuncName;
DeclName builtinLiteralFuncName;
Diag<> brokenProtocolDiag;
Diag<> brokenBuiltinProtocolDiag;
if (isStringLiteral) {
literalType = ctx.Id_StringLiteralType;
literalFuncName = DeclName(ctx, DeclBaseName::createConstructor(),
{ctx.Id_stringLiteral});
builtinProtocol = TypeChecker::getProtocol(
cs.getASTContext(), expr->getLoc(),
KnownProtocolKind::ExpressibleByBuiltinStringLiteral);
builtinLiteralFuncName =
DeclName(ctx, DeclBaseName::createConstructor(),
{ctx.Id_builtinStringLiteral,
ctx.getIdentifier("utf8CodeUnitCount"),
ctx.getIdentifier("isASCII")});
if (stringLiteral)
stringLiteral->setEncoding(StringLiteralExpr::UTF8);
else
magicLiteral->setStringEncoding(StringLiteralExpr::UTF8);
brokenProtocolDiag = diag::string_literal_broken_proto;
brokenBuiltinProtocolDiag = diag::builtin_string_literal_broken_proto;
} else if (isGraphemeClusterLiteral) {
literalType = ctx.Id_ExtendedGraphemeClusterLiteralType;
literalFuncName = DeclName(ctx, DeclBaseName::createConstructor(),
{ctx.Id_extendedGraphemeClusterLiteral});
builtinLiteralFuncName =
DeclName(ctx, DeclBaseName::createConstructor(),
{ctx.Id_builtinExtendedGraphemeClusterLiteral,
ctx.getIdentifier("utf8CodeUnitCount"),
ctx.getIdentifier("isASCII")});
builtinProtocol = TypeChecker::getProtocol(
cs.getASTContext(), expr->getLoc(),
KnownProtocolKind::
ExpressibleByBuiltinExtendedGraphemeClusterLiteral);
brokenProtocolDiag =
diag::extended_grapheme_cluster_literal_broken_proto;
brokenBuiltinProtocolDiag =
diag::builtin_extended_grapheme_cluster_literal_broken_proto;
} else {
// Otherwise, we should have just one Unicode scalar.
literalType = ctx.Id_UnicodeScalarLiteralType;
literalFuncName = DeclName(ctx, DeclBaseName::createConstructor(),
{ctx.Id_unicodeScalarLiteral});
builtinLiteralFuncName =
DeclName(ctx, DeclBaseName::createConstructor(),
{ctx.Id_builtinUnicodeScalarLiteral});
builtinProtocol = TypeChecker::getProtocol(
cs.getASTContext(), expr->getLoc(),
KnownProtocolKind::ExpressibleByBuiltinUnicodeScalarLiteral);
brokenProtocolDiag = diag::unicode_scalar_literal_broken_proto;
brokenBuiltinProtocolDiag =
diag::builtin_unicode_scalar_literal_broken_proto;
stringLiteral->setEncoding(StringLiteralExpr::OneUnicodeScalar);
}
return convertLiteralInPlace(expr,
type,
protocol,
literalType,
literalFuncName,
builtinProtocol,
builtinLiteralFuncName,
brokenProtocolDiag,
brokenBuiltinProtocolDiag);
}
Expr *visitStringLiteralExpr(StringLiteralExpr *expr) {
return handleStringLiteralExpr(expr);
}
Expr *
visitInterpolatedStringLiteralExpr(InterpolatedStringLiteralExpr *expr) {
// Figure out the string type we're converting to.
auto openedType = cs.getType(expr);
auto type = simplifyType(openedType);
cs.setType(expr, type);
auto &ctx = cs.getASTContext();
auto loc = expr->getStartLoc();
auto fetchProtocolInitWitness =
[&](KnownProtocolKind protocolKind, Type type,
ArrayRef<Identifier> argLabels) -> ConcreteDeclRef {
auto proto = TypeChecker::getProtocol(ctx, loc, protocolKind);
assert(proto && "Missing string interpolation protocol?");
auto conformance =
TypeChecker::conformsToProtocol(type, proto, cs.DC);
assert(conformance && "string interpolation type conforms to protocol");
DeclName constrName(ctx, DeclBaseName::createConstructor(), argLabels);
ConcreteDeclRef witness =
conformance.getWitnessByName(type->getRValueType(), constrName);
if (!witness || !isa<AbstractFunctionDecl>(witness.getDecl()))
return nullptr;
return witness;
};
auto *interpolationProto = TypeChecker::getProtocol(
cs.getASTContext(), expr->getLoc(),
KnownProtocolKind::ExpressibleByStringInterpolation);
auto associatedTypeDecl =
interpolationProto->getAssociatedType(ctx.Id_StringInterpolation);
if (associatedTypeDecl == nullptr) {
ctx.Diags.diagnose(expr->getStartLoc(),
diag::interpolation_broken_proto);
return nullptr;
}
auto interpolationType =
simplifyType(DependentMemberType::get(openedType, associatedTypeDecl));
// Fetch needed witnesses.
ConcreteDeclRef builderInit = fetchProtocolInitWitness(
KnownProtocolKind::StringInterpolationProtocol, interpolationType,
{ctx.Id_literalCapacity, ctx.Id_interpolationCount});
if (!builderInit) return nullptr;
expr->setBuilderInit(builderInit);
ConcreteDeclRef resultInit = fetchProtocolInitWitness(
KnownProtocolKind::ExpressibleByStringInterpolation, type,
{ctx.Id_stringInterpolation});
if (!resultInit) return nullptr;
expr->setInitializer(resultInit);
// Make the integer literals for the parameters.
auto buildExprFromUnsigned = [&](unsigned value) {
LiteralExpr *expr = IntegerLiteralExpr::createFromUnsigned(ctx, value);
cs.setType(expr, ctx.getIntDecl()->getDeclaredInterfaceType());
return handleIntegerLiteralExpr(expr);
};
expr->setLiteralCapacityExpr(
buildExprFromUnsigned(expr->getLiteralCapacity()));
expr->setInterpolationCountExpr(
buildExprFromUnsigned(expr->getInterpolationCount()));
// This OpaqueValueExpr represents the result of builderInit above in
// silgen.
OpaqueValueExpr *interpolationExpr =
new (ctx) OpaqueValueExpr(expr->getSourceRange(), interpolationType);
cs.setType(interpolationExpr, interpolationType);
expr->setInterpolationExpr(interpolationExpr);
auto appendingExpr = expr->getAppendingExpr();
appendingExpr->setSubExpr(interpolationExpr);
return expr;
}
Expr *visitMagicIdentifierLiteralExpr(MagicIdentifierLiteralExpr *expr) {
switch (expr->getKind()) {
#define MAGIC_STRING_IDENTIFIER(NAME, STRING, SYNTAX_KIND) \
case MagicIdentifierLiteralExpr::NAME: \
return handleStringLiteralExpr(expr);
#define MAGIC_INT_IDENTIFIER(NAME, STRING, SYNTAX_KIND) \
case MagicIdentifierLiteralExpr::NAME: \
return handleIntegerLiteralExpr(expr);
#define MAGIC_POINTER_IDENTIFIER(NAME, STRING, SYNTAX_KIND) \
case MagicIdentifierLiteralExpr::NAME: \
return expr;
#include "swift/AST/MagicIdentifierKinds.def"
}
llvm_unreachable("Unhandled MagicIdentifierLiteralExpr in switch.");
}
Expr *visitObjectLiteralExpr(ObjectLiteralExpr *expr) {
if (cs.getType(expr) && !cs.getType(expr)->hasTypeVariable())
return expr;
// Figure out the type we're converting to.
auto openedType = cs.getType(expr);
auto type = simplifyType(openedType);
cs.setType(expr, type);
if (type->is<UnresolvedType>())
return expr;
auto &ctx = cs.getASTContext();
Type conformingType = type;
if (auto baseType = conformingType->getOptionalObjectType()) {
// The type may be optional due to a failable initializer in the
// protocol.
conformingType = baseType;
}
// Find the appropriate object literal protocol.
auto proto = TypeChecker::getLiteralProtocol(ctx, expr);
assert(proto && "Missing object literal protocol?");
auto conformance =
TypeChecker::conformsToProtocol(conformingType, proto, cs.DC);
assert(conformance && "object literal type conforms to protocol");
auto constrName = TypeChecker::getObjectLiteralConstructorName(ctx, expr);
ConcreteDeclRef witness = conformance.getWitnessByName(
conformingType->getRValueType(), constrName);
auto selectedOverload = solution.getOverloadChoiceIfAvailable(
cs.getConstraintLocator(expr, ConstraintLocator::ConstructorMember));
if (!selectedOverload)
return nullptr;
auto fnType =
simplifyType(selectedOverload->openedType)->castTo<FunctionType>();
auto newArg = coerceCallArguments(
expr->getArg(), fnType, witness,
/*applyExpr=*/nullptr, expr->getArgumentLabels(),
cs.getConstraintLocator(expr, ConstraintLocator::ApplyArgument));
expr->setInitializer(witness);
expr->setArg(newArg);
return expr;
}
// Add a forced unwrap of an expression which either has type Optional<T>
// or is a function that returns an Optional<T>. The latter turns into a
// conversion expression that we will hoist above the ApplyExpr
// that needs to be forced during the process of rewriting the expression.
//
// forForcedOptional is used to indicate that we will further need
// to hoist this result above an explicit force of an optional that is
// in place for something like an @optional protocol member from
// Objective C that we might otherwise mistake for the thing we mean to
// force here.
Expr *forceUnwrapResult(Expr *expr, bool forForcedOptional =false) {
auto ty = simplifyType(cs.getType(expr));
if (forForcedOptional)
ty = ty->getOptionalObjectType();
if (auto *fnTy = ty->getAs<AnyFunctionType>()) {
auto underlyingType = cs.replaceFinalResultTypeWithUnderlying(fnTy);
auto &ctx = cs.getASTContext();
return cs.cacheType(new (ctx) ImplicitlyUnwrappedFunctionConversionExpr(
expr, underlyingType));
} else {
return coerceImplicitlyUnwrappedOptionalToValue(
expr, ty->getWithoutSpecifierType()->getOptionalObjectType());
}
}
bool shouldForceUnwrapResult(OverloadChoice choice,
ConstraintLocatorBuilder locator) {
if (!choice.isImplicitlyUnwrappedValueOrReturnValue())
return false;
auto *choiceLocator = cs.getConstraintLocator(locator.withPathElement(
ConstraintLocator::ImplicitlyUnwrappedDisjunctionChoice));
return solution.getDisjunctionChoice(choiceLocator);
}
Expr *forceUnwrapIfExpected(Expr *expr, OverloadChoice choice,
ConstraintLocatorBuilder locator,
bool forForcedOptional = false) {
if (!shouldForceUnwrapResult(choice, locator))
return expr;
// Force the expression if required for the solution.
return forceUnwrapResult(expr, forForcedOptional);
}
Expr *visitDeclRefExpr(DeclRefExpr *expr) {
auto locator = cs.getConstraintLocator(expr);
// Find the overload choice used for this declaration reference.
auto selected = solution.getOverloadChoice(locator);
return buildDeclRef(selected, expr->getNameLoc(), locator,
expr->isImplicit());
}
Expr *visitSuperRefExpr(SuperRefExpr *expr) {
simplifyExprType(expr);
return expr;
}
Expr *visitTypeExpr(TypeExpr *expr) {
auto toType = simplifyType(cs.getType(expr));
assert(toType->is<MetatypeType>());
cs.setType(expr, toType);
return expr;
}
Expr *visitOtherConstructorDeclRefExpr(OtherConstructorDeclRefExpr *expr) {
cs.setType(expr, expr->getDecl()->getInitializerInterfaceType());
return expr;
}
Expr *visitDotSyntaxBaseIgnoredExpr(DotSyntaxBaseIgnoredExpr *expr) {
return simplifyExprType(expr);
}
Expr *visitOverloadedDeclRefExpr(OverloadedDeclRefExpr *expr) {
// Determine the declaration selected for this overloaded reference.
auto locator = cs.getConstraintLocator(expr);
auto selected = solution.getOverloadChoice(locator);
return buildDeclRef(selected, expr->getNameLoc(), locator,
expr->isImplicit());
}
Expr *visitUnresolvedDeclRefExpr(UnresolvedDeclRefExpr *expr) {
// FIXME: We should have generated an overload set from this, in which
// case we can emit a typo-correction error here but recover well.
return nullptr;
}
Expr *visitUnresolvedSpecializeExpr(UnresolvedSpecializeExpr *expr) {
// Our specializations should have resolved the subexpr to the right type.
return expr->getSubExpr();
}
Expr *visitMemberRefExpr(MemberRefExpr *expr) {
auto memberLocator = cs.getConstraintLocator(expr,
ConstraintLocator::Member);
auto selected = solution.getOverloadChoice(memberLocator);
return buildMemberRef(
expr->getBase(), expr->getDotLoc(), selected, expr->getNameLoc(),
cs.getConstraintLocator(expr), memberLocator, expr->isImplicit(),
expr->getAccessSemantics());
}
Expr *visitDynamicMemberRefExpr(DynamicMemberRefExpr *expr) {
llvm_unreachable("already type-checked?");
}
Expr *visitUnresolvedMemberExpr(UnresolvedMemberExpr *expr) {
// If constraint solving resolved this to an UnresolvedType, then we're in
// an ambiguity tolerant mode used for diagnostic generation. Just leave
// this as an unresolved member reference.
Type resultTy = simplifyType(cs.getType(expr));
if (resultTy->hasUnresolvedType()) {
cs.setType(expr, resultTy);
return expr;
}
auto &ctx = cs.getASTContext();
// Find the selected member and base type.
auto memberLocator = cs.getConstraintLocator(
expr, ConstraintLocator::UnresolvedMember);
auto selected = solution.getOverloadChoice(memberLocator);
// Unresolved member lookup always happens in a metatype so dig out the
// instance type.
auto baseTy = selected.choice.getBaseType()->getMetatypeInstanceType();
baseTy = simplifyType(baseTy);
// The base expression is simply the metatype of the base type.
// FIXME: This location info is bogus.
auto base = TypeExpr::createImplicitHack(expr->getDotLoc(), baseTy, ctx);
cs.cacheExprTypes(base);
// Build the member reference.
auto *exprLoc = cs.getConstraintLocator(expr);
auto result = buildMemberRef(
base, expr->getDotLoc(), selected, expr->getNameLoc(), exprLoc,
memberLocator, expr->isImplicit(), AccessSemantics::Ordinary);
if (!result)
return nullptr;
return coerceToType(result, resultTy, cs.getConstraintLocator(expr));
}
private:
/// A list of "suspicious" optional injections that come from
/// forced downcasts.
SmallVector<InjectIntoOptionalExpr *, 4> SuspiciousOptionalInjections;
/// Create a member reference to the given constructor.
Expr *applyCtorRefExpr(Expr *expr, Expr *base, SourceLoc dotLoc,
DeclNameLoc nameLoc, bool implicit,
ConstraintLocator *ctorLocator,
SelectedOverload overload) {
auto choice = overload.choice;
assert(choice.getKind() != OverloadChoiceKind::DeclViaDynamic);
auto *ctor = cast<ConstructorDecl>(choice.getDecl());
// If the subexpression is a metatype, build a direct reference to the
// constructor.
if (cs.getType(base)->is<AnyMetatypeType>()) {
return buildMemberRef(
base, dotLoc, overload, nameLoc, cs.getConstraintLocator(expr),
ctorLocator, implicit, AccessSemantics::Ordinary);
}
// The subexpression must be either 'self' or 'super'.
if (!base->isSuperExpr()) {
// 'super' references have already been fully checked; handle the
// 'self' case below.
auto &de = cs.getASTContext().Diags;
bool diagnoseBadInitRef = true;
auto arg = base->getSemanticsProvidingExpr();
if (auto dre = dyn_cast<DeclRefExpr>(arg)) {
if (dre->getDecl()->getName() == cs.getASTContext().Id_self) {
// We have a reference to 'self'.
diagnoseBadInitRef = false;
// Make sure the reference to 'self' occurs within an initializer.
if (!dyn_cast_or_null<ConstructorDecl>(
cs.DC->getInnermostMethodContext())) {
if (!SuppressDiagnostics)
de.diagnose(dotLoc, diag::init_delegation_outside_initializer);
return nullptr;
}
}
}
// If we need to diagnose this as a bad reference to an initializer,
// do so now.
if (diagnoseBadInitRef) {
// Determine whether 'super' would have made sense as a base.
bool hasSuper = false;
if (auto func = cs.DC->getInnermostMethodContext()) {
if (auto classDecl = func->getDeclContext()->getSelfClassDecl()) {
hasSuper = classDecl->hasSuperclass();
}
}
if (SuppressDiagnostics)
return nullptr;
de.diagnose(dotLoc, diag::bad_init_ref_base, hasSuper);
}
}
// Build a partial application of the delegated initializer.
auto callee = resolveConcreteDeclRef(ctor, ctorLocator);
Expr *ctorRef = buildOtherConstructorRef(overload.openedFullType, callee,
base, nameLoc, ctorLocator,
implicit);
auto *call = new (cs.getASTContext()) DotSyntaxCallExpr(ctorRef, dotLoc,
base);
return finishApply(call, cs.getType(expr), cs.getConstraintLocator(expr),
ctorLocator);
}
/// Give the deprecation warning for referring to a global function
/// when there's a method from a conditional conformance in a smaller/closer
/// scope.
void
diagnoseDeprecatedConditionalConformanceOuterAccess(UnresolvedDotExpr *UDE,
ValueDecl *choice) {
auto getBaseName = [](DeclContext *context) -> DeclName {
if (auto generic = context->getSelfNominalTypeDecl()) {
return generic->getName();
} else if (context->isModuleScopeContext())
return context->getParentModule()->getName();
else
llvm_unreachable("Unsupported base");
};
auto result =
TypeChecker::lookupUnqualified(cs.DC, UDE->getName(), UDE->getLoc());
assert(result && "names can't just disappear");
// These should all come from the same place.
auto exampleInner = result.front();
auto innerChoice = exampleInner.getValueDecl();
auto innerDC = exampleInner.getDeclContext()->getInnermostTypeContext();
auto innerParentDecl = innerDC->getSelfNominalTypeDecl();
auto innerBaseName = getBaseName(innerDC);
auto choiceKind = choice->getDescriptiveKind();
auto choiceDC = choice->getDeclContext();
auto choiceBaseName = getBaseName(choiceDC);
auto choiceParentDecl = choiceDC->getAsDecl();
auto choiceParentKind = choiceParentDecl
? choiceParentDecl->getDescriptiveKind()
: DescriptiveDeclKind::Module;
auto &DE = cs.getASTContext().Diags;
DE.diagnose(UDE->getLoc(),
diag::warn_deprecated_conditional_conformance_outer_access,
UDE->getName(), choiceKind, choiceParentKind, choiceBaseName,
innerChoice->getDescriptiveKind(),
innerParentDecl->getDescriptiveKind(), innerBaseName);
auto name = choiceBaseName.getBaseIdentifier();
SmallString<32> namePlusDot = name.str();
namePlusDot.push_back('.');
DE.diagnose(UDE->getLoc(),
diag::fix_deprecated_conditional_conformance_outer_access,
namePlusDot, choiceKind, name)
.fixItInsert(UDE->getStartLoc(), namePlusDot);
}
Expr *applyMemberRefExpr(Expr *expr, Expr *base, SourceLoc dotLoc,
DeclNameLoc nameLoc, bool implicit) {
// If we have a constructor member, handle it as a constructor.
auto ctorLocator = cs.getConstraintLocator(
expr,
ConstraintLocator::ConstructorMember);
if (auto selected = solution.getOverloadChoiceIfAvailable(ctorLocator)) {
return applyCtorRefExpr(
expr, base, dotLoc, nameLoc, implicit, ctorLocator, *selected);
}
// Determine the declaration selected for this overloaded reference.
auto memberLocator = cs.getConstraintLocator(expr,
ConstraintLocator::Member);
auto selectedElt = solution.getOverloadChoiceIfAvailable(memberLocator);
if (!selectedElt) {
// If constraint solving resolved this to an UnresolvedType, then we're
// in an ambiguity tolerant mode used for diagnostic generation. Just
// leave this as whatever type of member reference it already is.
Type resultTy = simplifyType(cs.getType(expr));
cs.setType(expr, resultTy);
return expr;
}
auto selected = *selectedElt;
if (!selected.choice.getBaseType()) {
// This is one of the "outer alternatives", meaning the innermost
// methods didn't work out.
//
// The only way to get here is via an UnresolvedDotExpr with outer
// alternatives.
auto UDE = cast<UnresolvedDotExpr>(expr);
diagnoseDeprecatedConditionalConformanceOuterAccess(
UDE, selected.choice.getDecl());
return buildDeclRef(selected, nameLoc, memberLocator, implicit);
}
switch (selected.choice.getKind()) {
case OverloadChoiceKind::DeclViaBridge: {
base = cs.coerceToRValue(base);
// Look through an implicitly unwrapped optional.
auto baseTy = cs.getType(base);
auto &ctx = cs.getASTContext();
auto baseMetaTy = baseTy->getAs<MetatypeType>();
auto baseInstTy = (baseMetaTy ? baseMetaTy->getInstanceType() : baseTy);
auto classTy = ctx.getBridgedToObjC(cs.DC, baseInstTy);
if (baseMetaTy) {
// FIXME: We're dropping side effects in the base here!
base = TypeExpr::createImplicitHack(base->getLoc(), classTy, ctx);
cs.cacheExprTypes(base);
} else {
// Bridge the base to its corresponding Objective-C object.
base = bridgeToObjectiveC(base, classTy);
}
// Fall through to build the member reference.
LLVM_FALLTHROUGH;
}
case OverloadChoiceKind::Decl:
case OverloadChoiceKind::DeclViaUnwrappedOptional:
case OverloadChoiceKind::DeclViaDynamic:
return buildMemberRef(base, dotLoc, selected, nameLoc,
cs.getConstraintLocator(expr), memberLocator,
implicit, AccessSemantics::Ordinary);
case OverloadChoiceKind::TupleIndex: {
Type toType = simplifyType(cs.getType(expr));
auto baseTy = cs.getType(base);
// If the base type is not a tuple l-value, access to
// its elements supposed to be r-value as well.
//
// This is modeled in constraint system in a way
// that when member type is resolved by `resolveOverload`
// it would take r-value type of the element at
// specified index, but if it's a type variable it
// could still be bound to l-value later.
if (!baseTy->is<LValueType>())
toType = toType->getRValueType();
// If the result type is an rvalue and the base contains lvalues,
// need a full tuple coercion to properly load & set access kind
// on all underlying elements before taking a single element.
if (!toType->hasLValueType() && baseTy->hasLValueType())
base = coerceToType(base, baseTy->getRValueType(),
cs.getConstraintLocator(base));
return cs.cacheType(new (cs.getASTContext())
TupleElementExpr(base, dotLoc,
selected.choice.getTupleIndex(),
nameLoc.getBaseNameLoc(), toType));
}
case OverloadChoiceKind::KeyPathApplication:
llvm_unreachable("should only happen in a subscript");
case OverloadChoiceKind::DynamicMemberLookup:
case OverloadChoiceKind::KeyPathDynamicMemberLookup: {
return buildDynamicMemberLookupRef(
expr, base, dotLoc, nameLoc.getStartLoc(), selected, memberLocator);
}
}
llvm_unreachable("Unhandled OverloadChoiceKind in switch.");
}
/// Form a type checked expression for the index of a @dynamicMemberLookup
/// subscript index parameter.
Expr *buildDynamicMemberLookupIndexExpr(StringRef name, SourceLoc loc,
Type literalTy) {
// Build and type check the string literal index value to the specific
// string type expected by the subscript.
auto &ctx = cs.getASTContext();
auto *nameExpr = new (ctx) StringLiteralExpr(name, loc, /*implicit*/true);
cs.setType(nameExpr, literalTy);
return handleStringLiteralExpr(nameExpr);
}
Expr *buildDynamicMemberLookupRef(Expr *expr, Expr *base, SourceLoc dotLoc,
SourceLoc nameLoc,
const SelectedOverload &overload,
ConstraintLocator *memberLocator) {
// Application of a DynamicMemberLookup result turns
// a member access of `x.foo` into x[dynamicMember: "foo"], or
// x[dynamicMember: KeyPath<T, U>]
auto &ctx = cs.getASTContext();
// Figure out the expected type of the lookup parameter. We know the
// openedFullType will be "xType -> indexType -> resultType". Dig out
// its index type.
auto paramTy = getTypeOfDynamicMemberIndex(overload);
Expr *argExpr = nullptr;
if (overload.choice.getKind() ==
OverloadChoiceKind::DynamicMemberLookup) {
// Build and type check the string literal index value to the specific
// string type expected by the subscript.
auto fieldName = overload.choice.getName().getBaseIdentifier().str();
argExpr = buildDynamicMemberLookupIndexExpr(fieldName, nameLoc,
paramTy);
} else {
argExpr = buildKeyPathDynamicMemberIndexExpr(
paramTy->castTo<BoundGenericType>(), dotLoc, memberLocator);
}
if (!argExpr)
return nullptr;
// Build a tuple so that the argument has a label.
auto tupleTy =
TupleType::get(TupleTypeElt(paramTy, ctx.Id_dynamicMember), ctx);
Expr *index =
TupleExpr::createImplicit(ctx, argExpr, ctx.Id_dynamicMember);
index->setType(tupleTy);
cs.cacheType(index);
// Build and return a subscript that uses this string as the index.
return buildSubscript(
base, index, ctx.Id_dynamicMember,
/*trailingClosure*/ false, cs.getConstraintLocator(expr),
/*isImplicit*/ true, AccessSemantics::Ordinary, overload);
}
Type getTypeOfDynamicMemberIndex(const SelectedOverload &overload) {
assert(overload.choice.getKind() ==
OverloadChoiceKind::DynamicMemberLookup ||
overload.choice.getKind() ==
OverloadChoiceKind::KeyPathDynamicMemberLookup);
auto declTy = solution.simplifyType(overload.openedFullType);
auto subscriptTy = declTy->castTo<FunctionType>()->getResult();
auto refFnType = subscriptTy->castTo<FunctionType>();
assert(refFnType->getParams().size() == 1 &&
"subscript always has one arg");
return refFnType->getParams()[0].getPlainType();
}
public:
Expr *visitUnresolvedDotExpr(UnresolvedDotExpr *expr) {
return applyMemberRefExpr(expr, expr->getBase(), expr->getDotLoc(),
expr->getNameLoc(), expr->isImplicit());
}
Expr *visitSequenceExpr(SequenceExpr *expr) {
llvm_unreachable("Expression wasn't parsed?");
}
Expr *visitArrowExpr(ArrowExpr *expr) {
llvm_unreachable("Arrow expr wasn't converted to type?");
}
Expr *visitIdentityExpr(IdentityExpr *expr) {
cs.setType(expr, cs.getType(expr->getSubExpr()));
return expr;
}
Expr *visitAnyTryExpr(AnyTryExpr *expr) {
cs.setType(expr, cs.getType(expr->getSubExpr()));
return expr;
}
Expr *visitOptionalTryExpr(OptionalTryExpr *expr) {
// Prior to Swift 5, 'try?' simply wraps the type of its sub-expression
// in an Optional, regardless of the sub-expression type.
//
// In Swift 5+, the type of a 'try?' expression of static type T is:
// - Equal to T if T is optional
// - Equal to T? if T is not optional
//
// The result is that in Swift 5, 'try?' avoids producing nested optionals.
if (!cs.getASTContext().LangOpts.isSwiftVersionAtLeast(5)) {
// Nothing to do for Swift 4 and earlier!
return simplifyExprType(expr);
}
Type exprType = simplifyType(cs.getType(expr));
auto subExpr = coerceToType(expr->getSubExpr(), exprType,
cs.getConstraintLocator(expr));
if (!subExpr) return nullptr;
expr->setSubExpr(subExpr);
cs.setType(expr, exprType);
return expr;
}
Expr *visitParenExpr(ParenExpr *expr) {
return simplifyExprType(expr);
}
Expr *visitUnresolvedMemberChainResultExpr(
UnresolvedMemberChainResultExpr *expr) {
// Since this expression only exists to give the result type of an
// unresolved member chain visibility in the AST, remove it from the AST
// now that we have a solution and coerce the subexpr to the resulting
// type.
auto *subExpr = expr->getSubExpr();
auto type = simplifyType(cs.getType(expr));
subExpr = coerceToType(subExpr, type, cs.getConstraintLocator(subExpr));
cs.setType(subExpr, type);
return subExpr;
}
Expr *visitTupleExpr(TupleExpr *expr) {
return simplifyExprType(expr);
}
Expr *visitSubscriptExpr(SubscriptExpr *expr) {
auto *memberLocator =
cs.getConstraintLocator(expr, ConstraintLocator::SubscriptMember);
auto overload = solution.getOverloadChoiceIfAvailable(memberLocator);
// Handles situation where there was a solution available but it didn't
// have a proper overload selected from subscript call, might be because
// solver was allowed to return free or unresolved types, which can
// happen while running diagnostics on one of the expressions.
if (!overload) {
auto *base = expr->getBase();
auto &de = cs.getASTContext().Diags;
auto baseType = cs.getType(base);
if (auto errorType = baseType->getAs<ErrorType>()) {
de.diagnose(base->getLoc(), diag::cannot_subscript_base,
errorType->getOriginalType())
.highlight(base->getSourceRange());
} else {
de.diagnose(base->getLoc(), diag::cannot_subscript_ambiguous_base)
.highlight(base->getSourceRange());
}
return nullptr;
}
if (overload->choice.getKind() ==
OverloadChoiceKind::KeyPathDynamicMemberLookup) {
return buildDynamicMemberLookupRef(
expr, expr->getBase(), expr->getIndex()->getStartLoc(), SourceLoc(),
*overload, memberLocator);
}
return buildSubscript(
expr->getBase(), expr->getIndex(), expr->getArgumentLabels(),
expr->hasTrailingClosure(), cs.getConstraintLocator(expr),
expr->isImplicit(), expr->getAccessSemantics(), *overload);
}
/// "Finish" an array expression by filling in the semantic expression.
ArrayExpr *finishArrayExpr(ArrayExpr *expr) {
Type arrayTy = cs.getType(expr);
auto &ctx = cs.getASTContext();
ProtocolDecl *arrayProto = TypeChecker::getProtocol(
ctx, expr->getLoc(), KnownProtocolKind::ExpressibleByArrayLiteral);
assert(arrayProto && "type-checked array literal w/o protocol?!");
auto conformance =
TypeChecker::conformsToProtocol(arrayTy, arrayProto, cs.DC);
assert(conformance && "Type does not conform to protocol?");
DeclName name(ctx, DeclBaseName::createConstructor(),
{ctx.Id_arrayLiteral});
ConcreteDeclRef witness =
conformance.getWitnessByName(arrayTy->getRValueType(), name);
if (!witness || !isa<AbstractFunctionDecl>(witness.getDecl()))
return nullptr;
expr->setInitializer(witness);
auto elementType = expr->getElementType();
for (auto &element : expr->getElements()) {
element = coerceToType(element, elementType,
cs.getConstraintLocator(element));
}
return expr;
}
Expr *visitArrayExpr(ArrayExpr *expr) {
Type openedType = cs.getType(expr);
Type arrayTy = simplifyType(openedType);
cs.setType(expr, arrayTy);
if (!finishArrayExpr(expr)) return nullptr;
// If the array element type was defaulted, note that in the expression.
if (solution.DefaultedConstraints.count(cs.getConstraintLocator(expr)))
expr->setIsTypeDefaulted();
return expr;
}
/// "Finish" a dictionary expression by filling in the semantic expression.
DictionaryExpr *finishDictionaryExpr(DictionaryExpr *expr) {
Type dictionaryTy = cs.getType(expr);
auto &ctx = cs.getASTContext();
ProtocolDecl *dictionaryProto = TypeChecker::getProtocol(
cs.getASTContext(), expr->getLoc(),
KnownProtocolKind::ExpressibleByDictionaryLiteral);
auto conformance =
TypeChecker::conformsToProtocol(dictionaryTy, dictionaryProto, cs.DC);
if (conformance.isInvalid())
return nullptr;
DeclName name(ctx, DeclBaseName::createConstructor(),
{ctx.Id_dictionaryLiteral});
ConcreteDeclRef witness =
conformance.getWitnessByName(dictionaryTy->getRValueType(), name);
if (!witness || !isa<AbstractFunctionDecl>(witness.getDecl()))
return nullptr;
expr->setInitializer(witness);
auto elementType = expr->getElementType();
for (auto &element : expr->getElements()) {
element = coerceToType(element, elementType,
cs.getConstraintLocator(element));
}
return expr;
}
Expr *visitDictionaryExpr(DictionaryExpr *expr) {
Type openedType = cs.getType(expr);
Type dictionaryTy = simplifyType(openedType);
cs.setType(expr, dictionaryTy);
if (!finishDictionaryExpr(expr)) return nullptr;
// If the dictionary key or value type was defaulted, note that in the
// expression.
if (solution.DefaultedConstraints.count(cs.getConstraintLocator(expr)))
expr->setIsTypeDefaulted();
return expr;
}
Expr *visitDynamicSubscriptExpr(DynamicSubscriptExpr *expr) {
auto *memberLocator =
cs.getConstraintLocator(expr, ConstraintLocator::SubscriptMember);
return buildSubscript(expr->getBase(), expr->getIndex(),
expr->getArgumentLabels(),
expr->hasTrailingClosure(),
cs.getConstraintLocator(expr),
expr->isImplicit(), AccessSemantics::Ordinary,
solution.getOverloadChoice(memberLocator));
}
Expr *visitTupleElementExpr(TupleElementExpr *expr) {
simplifyExprType(expr);
return expr;
}
Expr *visitCaptureListExpr(CaptureListExpr *expr) {
// The type of the capture list is the type of the closure contained
// inside it.
cs.setType(expr, cs.getType(expr->getClosureBody()));
return expr;
}
Expr *visitClosureExpr(ClosureExpr *expr) {
llvm_unreachable("Handled by the walker directly");
}
Expr *visitAutoClosureExpr(AutoClosureExpr *expr) {
llvm_unreachable("Already type-checked");
}
Expr *visitInOutExpr(InOutExpr *expr) {
auto objectTy = cs.getType(expr->getSubExpr())->getRValueType();
// The type is simply inout of whatever the lvalue's object type was.
cs.setType(expr, InOutType::get(objectTy));
return expr;
}
Expr *visitVarargExpansionExpr(VarargExpansionExpr *expr) {
simplifyExprType(expr);
auto arrayTy = cs.getType(expr);
expr->setSubExpr(coerceToType(expr->getSubExpr(), arrayTy,
cs.getConstraintLocator(expr)));
return expr;
}
Expr *visitDynamicTypeExpr(DynamicTypeExpr *expr) {
Expr *base = expr->getBase();
base = cs.coerceToRValue(base);
expr->setBase(base);
return simplifyExprType(expr);
}
Expr *visitOpaqueValueExpr(OpaqueValueExpr *expr) {
assert(expr->isPlaceholder() && "Already type-checked");
return expr;
}
Expr *visitPropertyWrapperValuePlaceholderExpr(
PropertyWrapperValuePlaceholderExpr *expr) {
return expr;
}
Expr *visitDefaultArgumentExpr(DefaultArgumentExpr *expr) {
llvm_unreachable("Already type-checked");
}
Expr *visitApplyExpr(ApplyExpr *expr) {
auto *calleeLoc = CalleeLocators[expr];
assert(calleeLoc);
return finishApply(expr, cs.getType(expr), cs.getConstraintLocator(expr),
calleeLoc);
}
Expr *visitRebindSelfInConstructorExpr(RebindSelfInConstructorExpr *expr) {
// A non-failable initializer cannot delegate to a failable
// initializer.
Expr *unwrappedSubExpr = expr->getSubExpr()->getSemanticsProvidingExpr();
Type valueTy = cs.getType(unwrappedSubExpr)->getOptionalObjectType();
auto inCtor = cast<ConstructorDecl>(cs.DC->getInnermostMethodContext());
if (valueTy && !inCtor->isFailable()) {
bool isChaining;
auto *otherCtorRef = expr->getCalledConstructor(isChaining);
ConstructorDecl *ctor = otherCtorRef->getDecl();
assert(ctor);
// If the initializer we're calling is not declared as
// checked, it's an error.
bool isError = !ctor->isImplicitlyUnwrappedOptional();
// If we're suppressing diagnostics, just fail.
if (isError && SuppressDiagnostics)
return nullptr;
auto &ctx = cs.getASTContext();
auto &de = cs.getASTContext().Diags;
if (isError) {
if (auto *optTry = dyn_cast<OptionalTryExpr>(unwrappedSubExpr)) {
de.diagnose(optTry->getTryLoc(),
diag::delegate_chain_nonoptional_to_optional_try,
isChaining);
de.diagnose(optTry->getTryLoc(), diag::init_delegate_force_try)
.fixItReplace({optTry->getTryLoc(), optTry->getQuestionLoc()},
"try!");
de.diagnose(inCtor->getLoc(), diag::init_propagate_failure)
.fixItInsertAfter(inCtor->getLoc(), "?");
} else {
// Give the user the option of adding '!' or making the enclosing
// initializer failable.
de.diagnose(otherCtorRef->getLoc(),
diag::delegate_chain_nonoptional_to_optional,
isChaining, ctor->getName());
de.diagnose(otherCtorRef->getLoc(), diag::init_force_unwrap)
.fixItInsertAfter(expr->getEndLoc(), "!");
de.diagnose(inCtor->getLoc(), diag::init_propagate_failure)
.fixItInsertAfter(inCtor->getLoc(), "?");
}
}
// Recover by injecting the force operation (the first option).
Expr *newSub = new (ctx) ForceValueExpr(expr->getSubExpr(),
expr->getEndLoc());
cs.setType(newSub, valueTy);
newSub->setImplicit();
expr->setSubExpr(newSub);
}
return expr;
}
Expr *visitIfExpr(IfExpr *expr) {
auto resultTy = simplifyType(cs.getType(expr));
cs.setType(expr, resultTy);
auto cond = cs.coerceToRValue(expr->getCondExpr());
expr->setCondExpr(cond);
// Coerce the then/else branches to the common type.
expr->setThenExpr(coerceToType(expr->getThenExpr(), resultTy,
cs.getConstraintLocator(expr->getThenExpr())));
expr->setElseExpr(coerceToType(expr->getElseExpr(), resultTy,
cs.getConstraintLocator(expr->getElseExpr())));
return expr;
}
Expr *visitImplicitConversionExpr(ImplicitConversionExpr *expr) {
llvm_unreachable("Already type-checked");
}
Expr *visitIsExpr(IsExpr *expr) {
// Turn the subexpression into an rvalue.
auto &ctx = cs.getASTContext();
auto sub = cs.coerceToRValue(expr->getSubExpr());
expr->setSubExpr(sub);
// Simplify and update the type we checked against.
auto *const castTypeRepr = expr->getCastTypeRepr();
const auto fromType = cs.getType(sub);
const auto toType = simplifyType(cs.getType(castTypeRepr));
expr->setCastType(toType);
cs.setType(castTypeRepr, toType);
auto castContextKind =
SuppressDiagnostics ? CheckedCastContextKind::None
: CheckedCastContextKind::IsExpr;
auto castKind = TypeChecker::typeCheckCheckedCast(
fromType, toType, castContextKind, cs.DC, expr->getLoc(), sub,
castTypeRepr->getSourceRange());
switch (castKind) {
case CheckedCastKind::Unresolved:
expr->setCastKind(CheckedCastKind::ValueCast);
break;
case CheckedCastKind::Coercion:
case CheckedCastKind::BridgingCoercion:
// Check is trivially true.
ctx.Diags.diagnose(expr->getLoc(), diag::isa_is_always_true, "is");
expr->setCastKind(castKind);
break;
case CheckedCastKind::ValueCast:
// Check the cast target is a non-foreign type
if (auto cls = toType->getAs<ClassType>()) {
if (cls->getDecl()->getForeignClassKind() ==
ClassDecl::ForeignKind::CFType) {
ctx.Diags.diagnose(expr->getLoc(), diag::isa_is_foreign_check,
toType);
}
}
expr->setCastKind(castKind);
break;
case CheckedCastKind::ArrayDowncast:
case CheckedCastKind::DictionaryDowncast:
case CheckedCastKind::SetDowncast:
// Valid checks.
expr->setCastKind(castKind);
break;
}
// SIL-generation magically turns this into a Bool; make sure it can.
if (!ctx.getBoolBuiltinInitDecl()) {
ctx.Diags.diagnose(expr->getLoc(), diag::broken_bool);
// Continue anyway.
}
// Dig through the optionals in the from/to types.
SmallVector<Type, 2> fromOptionals;
fromType->lookThroughAllOptionalTypes(fromOptionals);
SmallVector<Type, 2> toOptionals;
toType->lookThroughAllOptionalTypes(toOptionals);
// If we have an imbalance of optionals or a collection
// downcast, handle this as a checked cast followed by a
// a 'hasValue' check.
if (fromOptionals.size() != toOptionals.size() ||
castKind == CheckedCastKind::ArrayDowncast ||
castKind == CheckedCastKind::DictionaryDowncast ||
castKind == CheckedCastKind::SetDowncast) {
auto *const cast =
ConditionalCheckedCastExpr::createImplicit(ctx, sub, toType);
cast->setType(OptionalType::get(toType));
cast->setCastType(toType);
cs.setType(cast, cast->getType());
// Type-check this conditional case.
Expr *result = handleConditionalCheckedCastExpr(cast, castTypeRepr);
if (!result)
return nullptr;
// Extract a Bool from the resulting expression.
TypeChecker::requireOptionalIntrinsics(ctx, expr->getLoc());
// Match the optional value against its `Some` case.
auto *someDecl = ctx.getOptionalSomeDecl();
auto isSomeExpr =
new (ctx) EnumIsCaseExpr(result, castTypeRepr, someDecl);
auto boolDecl = ctx.getBoolDecl();
if (!boolDecl) {
ctx.Diags.diagnose(SourceLoc(), diag::broken_bool);
}
cs.setType(isSomeExpr,
boolDecl
? boolDecl->getDeclaredInterfaceType()
: Type());
return isSomeExpr;
}
return expr;
}
/// The kind of cast we're working with for handling optional bindings.
enum class OptionalBindingsCastKind {
/// An explicit bridging conversion, spelled "as".
Bridged,
/// A forced cast, spelled "as!".
Forced,
/// A conditional cast, spelled "as?".
Conditional,
};
/// Handle optional operands and results in an explicit cast.
Expr *handleOptionalBindingsForCast(ExplicitCastExpr *cast,
Type finalResultType,
OptionalBindingsCastKind castKind) {
return handleOptionalBindings(cast->getSubExpr(), finalResultType,
castKind,
[&](Expr *sub, Type resultType) -> Expr* {
// Complain about conditional casts to CF class types; they can't
// actually be conditionally checked.
if (castKind == OptionalBindingsCastKind::Conditional) {
Type destValueType = resultType->getOptionalObjectType();
auto destObjectType = destValueType;
if (auto metaTy = destObjectType->getAs<MetatypeType>())
destObjectType = metaTy->getInstanceType();
if (auto destClass = destObjectType->getClassOrBoundGenericClass()) {
if (destClass->getForeignClassKind() ==
ClassDecl::ForeignKind::CFType) {
if (SuppressDiagnostics)
return nullptr;
auto &de = cs.getASTContext().Diags;
de.diagnose(cast->getLoc(), diag::conditional_downcast_foreign,
destValueType);
ConcreteDeclRef refDecl = sub->getReferencedDecl();
if (refDecl) {
de.diagnose(cast->getLoc(),
diag::note_explicitly_compare_cftypeid,
refDecl.getDecl()->getBaseName(), destValueType);
}
}
}
}
// Set the expression as the sub-expression of the cast, then
// use the cast as the inner operation.
cast->setSubExpr(sub);
cs.setType(cast, resultType);
return cast;
});
}
/// A helper function to build an operation. The inner result type
/// is the expected type of the operation; it will be a non-optional
/// type unless the castKind is Conditional.
using OperationBuilderRef =
llvm::function_ref<Expr*(Expr *subExpr, Type innerResultType)>;
/// Handle optional operands and results in an explicit cast.
Expr *handleOptionalBindings(Expr *subExpr, Type finalResultType,
OptionalBindingsCastKind castKind,
OperationBuilderRef buildInnerOperation) {
auto &ctx = cs.getASTContext();
unsigned destExtraOptionals;
bool forceExtraSourceOptionals;
switch (castKind) {
case OptionalBindingsCastKind::Bridged:
destExtraOptionals = 0;
forceExtraSourceOptionals = true;
break;
case OptionalBindingsCastKind::Forced:
destExtraOptionals = 0;
forceExtraSourceOptionals = true;
break;
case OptionalBindingsCastKind::Conditional:
destExtraOptionals = 1;
forceExtraSourceOptionals = false;
break;
}
// FIXME: some of this work needs to be delayed until runtime to
// properly account for archetypes dynamically being optional
// types. For example, if we're casting T to NSView?, that
// should succeed if T=NSObject? and its value is actually nil.
Type srcType = cs.getType(subExpr);
SmallVector<Type, 4> srcOptionals;
srcType = srcType->lookThroughAllOptionalTypes(srcOptionals);
SmallVector<Type, 4> destOptionals;
auto destValueType
= finalResultType->lookThroughAllOptionalTypes(destOptionals);
auto isBridgeToAnyObject =
castKind == OptionalBindingsCastKind::Bridged &&
destValueType->isAnyObject();
// If the destination value type is 'AnyObject' when performing a
// bridging operation, or if the destination value type could dynamically
// be an optional type, leave any extra optionals on the source in place.
// Only apply the latter condition in Swift 5 mode to best preserve
// compatibility with Swift 4.1's casting behaviour.
if (isBridgeToAnyObject || (ctx.isSwiftVersionAtLeast(5) &&
destValueType->canDynamicallyBeOptionalType(
/*includeExistential*/ false))) {
auto destOptionalsCount = destOptionals.size() - destExtraOptionals;
if (srcOptionals.size() > destOptionalsCount) {
srcType = srcOptionals[destOptionalsCount];
srcOptionals.erase(srcOptionals.begin() + destOptionalsCount,
srcOptionals.end());
}
}
// When performing a bridging operation, if the destination type
// is more optional than the source, we'll add extra optional injections
// at the end.
SmallVector<Type, 4> destOptionalInjections;
if (castKind == OptionalBindingsCastKind::Bridged &&
destOptionals.size() > srcOptionals.size()) {
// Remove the extra optionals from destOptionals, but keep them around
// separately so we can perform the injections on the final result of
// the cast.
auto cutPoint = destOptionals.end() - srcOptionals.size();
destOptionalInjections.append(destOptionals.begin(), cutPoint);
destOptionals.erase(destOptionals.begin(), cutPoint);
finalResultType = destOptionals.empty() ? destValueType
: destOptionals.front();
}
// Local function to add the optional injections to final result.
auto addFinalOptionalInjections = [&](Expr *result) {
for (auto destType : llvm::reverse(destOptionalInjections)) {
result =
cs.cacheType(new (ctx) InjectIntoOptionalExpr(result, destType));
}
return result;
};
// There's nothing special to do if the operand isn't optional
// (or is insufficiently optional) and we don't need any bridging.
if (srcOptionals.empty()
|| (srcOptionals.size() < destOptionals.size() - destExtraOptionals)) {
Expr *result = buildInnerOperation(subExpr, finalResultType);
if (!result) return nullptr;
return addFinalOptionalInjections(result);
}
// The outermost N levels of optionals on the operand must all
// be present or the cast fails. The innermost M levels of
// optionals on the operand are reflected in the requested
// destination type, so we should map these nils into the result.
unsigned numRequiredOptionals =
srcOptionals.size() - (destOptionals.size() - destExtraOptionals);
// The number of OptionalEvaluationExprs between the point of the
// inner cast and the enclosing OptionalEvaluationExpr (exclusive)
// which represents failure for the entire operation.
unsigned failureDepth = destOptionals.size() - destExtraOptionals;
// Drill down on the operand until it's non-optional.
SourceLoc fakeQuestionLoc = subExpr->getEndLoc();
for (unsigned i : indices(srcOptionals)) {
Type valueType =
(i + 1 == srcOptionals.size() ? srcType : srcOptionals[i+1]);
// As we move into the range of mapped optionals, start
// lowering the depth.
unsigned depth = failureDepth;
if (i >= numRequiredOptionals) {
depth -= (i - numRequiredOptionals) + 1;
} else if (forceExtraSourceOptionals) {
// For a forced cast, force the required optionals.
subExpr = new (ctx) ForceValueExpr(subExpr, fakeQuestionLoc);
cs.setType(subExpr, valueType);
subExpr->setImplicit(true);
continue;
}
subExpr = cs.cacheType(new (ctx) BindOptionalExpr(
subExpr, fakeQuestionLoc, depth, valueType));
subExpr->setImplicit(true);
}
// If this is a conditional cast, the result type will always
// have at least one level of optional, which should become the
// type of the checked-cast expression.
Expr *result;
if (castKind == OptionalBindingsCastKind::Conditional) {
assert(!destOptionals.empty() &&
"result of checked cast is not an optional type");
result = buildInnerOperation(subExpr, destOptionals.back());
} else {
result = buildInnerOperation(subExpr, destValueType);
}
if (!result) return nullptr;
// If we're casting to an optional type, we need to capture the
// final M bindings.
if (destOptionals.size() > destExtraOptionals) {
if (castKind == OptionalBindingsCastKind::Conditional) {
// If the innermost cast fails, the entire expression fails. To
// get this behavior, we have to bind and then re-inject the result.
// (SILGen should know how to peephole this.)
result = cs.cacheType(new (ctx) BindOptionalExpr(
result, result->getEndLoc(), failureDepth, destValueType));
result->setImplicit(true);
}
for (unsigned i = destOptionals.size(); i != 0; --i) {
Type destType = destOptionals[i-1];
result =
cs.cacheType(new (ctx) InjectIntoOptionalExpr(result, destType));
result =
cs.cacheType(new (ctx) OptionalEvaluationExpr(result, destType));
}
// Otherwise, we just need to capture the failure-depth binding.
} else if (!forceExtraSourceOptionals) {
result = cs.cacheType(
new (ctx) OptionalEvaluationExpr(result, finalResultType));
}
return addFinalOptionalInjections(result);
}
bool hasForcedOptionalResult(ExplicitCastExpr *expr) {
const auto *const TR = expr->getCastTypeRepr();
if (TR && TR->getKind() == TypeReprKind::ImplicitlyUnwrappedOptional) {
auto *locator = cs.getConstraintLocator(
expr, ConstraintLocator::ImplicitlyUnwrappedDisjunctionChoice);
return solution.getDisjunctionChoice(locator);
}
return false;
}
Expr *visitCoerceExpr(CoerceExpr *expr) {
// If we need to insert a force-unwrap for coercions of the form
// 'as T!', do so now.
if (hasForcedOptionalResult(expr)) {
auto *coerced = visitCoerceExpr(expr, None);
if (!coerced)
return nullptr;
return coerceImplicitlyUnwrappedOptionalToValue(
coerced, cs.getType(coerced)->getOptionalObjectType());
}
return visitCoerceExpr(expr, None);
}
Expr *visitCoerceExpr(CoerceExpr *expr, Optional<unsigned> choice) {
// Simplify and update the type we're coercing to.
// SWIFT_ENABLE_TENSORFLOW
// Handle implicit `CoerceExpr` with null `TypeRepr`.
// Created by `KeyPathIterable` derived conformances.
if (expr->getCastType()) {
const auto toType = simplifyType(expr->getCastType());
expr->setCastType(toType);
} else {
assert(expr->getCastTypeRepr());
const auto toType = simplifyType(cs.getType(expr->getCastTypeRepr()));
expr->setCastType(toType);
cs.setType(expr->getCastTypeRepr(), toType);
}
const auto toType = expr->getCastType();
// SWIFT_ENABLE_TENSORFLOW END
// If this is a literal that got converted into constructor call
// lets put proper source information in place.
if (expr->isLiteralInit()) {
auto *literalInit = expr->getSubExpr();
if (auto *call = dyn_cast<CallExpr>(literalInit)) {
forEachExprInConstraintSystem(call->getFn(),
[&](Expr *subExpr) -> Expr * {
auto *TE = dyn_cast<TypeExpr>(subExpr);
if (!TE)
return subExpr;
auto type = cs.getInstanceType(TE);
assert(!type->hasError());
if (!type->isEqual(toType))
return subExpr;
return cs.cacheType(TypeExpr::createImplicitHack(
expr->getLoc(), toType, cs.getASTContext()));
});
}
if (auto *literal = dyn_cast<NumberLiteralExpr>(literalInit)) {
literal->setExplicitConversion();
} else {
literalInit->setImplicit(false);
}
cs.setType(expr, toType);
// Keep the coercion around, because it contains the source range
// for the original constructor call.
return expr;
}
// Turn the subexpression into an rvalue.
auto rvalueSub = cs.coerceToRValue(expr->getSubExpr());
expr->setSubExpr(rvalueSub);
// If we weren't explicitly told by the caller which disjunction choice,
// get it from the solution to determine whether we've picked a coercion
// or a bridging conversion.
auto *locator = cs.getConstraintLocator(expr);
if (!choice) {
choice = solution.getDisjunctionChoice(locator);
}
// Handle the coercion/bridging of the underlying subexpression, where
// optionality has been removed.
if (*choice == 0) {
// Convert the subexpression.
Expr *sub = expr->getSubExpr();
sub = solution.coerceToType(sub, toType, cs.getConstraintLocator(sub));
if (!sub)
return nullptr;
expr->setSubExpr(sub);
cs.setType(expr, toType);
return expr;
}
// Bridging conversion.
assert(*choice == 1 && "should be bridging");
// Handle optional bindings.
Expr *sub = handleOptionalBindings(expr->getSubExpr(), toType,
OptionalBindingsCastKind::Bridged,
[&](Expr *sub, Type toInstanceType) {
return buildObjCBridgeExpr(sub, toInstanceType, locator);
});
if (!sub) return nullptr;
expr->setSubExpr(sub);
cs.setType(expr, toType);
return expr;
}
// Rewrite ForcedCheckedCastExpr based on what the solver computed.
Expr *visitForcedCheckedCastExpr(ForcedCheckedCastExpr *expr) {
// The subexpression is always an rvalue.
auto &ctx = cs.getASTContext();
auto sub = cs.coerceToRValue(expr->getSubExpr());
expr->setSubExpr(sub);
// Simplify and update the type we're casting to.
auto *const castTypeRepr = expr->getCastTypeRepr();
const auto fromType = cs.getType(sub);
auto toType = simplifyType(cs.getType(castTypeRepr));
if (hasForcedOptionalResult(expr))
toType = toType->getOptionalObjectType();
expr->setCastType(toType);
cs.setType(castTypeRepr, toType);
auto castContextKind =
SuppressDiagnostics ? CheckedCastContextKind::None
: CheckedCastContextKind::ForcedCast;
const auto castKind = TypeChecker::typeCheckCheckedCast(
fromType, toType, castContextKind, cs.DC, expr->getLoc(), sub,
castTypeRepr->getSourceRange());
switch (castKind) {
/// Invalid cast.
case CheckedCastKind::Unresolved:
return nullptr;
case CheckedCastKind::Coercion:
case CheckedCastKind::BridgingCoercion: {
if (cs.getType(sub)->isEqual(toType)) {
ctx.Diags.diagnose(expr->getLoc(), diag::forced_downcast_noop, toType)
.fixItRemove(SourceRange(expr->getLoc(),
castTypeRepr->getSourceRange().End));
} else {
ctx.Diags
.diagnose(expr->getLoc(), diag::forced_downcast_coercion,
cs.getType(sub), toType)
.fixItReplace(SourceRange(expr->getLoc(), expr->getExclaimLoc()),
"as");
}
expr->setCastKind(castKind);
cs.setType(expr, toType);
return expr;
}
// Valid casts.
case CheckedCastKind::ArrayDowncast:
case CheckedCastKind::DictionaryDowncast:
case CheckedCastKind::SetDowncast:
case CheckedCastKind::ValueCast:
expr->setCastKind(castKind);
break;
}
return handleOptionalBindingsForCast(expr, simplifyType(cs.getType(expr)),
OptionalBindingsCastKind::Forced);
}
Expr *visitConditionalCheckedCastExpr(ConditionalCheckedCastExpr *expr) {
// Simplify and update the type we're casting to.
auto *const castTypeRepr = expr->getCastTypeRepr();
const auto toType = simplifyType(cs.getType(castTypeRepr));
expr->setCastType(toType);
cs.setType(castTypeRepr, toType);
// If we need to insert a force-unwrap for coercions of the form
// 'as! T!', do so now.
if (hasForcedOptionalResult(expr)) {
auto *coerced = handleConditionalCheckedCastExpr(expr, castTypeRepr);
if (!coerced)
return nullptr;
return coerceImplicitlyUnwrappedOptionalToValue(
coerced, cs.getType(coerced)->getOptionalObjectType());
}
return handleConditionalCheckedCastExpr(expr, castTypeRepr);
}
Expr *handleConditionalCheckedCastExpr(ConditionalCheckedCastExpr *expr,
TypeRepr *castTypeRepr) {
assert(castTypeRepr &&
"cast requires TypeRepr; implicit casts are superfluous");
// The subexpression is always an rvalue.
auto &ctx = cs.getASTContext();
auto sub = cs.coerceToRValue(expr->getSubExpr());
expr->setSubExpr(sub);
// Simplify and update the type we're casting to.
const auto fromType = cs.getType(sub);
const auto toType = expr->getCastType();
bool isSubExprLiteral = isa<LiteralExpr>(sub);
auto castContextKind =
(SuppressDiagnostics || expr->isImplicit() || isSubExprLiteral)
? CheckedCastContextKind::None
: CheckedCastContextKind::ConditionalCast;
auto castKind = TypeChecker::typeCheckCheckedCast(
fromType, toType, castContextKind, cs.DC, expr->getLoc(), sub,
castTypeRepr->getSourceRange());
switch (castKind) {
// Invalid cast.
case CheckedCastKind::Unresolved:
// FIXME: This literal diagnostics needs to be revisited by a proposal
// to unify casting semantics for literals.
// https://bugs.swift.org/browse/SR-12093
if (isSubExprLiteral) {
auto protocol = TypeChecker::getLiteralProtocol(ctx, sub);
// Special handle for literals conditional checked cast when they can
// be statically coerced to the cast type.
if (protocol && TypeChecker::conformsToProtocol(
toType, protocol, cs.DC)) {
ctx.Diags
.diagnose(expr->getLoc(),
diag::literal_conditional_downcast_to_coercion,
toType);
} else {
ctx.Diags
.diagnose(expr->getLoc(), diag::downcast_to_unrelated, fromType,
toType)
.highlight(sub->getSourceRange())
.highlight(castTypeRepr->getSourceRange());
}
}
expr->setCastKind(CheckedCastKind::ValueCast);
break;
case CheckedCastKind::Coercion:
case CheckedCastKind::BridgingCoercion: {
ctx.Diags.diagnose(expr->getLoc(), diag::conditional_downcast_coercion,
fromType, toType);
expr->setCastKind(castKind);
cs.setType(expr, OptionalType::get(toType));
return expr;
}
// Valid casts.
case CheckedCastKind::ArrayDowncast:
case CheckedCastKind::DictionaryDowncast:
case CheckedCastKind::SetDowncast:
case CheckedCastKind::ValueCast:
expr->setCastKind(castKind);
break;
}
return handleOptionalBindingsForCast(expr, simplifyType(cs.getType(expr)),
OptionalBindingsCastKind::Conditional);
}
Expr *visitAssignExpr(AssignExpr *expr) {
// Convert the source to the simplified destination type.
auto destTy = simplifyType(cs.getType(expr->getDest()));
auto locator =
ConstraintLocatorBuilder(cs.getConstraintLocator(expr->getSrc()));
Expr *src = coerceToType(expr->getSrc(), destTy->getRValueType(), locator);
if (!src)
return nullptr;
expr->setSrc(src);
if (!SuppressDiagnostics) {
// If we're performing an assignment to a weak or unowned variable from
// a constructor call, emit a warning that the instance will be
// immediately deallocated.
diagnoseUnownedImmediateDeallocation(cs.getASTContext(), expr);
}
return expr;
}
Expr *visitDiscardAssignmentExpr(DiscardAssignmentExpr *expr) {
return simplifyExprType(expr);
}
Expr *visitUnresolvedPatternExpr(UnresolvedPatternExpr *expr) {
// If we end up here, we should have diagnosed somewhere else
// already.
Expr *simplified = simplifyExprType(expr);
// Invalidate 'VarDecl's inside the pattern.
expr->getSubPattern()->forEachVariable([](VarDecl *VD) {
VD->setInvalid();
});
if (!SuppressDiagnostics
&& !cs.getType(simplified)->is<UnresolvedType>()) {
auto &de = cs.getASTContext().Diags;
de.diagnose(simplified->getLoc(), diag::pattern_in_expr,
expr->getSubPattern()->getKind());
}
return simplified;
}
Expr *visitBindOptionalExpr(BindOptionalExpr *expr) {
return simplifyExprType(expr);
}
Expr *visitOptionalEvaluationExpr(OptionalEvaluationExpr *expr) {
Type optType = simplifyType(cs.getType(expr));
// If this is an optional chain that isn't chaining anything, and if the
// subexpression is already optional (not IUO), then this is a noop:
// reject it. This avoids confusion of the model (where the programmer
// thought it was doing something) and keeps pointless ?'s out of the
// code.
if (!SuppressDiagnostics) {
auto &de = cs.getASTContext().Diags;
if (auto *Bind = dyn_cast<BindOptionalExpr>(
expr->getSubExpr()->getSemanticsProvidingExpr())) {
if (cs.getType(Bind->getSubExpr())->isEqual(optType)) {
de.diagnose(expr->getLoc(), diag::optional_chain_noop, optType)
.fixItRemove(Bind->getQuestionLoc());
} else {
de.diagnose(expr->getLoc(), diag::optional_chain_isnt_chaining);
}
}
}
Expr *subExpr = coerceToType(expr->getSubExpr(), optType,
cs.getConstraintLocator(expr));
if (!subExpr) return nullptr;
expr->setSubExpr(subExpr);
cs.setType(expr, optType);
return expr;
}
Expr *visitForceValueExpr(ForceValueExpr *expr) {
// Check to see if we are forcing an
// ImplicitlyUnwrappedFunctionConversionExpr. This can happen
// in cases where we had a ForceValueExpr of an optional for a
// declaration for a function whose result type we need to
// implicitly force after applying. We need to hoist the function
// conversion above the ForceValueExpr, so that we may ultimately
// hoist it above the ApplyExpr where we will eventually rewrite the
// function conversion into a force of the result.
Expr *replacement = expr;
if (auto fnConv =
dyn_cast<ImplicitlyUnwrappedFunctionConversionExpr>(expr->getSubExpr())) {
auto fnConvSubExpr = fnConv->getSubExpr();
auto fnConvSubObjTy =
cs.getType(fnConvSubExpr)->getOptionalObjectType();
cs.setType(expr, fnConvSubObjTy);
expr->setSubExpr(fnConvSubExpr);
fnConv->setSubExpr(expr);
replacement = fnConv;
}
Type valueType = simplifyType(cs.getType(expr));
cs.setType(expr, valueType);
// Coerce the object type, if necessary.
auto subExpr = expr->getSubExpr();
if (auto objectTy = cs.getType(subExpr)->getOptionalObjectType()) {
if (objectTy && !objectTy->isEqual(valueType)) {
auto coercedSubExpr = coerceToType(subExpr,
OptionalType::get(valueType),
cs.getConstraintLocator(subExpr));
expr->setSubExpr(coercedSubExpr);
}
}
return replacement;
}
Expr *visitOpenExistentialExpr(OpenExistentialExpr *expr) {
llvm_unreachable("Already type-checked");
}
Expr *visitMakeTemporarilyEscapableExpr(MakeTemporarilyEscapableExpr *expr){
llvm_unreachable("Already type-checked");
}
Expr *visitKeyPathApplicationExpr(KeyPathApplicationExpr *expr){
// This should already be type-checked, but we may have had to re-
// check it for failure diagnosis.
return simplifyExprType(expr);
}
Expr *visitEnumIsCaseExpr(EnumIsCaseExpr *expr) {
// Should already be type-checked.
return simplifyExprType(expr);
}
Expr *visitLazyInitializerExpr(LazyInitializerExpr *expr) {
llvm_unreachable("Already type-checked");
}
Expr *visitEditorPlaceholderExpr(EditorPlaceholderExpr *E) {
simplifyExprType(E);
auto valueType = cs.getType(E);
assert(!valueType->hasUnresolvedType());
auto &ctx = cs.getASTContext();
// Synthesize a call to _undefined() of appropriate type.
FuncDecl *undefinedDecl = ctx.getUndefined();
if (!undefinedDecl) {
ctx.Diags.diagnose(E->getLoc(), diag::missing_undefined_runtime);
return nullptr;
}
DeclRefExpr *fnRef = new (ctx) DeclRefExpr(undefinedDecl, DeclNameLoc(),
/*Implicit=*/true);
fnRef->setFunctionRefKind(FunctionRefKind::SingleApply);
StringRef msg = "attempt to evaluate editor placeholder";
Expr *argExpr = new (ctx) StringLiteralExpr(msg, E->getLoc(),
/*implicit*/true);
Expr *callExpr = CallExpr::createImplicit(ctx, fnRef, { argExpr },
{ Identifier() });
auto resultTy = TypeChecker::typeCheckExpression(
callExpr, cs.DC, /*contextualInfo=*/{valueType, CTP_CannotFail});
assert(resultTy && "Conversion cannot fail!");
(void)resultTy;
cs.cacheExprTypes(callExpr);
E->setSemanticExpr(callExpr);
return E;
}
Expr *visitObjCSelectorExpr(ObjCSelectorExpr *E) {
// Dig out the reference to a declaration.
Expr *subExpr = E->getSubExpr();
ValueDecl *foundDecl = nullptr;
while (subExpr) {
// Declaration reference.
if (auto declRef = dyn_cast<DeclRefExpr>(subExpr)) {
foundDecl = declRef->getDecl();
break;
}
// Constructor reference.
if (auto ctorRef = dyn_cast<OtherConstructorDeclRefExpr>(subExpr)) {
foundDecl = ctorRef->getDecl();
break;
}
// Member reference.
if (auto memberRef = dyn_cast<MemberRefExpr>(subExpr)) {
foundDecl = memberRef->getMember().getDecl();
break;
}
// Dynamic member reference.
if (auto dynMemberRef = dyn_cast<DynamicMemberRefExpr>(subExpr)) {
foundDecl = dynMemberRef->getMember().getDecl();
break;
}
// Look through parentheses.
if (auto paren = dyn_cast<ParenExpr>(subExpr)) {
subExpr = paren->getSubExpr();
continue;
}
// Look through "a.b" to "b".
if (auto dotSyntax = dyn_cast<DotSyntaxBaseIgnoredExpr>(subExpr)) {
subExpr = dotSyntax->getRHS();
continue;
}
// Look through self-rebind expression.
if (auto rebindSelf = dyn_cast<RebindSelfInConstructorExpr>(subExpr)) {
subExpr = rebindSelf->getSubExpr();
continue;
}
// Look through optional binding within the monadic "?".
if (auto bind = dyn_cast<BindOptionalExpr>(subExpr)) {
subExpr = bind->getSubExpr();
continue;
}
// Look through optional evaluation of the monadic "?".
if (auto optEval = dyn_cast<OptionalEvaluationExpr>(subExpr)) {
subExpr = optEval->getSubExpr();
continue;
}
// Look through an implicit force-value.
if (auto force = dyn_cast<ForceValueExpr>(subExpr)) {
subExpr = force->getSubExpr();
continue;
}
// Look through implicit open-existential operations.
if (auto open = dyn_cast<OpenExistentialExpr>(subExpr)) {
if (open->isImplicit()) {
subExpr = open->getSubExpr();
continue;
}
break;
}
// Look to the referenced member in a self-application.
if (auto selfApply = dyn_cast<SelfApplyExpr>(subExpr)) {
subExpr = selfApply->getFn();
continue;
}
// Look through implicit conversions.
if (auto conversion = dyn_cast<ImplicitConversionExpr>(subExpr)) {
subExpr = conversion->getSubExpr();
continue;
}
// Look through explicit coercions.
if (auto coercion = dyn_cast<CoerceExpr>(subExpr)) {
subExpr = coercion->getSubExpr();
continue;
}
break;
}
if (!subExpr) return nullptr;
// If we didn't find any declaration at all, we're stuck.
auto &de = cs.getASTContext().Diags;
if (!foundDecl) {
de.diagnose(E->getLoc(), diag::expr_selector_no_declaration)
.highlight(subExpr->getSourceRange());
return E;
}
// Check whether we found an entity that #selector could refer to.
// If we found a method or initializer, check it.
AbstractFunctionDecl *method = nullptr;
if (auto func = dyn_cast<AbstractFunctionDecl>(foundDecl)) {
// Methods and initializers.
// If this isn't a method, complain.
if (!func->getDeclContext()->isTypeContext()) {
de.diagnose(E->getLoc(), diag::expr_selector_not_method,
func->getDeclContext()->isModuleScopeContext(),
func->getName())
.highlight(subExpr->getSourceRange());
de.diagnose(func, diag::decl_declared_here, func->getName());
return E;
}
// Check that we requested a method.
switch (E->getSelectorKind()) {
case ObjCSelectorExpr::Method:
break;
case ObjCSelectorExpr::Getter:
case ObjCSelectorExpr::Setter:
// Complain that we cannot ask for the getter or setter of a
// method.
de.diagnose(E->getModifierLoc(),
diag::expr_selector_expected_property,
E->getSelectorKind() == ObjCSelectorExpr::Setter,
foundDecl->getDescriptiveKind(), foundDecl->getName())
.fixItRemoveChars(E->getModifierLoc(),
E->getSubExpr()->getStartLoc());
// Update the AST to reflect the fix.
E->overrideObjCSelectorKind(ObjCSelectorExpr::Method, SourceLoc());
break;
}
// Note the method we're referring to.
method = func;
} else if (auto var = dyn_cast<VarDecl>(foundDecl)) {
// Properties.
// If this isn't a property on a type, complain.
if (!var->getDeclContext()->isTypeContext()) {
de.diagnose(E->getLoc(), diag::expr_selector_not_property,
isa<ParamDecl>(var), var->getName())
.highlight(subExpr->getSourceRange());
de.diagnose(var, diag::decl_declared_here, var->getName());
return E;
}
// Check that we requested a property getter or setter.
switch (E->getSelectorKind()) {
case ObjCSelectorExpr::Method: {
bool isSettable = var->isSettable(cs.DC) &&
var->isSetterAccessibleFrom(cs.DC);
auto primaryDiag =
de.diagnose(E->getLoc(), diag::expr_selector_expected_method,
isSettable, var->getName());
primaryDiag.highlight(subExpr->getSourceRange());
// The point at which we will insert the modifier.
SourceLoc modifierLoc = E->getSubExpr()->getStartLoc();
// If the property is settable, we don't know whether the
// user wanted the getter or setter. Provide notes for each.
if (isSettable) {
// Flush the primary diagnostic. We have notes to add.
primaryDiag.flush();
// Add notes for the getter and setter, respectively.
de.diagnose(modifierLoc, diag::expr_selector_add_modifier, false,
var->getName())
.fixItInsert(modifierLoc, "getter: ");
de.diagnose(modifierLoc, diag::expr_selector_add_modifier, true,
var->getName())
.fixItInsert(modifierLoc, "setter: ");
// Bail out now. We don't know what the user wanted, so
// don't fill in the details.
return E;
}
// The property is non-settable, so add "getter:".
primaryDiag.fixItInsert(modifierLoc, "getter: ");
E->overrideObjCSelectorKind(ObjCSelectorExpr::Getter, modifierLoc);
method = var->getOpaqueAccessor(AccessorKind::Get);
break;
}
case ObjCSelectorExpr::Getter:
method = var->getOpaqueAccessor(AccessorKind::Get);
break;
case ObjCSelectorExpr::Setter:
// Make sure we actually have a setter.
if (!var->isSettable(cs.DC)) {
de.diagnose(E->getLoc(), diag::expr_selector_property_not_settable,
var->getDescriptiveKind(), var->getName());
de.diagnose(var, diag::decl_declared_here, var->getName());
return E;
}
// Make sure the setter is accessible.
if (!var->isSetterAccessibleFrom(cs.DC)) {
de.diagnose(E->getLoc(),
diag::expr_selector_property_setter_inaccessible,
var->getDescriptiveKind(), var->getName());
de.diagnose(var, diag::decl_declared_here, var->getName());
return E;
}
method = var->getOpaqueAccessor(AccessorKind::Set);
break;
}
} else {
// Cannot reference with #selector.
de.diagnose(E->getLoc(), diag::expr_selector_no_declaration)
.highlight(subExpr->getSourceRange());
de.diagnose(foundDecl, diag::decl_declared_here,
foundDecl->getName());
return E;
}
assert(method && "Didn't find a method?");
// The declaration we found must be exposed to Objective-C.
if (!method->isObjC()) {
// If the method declaration lies in a protocol and we're providing
// a default implementation of the method through a protocol extension
// and using it as a selector, then bail out as adding @objc to the
// protocol might not be the right thing to do and could lead to
// problems.
if (auto protocolDecl = dyn_cast<ProtocolDecl>(foundDecl->getDeclContext())) {
de.diagnose(E->getLoc(), diag::expr_selector_cannot_be_used,
foundDecl->getBaseName(), protocolDecl->getName());
return E;
}
de.diagnose(E->getLoc(), diag::expr_selector_not_objc,
foundDecl->getDescriptiveKind(), foundDecl->getName())
.highlight(subExpr->getSourceRange());
de.diagnose(foundDecl, diag::make_decl_objc,
foundDecl->getDescriptiveKind())
.fixItInsert(foundDecl->getAttributeInsertionLoc(false), "@objc ");
return E;
} else if (auto attr = foundDecl->getAttrs().getAttribute<ObjCAttr>()) {
// If this attribute was inferred based on deprecated Swift 3 rules,
// complain.
if (attr->isSwift3Inferred() &&
cs.getASTContext().LangOpts.WarnSwift3ObjCInference ==
Swift3ObjCInferenceWarnings::Minimal) {
de.diagnose(E->getLoc(), diag::expr_selector_swift3_objc_inference,
foundDecl->getDescriptiveKind(), foundDecl->getName(),
foundDecl->getDeclContext()
->getSelfNominalTypeDecl()
->getName())
.highlight(subExpr->getSourceRange());
de.diagnose(foundDecl, diag::make_decl_objc,
foundDecl->getDescriptiveKind())
.fixItInsert(foundDecl->getAttributeInsertionLoc(false),
"@objc ");
}
}
// Note which method we're referencing.
E->setMethod(method);
return E;
}
Expr *visitKeyPathExpr(KeyPathExpr *E) {
if (E->isObjC()) {
cs.setType(E, cs.getType(E->getObjCStringLiteralExpr()));
return E;
}
simplifyExprType(E);
if (cs.getType(E)->hasError())
return E;
// If a component is already resolved, then all of them should be
// resolved, and we can let the expression be. This might happen when
// re-checking a failed system for diagnostics.
if (!E->getComponents().empty()
&& E->getComponents().front().isResolved()) {
assert([&]{
for (auto &c : E->getComponents())
if (!c.isResolved())
return false;
return true;
}());
return E;
}
SmallVector<KeyPathExpr::Component, 4> resolvedComponents;
// Resolve each of the components.
bool didOptionalChain = false;
bool isFunctionType = false;
Type baseTy, leafTy;
Type exprType = cs.getType(E);
if (auto fnTy = exprType->getAs<FunctionType>()) {
baseTy = fnTy->getParams()[0].getParameterType();
leafTy = fnTy->getResult();
isFunctionType = true;
} else {
auto keyPathTy = exprType->castTo<BoundGenericType>();
baseTy = keyPathTy->getGenericArgs()[0];
leafTy = keyPathTy->getGenericArgs()[1];
}
// Track the type of the current component. Once we finish projecting
// through each component of the key path, we should reach the leafTy.
auto componentTy = baseTy;
for (unsigned i : indices(E->getComponents())) {
auto &origComponent = E->getMutableComponents()[i];
// If there were unresolved types, we may end up with a null base for
// following components.
if (!componentTy) {
resolvedComponents.push_back(origComponent);
continue;
}
auto kind = origComponent.getKind();
auto locator = cs.getConstraintLocator(
E, LocatorPathElt::KeyPathComponent(i));
// Adjust the locator such that it includes any additional elements to
// point to the component's callee, e.g a SubscriptMember for a
// subscript component.
locator = cs.getCalleeLocator(locator);
bool isDynamicMember = false;
// If this is an unresolved link, make sure we resolved it.
if (kind == KeyPathExpr::Component::Kind::UnresolvedProperty ||
kind == KeyPathExpr::Component::Kind::UnresolvedSubscript) {
auto foundDecl = solution.getOverloadChoiceIfAvailable(locator);
if (!foundDecl) {
// If we couldn't resolve the component, leave it alone.
resolvedComponents.push_back(origComponent);
componentTy = origComponent.getComponentType();
continue;
}
isDynamicMember =
foundDecl->choice.getKind() ==
OverloadChoiceKind::DynamicMemberLookup ||
foundDecl->choice.getKind() ==
OverloadChoiceKind::KeyPathDynamicMemberLookup;
// If this was a @dynamicMemberLookup property, then we actually
// form a subscript reference, so switch the kind.
if (isDynamicMember) {
kind = KeyPathExpr::Component::Kind::UnresolvedSubscript;
}
}
switch (kind) {
case KeyPathExpr::Component::Kind::UnresolvedProperty: {
buildKeyPathPropertyComponent(solution.getOverloadChoice(locator),
origComponent.getLoc(),
locator, resolvedComponents);
break;
}
case KeyPathExpr::Component::Kind::UnresolvedSubscript: {
ArrayRef<Identifier> subscriptLabels;
if (!isDynamicMember)
subscriptLabels = origComponent.getSubscriptLabels();
buildKeyPathSubscriptComponent(
solution.getOverloadChoice(locator),
origComponent.getLoc(), origComponent.getIndexExpr(),
subscriptLabels, locator, resolvedComponents);
break;
}
case KeyPathExpr::Component::Kind::OptionalChain: {
didOptionalChain = true;
// Chaining always forces the element to be an rvalue.
auto objectTy =
componentTy->getWithoutSpecifierType()->getOptionalObjectType();
if (componentTy->hasUnresolvedType() && !objectTy) {
objectTy = componentTy;
}
assert(objectTy);
auto loc = origComponent.getLoc();
resolvedComponents.push_back(
KeyPathExpr::Component::forOptionalChain(objectTy, loc));
break;
}
case KeyPathExpr::Component::Kind::OptionalForce: {
// Handle force optional when it is the first component e.g.
// \String?.!.count
if (resolvedComponents.empty()) {
auto loc = origComponent.getLoc();
auto objectTy = componentTy->getOptionalObjectType();
assert(objectTy);
resolvedComponents.push_back(
KeyPathExpr::Component::forOptionalForce(objectTy, loc));
} else {
buildKeyPathOptionalForceComponent(resolvedComponents);
}
break;
}
case KeyPathExpr::Component::Kind::Invalid: {
auto component = origComponent;
component.setComponentType(leafTy);
resolvedComponents.push_back(component);
break;
}
case KeyPathExpr::Component::Kind::Identity: {
auto component = origComponent;
component.setComponentType(componentTy);
resolvedComponents.push_back(component);
break;
}
case KeyPathExpr::Component::Kind::Property:
case KeyPathExpr::Component::Kind::Subscript:
case KeyPathExpr::Component::Kind::OptionalWrap:
case KeyPathExpr::Component::Kind::TupleElement:
llvm_unreachable("already resolved");
break;
case KeyPathExpr::Component::Kind::DictionaryKey:
llvm_unreachable("DictionaryKey only valid in #keyPath");
break;
}
// Update "componentTy" with the result type of the last component.
assert(!resolvedComponents.empty());
componentTy = resolvedComponents.back().getComponentType();
}
// Wrap a non-optional result if there was chaining involved.
if (didOptionalChain && componentTy &&
!componentTy->hasUnresolvedType() &&
!componentTy->getWithoutSpecifierType()->isEqual(leafTy)) {
assert(leafTy->getOptionalObjectType()->isEqual(
componentTy->getWithoutSpecifierType()));
auto component = KeyPathExpr::Component::forOptionalWrap(leafTy);
resolvedComponents.push_back(component);
componentTy = leafTy;
}
// Set the resolved components, and cache their types.
E->resolveComponents(cs.getASTContext(), resolvedComponents);
cs.cacheExprTypes(E);
// See whether there's an equivalent ObjC key path string we can produce
// for interop purposes.
checkAndSetObjCKeyPathString(E);
// The final component type ought to line up with the leaf type of the
// key path.
assert(!componentTy || componentTy->hasUnresolvedType()
|| componentTy->getWithoutSpecifierType()->isEqual(leafTy));
if (!isFunctionType)
return E;
// If we've gotten here, the user has used key path literal syntax to form
// a closure. The type checker has given E a function type to indicate
// this; we're going to change E's type to KeyPath<baseTy, leafTy> and
// then wrap it in a larger closure expression with the appropriate type.
// Compute KeyPath<baseTy, leafTy> and set E's type back to it.
auto kpDecl = cs.getASTContext().getKeyPathDecl();
auto keyPathTy =
BoundGenericType::get(kpDecl, nullptr, { baseTy, leafTy });
E->setType(keyPathTy);
cs.cacheType(E);
// To ensure side effects of the key path expression (mainly indices in
// subscripts) are only evaluated once, we construct an outer closure,
// which is immediately evaluated, and an inner closure, which it returns.
// The result looks like this:
//
// return "{ $kp$ in { $0[keyPath: $kp$] } }( \(E) )"
auto &ctx = cs.getASTContext();
auto discriminator = AutoClosureExpr::InvalidDiscriminator;
// The inner closure.
//
// let closure = "{ $0[keyPath: $kp$] }"
auto closureTy =
FunctionType::get({ FunctionType::Param(baseTy) }, leafTy);
auto closure = new (ctx)
AutoClosureExpr(/*set body later*/nullptr, leafTy,
discriminator, cs.DC);
auto param = new (ctx) ParamDecl(
SourceLoc(),
/*argument label*/ SourceLoc(), Identifier(),
/*parameter name*/ SourceLoc(), ctx.getIdentifier("$0"), closure);
param->setInterfaceType(baseTy->mapTypeOutOfContext());
param->setSpecifier(ParamSpecifier::Default);
// The outer closure.
//
// let outerClosure = "{ $kp$ in \(closure) }"
auto outerClosureTy =
FunctionType::get({ FunctionType::Param(keyPathTy) }, closureTy);
auto outerClosure = new (ctx)
AutoClosureExpr(/*set body later*/nullptr, closureTy,
discriminator, cs.DC);
auto outerParam =
new (ctx) ParamDecl(SourceLoc(),
/*argument label*/ SourceLoc(), Identifier(),
/*parameter name*/ SourceLoc(),
ctx.getIdentifier("$kp$"), outerClosure);
outerParam->setInterfaceType(keyPathTy->mapTypeOutOfContext());
outerParam->setSpecifier(ParamSpecifier::Default);
// let paramRef = "$0"
auto *paramRef = new (ctx)
DeclRefExpr(param, DeclNameLoc(E->getLoc()), /*Implicit=*/true);
paramRef->setType(baseTy);
cs.cacheType(paramRef);
// let outerParamRef = "$kp$"
auto outerParamRef = new (ctx)
DeclRefExpr(outerParam, DeclNameLoc(E->getLoc()), /*Implicit=*/true);
outerParamRef->setType(keyPathTy);
cs.cacheType(outerParamRef);
// let application = "\(paramRef)[keyPath: \(outerParamRef)]"
auto *application = new (ctx)
KeyPathApplicationExpr(paramRef,
E->getStartLoc(), outerParamRef, E->getEndLoc(),
leafTy, /*implicit=*/true);
cs.cacheType(application);
// Finish up the inner closure.
closure->setParameterList(ParameterList::create(ctx, {param}));
closure->setBody(application);
closure->setType(closureTy);
cs.cacheType(closure);
// Finish up the outer closure.
outerClosure->setParameterList(ParameterList::create(ctx, {outerParam}));
outerClosure->setBody(closure);
outerClosure->setType(outerClosureTy);
cs.cacheType(outerClosure);
// let outerApply = "\( outerClosure )( \(E) )"
auto outerApply = CallExpr::createImplicit(ctx, outerClosure, {E}, {});
outerApply->setType(closureTy);
cs.cacheExprTypes(outerApply);
return coerceToType(outerApply, exprType, cs.getConstraintLocator(E));
}
void buildKeyPathOptionalForceComponent(
SmallVectorImpl<KeyPathExpr::Component> &components) {
assert(!components.empty());
// Unwrap the last component type, preserving @lvalue-ness.
auto optionalTy = components.back().getComponentType();
Type objectTy;
if (auto lvalue = optionalTy->getAs<LValueType>()) {
objectTy = lvalue->getObjectType()->getOptionalObjectType();
if (optionalTy->hasUnresolvedType() && !objectTy) {
objectTy = optionalTy;
}
objectTy = LValueType::get(objectTy);
} else {
objectTy = optionalTy->getOptionalObjectType();
if (optionalTy->hasUnresolvedType() && !objectTy) {
objectTy = optionalTy;
}
}
assert(objectTy);
auto loc = components.back().getLoc();
components.push_back(
KeyPathExpr::Component::forOptionalForce(objectTy, loc));
}
void buildKeyPathPropertyComponent(
const SelectedOverload &overload, SourceLoc componentLoc,
ConstraintLocator *locator,
SmallVectorImpl<KeyPathExpr::Component> &components) {
auto resolvedTy = simplifyType(overload.openedType);
if (auto *property = overload.choice.getDeclOrNull()) {
// Key paths can only refer to properties currently.
auto varDecl = cast<VarDecl>(property);
// Key paths don't work with mutating-get properties.
assert(!varDecl->isGetterMutating());
// Key paths don't currently support static members.
// There is a fix which diagnoses such situation already.
assert(!varDecl->isStatic());
// Compute the concrete reference to the member.
auto ref = resolveConcreteDeclRef(property, locator);
components.push_back(
KeyPathExpr::Component::forProperty(ref, resolvedTy, componentLoc));
} else {
auto fieldIndex = overload.choice.getTupleIndex();
components.push_back(KeyPathExpr::Component::forTupleElement(
fieldIndex, resolvedTy, componentLoc));
}
if (shouldForceUnwrapResult(overload.choice, locator))
buildKeyPathOptionalForceComponent(components);
}
void buildKeyPathSubscriptComponent(
const SelectedOverload &overload,
SourceLoc componentLoc, Expr *indexExpr,
ArrayRef<Identifier> labels, ConstraintLocator *locator,
SmallVectorImpl<KeyPathExpr::Component> &components) {
auto subscript = cast<SubscriptDecl>(overload.choice.getDecl());
assert(!subscript->isGetterMutating());
// Compute substitutions to refer to the member.
auto ref = resolveConcreteDeclRef(subscript, locator);
// If this is a @dynamicMemberLookup reference to resolve a property
// through the subscript(dynamicMember:) member, restore the
// openedType and origComponent to its full reference as if the user
// wrote out the subscript manually.
bool forDynamicLookup =
overload.choice.getKind() ==
OverloadChoiceKind::DynamicMemberLookup ||
overload.choice.getKind() ==
OverloadChoiceKind::KeyPathDynamicMemberLookup;
if (forDynamicLookup) {
labels = cs.getASTContext().Id_dynamicMember;
auto indexType = getTypeOfDynamicMemberIndex(overload);
if (overload.choice.getKind() ==
OverloadChoiceKind::KeyPathDynamicMemberLookup) {
indexExpr = buildKeyPathDynamicMemberIndexExpr(
indexType->castTo<BoundGenericType>(), componentLoc, locator);
} else {
auto fieldName = overload.choice.getName().getBaseIdentifier().str();
indexExpr = buildDynamicMemberLookupIndexExpr(fieldName, componentLoc,
indexType);
}
}
auto subscriptType =
simplifyType(overload.openedType)->castTo<AnyFunctionType>();
auto resolvedTy = subscriptType->getResult();
// Coerce the indices to the type the subscript expects.
auto *newIndexExpr =
coerceCallArguments(indexExpr, subscriptType, ref,
/*applyExpr*/ nullptr, labels,
locator);
// We need to be able to hash the captured index values in order for
// KeyPath itself to be hashable, so check that all of the subscript
// index components are hashable and collect their conformances here.
SmallVector<ProtocolConformanceRef, 4> conformances;
auto hashable =
cs.getASTContext().getProtocol(KnownProtocolKind::Hashable);
auto fnType = overload.openedType->castTo<FunctionType>();
SmallVector<Identifier, 4> newLabels;
for (auto &param : fnType->getParams()) {
newLabels.push_back(param.getLabel());
auto indexType = simplifyType(param.getParameterType());
// Index type conformance to Hashable protocol has been
// verified by the solver, we just need to get it again
// with all of the generic parameters resolved.
auto hashableConformance =
TypeChecker::conformsToProtocol(indexType, hashable, cs.DC);
assert(hashableConformance);
conformances.push_back(hashableConformance);
}
auto comp = KeyPathExpr::Component::forSubscriptWithPrebuiltIndexExpr(
ref, newIndexExpr, cs.getASTContext().AllocateCopy(newLabels),
resolvedTy, componentLoc,
cs.getASTContext().AllocateCopy(conformances));
components.push_back(comp);
if (shouldForceUnwrapResult(overload.choice, locator))
buildKeyPathOptionalForceComponent(components);
}
Expr *visitKeyPathDotExpr(KeyPathDotExpr *E) {
llvm_unreachable("found KeyPathDotExpr in CSApply");
}
Expr *visitOneWayExpr(OneWayExpr *E) {
auto type = simplifyType(cs.getType(E));
return coerceToType(E->getSubExpr(), type, cs.getConstraintLocator(E));
}
Expr *visitTapExpr(TapExpr *E) {
auto type = simplifyType(cs.getType(E));
E->getVar()->setInterfaceType(type->mapTypeOutOfContext());
cs.setType(E, type);
E->setType(type);
return E;
}
/// Interface for ExprWalker
void walkToExprPre(Expr *expr) {
// If we have an apply, make a note of its callee locator prior to
// rewriting.
if (auto *apply = dyn_cast<ApplyExpr>(expr)) {
auto *calleeLoc = cs.getCalleeLocator(cs.getConstraintLocator(expr));
CalleeLocators[apply] = calleeLoc;
}
ExprStack.push_back(expr);
}
Expr *walkToExprPost(Expr *expr) {
Expr *result = visit(expr);
assert(expr == ExprStack.back());
ExprStack.pop_back();
return result;
}
void finalize() {
assert(ExprStack.empty());
assert(OpenedExistentials.empty());
auto &ctx = cs.getASTContext();
// Look at all of the suspicious optional injections
for (auto injection : SuspiciousOptionalInjections) {
auto *cast = findForcedDowncast(ctx, injection->getSubExpr());
if (!cast)
continue;
if (isa<ParenExpr>(injection->getSubExpr()))
continue;
ctx.Diags.diagnose(
injection->getLoc(), diag::inject_forced_downcast,
cs.getType(injection->getSubExpr())->getRValueType());
auto exclaimLoc = cast->getExclaimLoc();
ctx.Diags
.diagnose(exclaimLoc, diag::forced_to_conditional_downcast,
cs.getType(injection)->getOptionalObjectType())
.fixItReplace(exclaimLoc, "?");
ctx.Diags
.diagnose(cast->getStartLoc(), diag::silence_inject_forced_downcast)
.fixItInsert(cast->getStartLoc(), "(")
.fixItInsertAfter(cast->getEndLoc(), ")");
}
}
/// Diagnose an optional injection that is probably not what the
/// user wanted, because it comes from a forced downcast.
void diagnoseOptionalInjection(InjectIntoOptionalExpr *injection) {
// Check whether we have a forced downcast.
auto *cast =
findForcedDowncast(cs.getASTContext(), injection->getSubExpr());
if (!cast)
return;
SuspiciousOptionalInjections.push_back(injection);
}
};
} // end anonymous namespace
ConcreteDeclRef
Solution::resolveLocatorToDecl(ConstraintLocator *locator) const {
// Get the callee locator without looking through applies, ensuring we only
// return a decl for a direct reference.
auto *calleeLoc =
constraintSystem->getCalleeLocator(locator, /*lookThroughApply*/ false);
auto overload = getOverloadChoiceIfAvailable(calleeLoc);
if (!overload)
return ConcreteDeclRef();
return resolveConcreteDeclRef(overload->choice.getDeclOrNull(), locator);
}
/// Returns the concrete callee which 'owns' the default argument at a given
/// index. This looks through inheritance for inherited default args.
static ConcreteDeclRef getDefaultArgOwner(ConcreteDeclRef owner,
unsigned index) {
auto *param = getParameterAt(owner.getDecl(), index);
if (param->getDefaultArgumentKind() == DefaultArgumentKind::Inherited) {
return getDefaultArgOwner(owner.getOverriddenDecl(), index);
}
return owner;
}
static bool canPeepholeTupleConversion(Expr *expr,
ArrayRef<unsigned> sources) {
if (!isa<TupleExpr>(expr))
return false;
for (unsigned i = 0, e = sources.size(); i != e; ++i) {
if (sources[i] != i)
return false;
}
return true;
}
Expr *ExprRewriter::coerceTupleToTuple(Expr *expr,
TupleType *fromTuple,
TupleType *toTuple,
ConstraintLocatorBuilder locator,
ArrayRef<unsigned> sources) {
auto &ctx = cs.getASTContext();
// If the input expression is a tuple expression, we can convert it in-place.
if (canPeepholeTupleConversion(expr, sources)) {
auto *tupleExpr = cast<TupleExpr>(expr);
for (unsigned i = 0, e = tupleExpr->getNumElements(); i != e; ++i) {
auto *fromElt = tupleExpr->getElement(i);
// Actually convert the source element.
auto toEltType = toTuple->getElementType(i);
auto *toElt
= coerceToType(fromElt, toEltType,
locator.withPathElement(
LocatorPathElt::TupleElement(i)));
if (!toElt)
return nullptr;
tupleExpr->setElement(i, toElt);
}
tupleExpr->setType(toTuple);
cs.cacheType(tupleExpr);
return tupleExpr;
}
// Build a list of OpaqueValueExprs that matches the structure
// of expr's type.
//
// Each OpaqueValueExpr's type is equal to the type of the
// corresponding element of fromTuple.
SmallVector<OpaqueValueExpr *, 4> destructured;
for (unsigned i = 0, e = sources.size(); i != e; ++i) {
auto fromEltType = fromTuple->getElementType(i);
auto *opaqueElt =
new (ctx) OpaqueValueExpr(expr->getSourceRange(), fromEltType);
cs.cacheType(opaqueElt);
destructured.push_back(opaqueElt);
}
// Convert each OpaqueValueExpr to the correct type.
SmallVector<Expr *, 4> converted;
SmallVector<Identifier, 4> labels;
SmallVector<TupleTypeElt, 4> convertedElts;
bool anythingShuffled = false;
for (unsigned i = 0, e = sources.size(); i != e; ++i) {
unsigned source = sources[i];
auto *fromElt = destructured[source];
// Actually convert the source element.
auto toEltType = toTuple->getElementType(i);
auto toLabel = toTuple->getElement(i).getName();
// If we're shuffling positions and labels, we have to warn about this
// conversion.
if (i != sources[i] &&
fromTuple->getElement(i).getName() != toLabel)
anythingShuffled = true;
auto *toElt
= coerceToType(fromElt, toEltType,
locator.withPathElement(
LocatorPathElt::TupleElement(source)));
if (!toElt)
return nullptr;
converted.push_back(toElt);
labels.push_back(toLabel);
convertedElts.emplace_back(toEltType, toLabel, ParameterTypeFlags());
}
// Shuffling tuple elements is an anti-pattern worthy of a diagnostic. We
// will form the shuffle for now, but a future compiler should decline to
// do so and begin the process of removing them altogether.
if (anythingShuffled) {
cs.getASTContext().Diags.diagnose(
expr->getLoc(), diag::warn_reordering_tuple_shuffle_deprecated);
}
// Create the result tuple, written in terms of the destructured
// OpaqueValueExprs.
auto *result = TupleExpr::createImplicit(ctx, converted, labels);
result->setType(TupleType::get(convertedElts, ctx));
cs.cacheType(result);
// Create the tuple conversion.
return cs.cacheType(
DestructureTupleExpr::create(ctx, destructured, expr, result, toTuple));
}
static Type getMetatypeSuperclass(Type t) {
if (auto *metaTy = t->getAs<MetatypeType>())
return MetatypeType::get(getMetatypeSuperclass(
metaTy->getInstanceType()));
if (auto *metaTy = t->getAs<ExistentialMetatypeType>())
return ExistentialMetatypeType::get(getMetatypeSuperclass(
metaTy->getInstanceType()));
return t->getSuperclass();
}
Expr *ExprRewriter::coerceSuperclass(Expr *expr, Type toType) {
auto &ctx = cs.getASTContext();
auto fromType = cs.getType(expr);
auto fromInstanceType = fromType;
auto toInstanceType = toType;
while (fromInstanceType->is<AnyMetatypeType>() &&
toInstanceType->is<MetatypeType>()) {
fromInstanceType = fromInstanceType->castTo<AnyMetatypeType>()
->getInstanceType();
toInstanceType = toInstanceType->castTo<MetatypeType>()
->getInstanceType();
}
if (fromInstanceType->is<ArchetypeType>()) {
// Coercion from archetype to its (concrete) superclass.
auto superclass = getMetatypeSuperclass(fromType);
expr =
cs.cacheType(
new (ctx) ArchetypeToSuperExpr(expr, superclass));
if (!superclass->isEqual(toType))
return coerceSuperclass(expr, toType);
return expr;
}
if (fromInstanceType->isExistentialType()) {
// Coercion from superclass-constrained existential to its
// concrete superclass.
auto fromArchetype = OpenedArchetypeType::getAny(fromType);
auto *archetypeVal = cs.cacheType(new (ctx) OpaqueValueExpr(
expr->getSourceRange(), fromArchetype));
auto *result = coerceSuperclass(archetypeVal, toType);
return cs.cacheType(
new (ctx) OpenExistentialExpr(expr, archetypeVal, result,
toType));
}
// Coercion from subclass to superclass.
if (toType->is<MetatypeType>()) {
return cs.cacheType(
new (ctx) MetatypeConversionExpr(expr, toType));
}
return cs.cacheType(
new (ctx) DerivedToBaseExpr(expr, toType));
}
/// Collect the conformances for all the protocols of an existential type.
/// If the source type is also existential, we don't want to check conformance
/// because most protocols do not conform to themselves -- however we still
/// allow the conversion here, except the ErasureExpr ends up with trivial
/// conformances.
static ArrayRef<ProtocolConformanceRef>
collectExistentialConformances(Type fromType, Type toType,
DeclContext *DC) {
auto layout = toType->getExistentialLayout();
SmallVector<ProtocolConformanceRef, 4> conformances;
for (auto proto : layout.getProtocols()) {
conformances.push_back(TypeChecker::containsProtocol(
fromType, proto->getDecl(), DC));
}
return toType->getASTContext().AllocateCopy(conformances);
}
Expr *ExprRewriter::coerceExistential(Expr *expr, Type toType) {
Type fromType = cs.getType(expr);
Type fromInstanceType = fromType;
Type toInstanceType = toType;
// Look through metatypes
while ((fromInstanceType->is<UnresolvedType>() ||
fromInstanceType->is<AnyMetatypeType>()) &&
toInstanceType->is<ExistentialMetatypeType>()) {
if (!fromInstanceType->is<UnresolvedType>())
fromInstanceType = fromInstanceType->castTo<AnyMetatypeType>()->getInstanceType();
toInstanceType = toInstanceType->castTo<ExistentialMetatypeType>()->getInstanceType();
}
ASTContext &ctx = cs.getASTContext();
auto conformances =
collectExistentialConformances(fromInstanceType, toInstanceType, cs.DC);
// For existential-to-existential coercions, open the source existential.
if (fromType->isAnyExistentialType()) {
fromType = OpenedArchetypeType::getAny(fromType);
auto *archetypeVal = cs.cacheType(
new (ctx) OpaqueValueExpr(expr->getSourceRange(), fromType));
auto *result = cs.cacheType(ErasureExpr::create(ctx, archetypeVal, toType,
conformances));
return cs.cacheType(
new (ctx) OpenExistentialExpr(expr, archetypeVal, result,
cs.getType(result)));
}
// Load tuples with lvalue elements.
if (auto tupleType = fromType->getAs<TupleType>()) {
if (tupleType->hasLValueType()) {
expr = cs.coerceToRValue(expr);
}
}
return cs.cacheType(ErasureExpr::create(ctx, expr, toType, conformances));
}
/// Given that the given expression is an implicit conversion added
/// to the target by coerceToType, find out how many OptionalEvaluationExprs
/// it includes and the target.
static unsigned getOptionalEvaluationDepth(Expr *expr, Expr *target) {
unsigned depth = 0;
while (true) {
// Look through sugar expressions.
expr = expr->getSemanticsProvidingExpr();
// If we find the target expression, we're done.
if (expr == target) return depth;
// If we see an optional evaluation, the depth goes up.
if (auto optEval = dyn_cast<OptionalEvaluationExpr>(expr)) {
++depth;
expr = optEval->getSubExpr();
// We have to handle any other expressions that can be introduced by
// coerceToType.
} else if (auto bind = dyn_cast<BindOptionalExpr>(expr)) {
expr = bind->getSubExpr();
} else if (auto force = dyn_cast<ForceValueExpr>(expr)) {
expr = force->getSubExpr();
} else if (auto open = dyn_cast<OpenExistentialExpr>(expr)) {
depth += getOptionalEvaluationDepth(open->getSubExpr(),
open->getOpaqueValue());
expr = open->getExistentialValue();
// Otherwise, look through implicit conversions.
} else {
expr = cast<ImplicitConversionExpr>(expr)->getSubExpr();
}
}
}
Expr *ExprRewriter::coerceOptionalToOptional(Expr *expr, Type toType,
ConstraintLocatorBuilder locator,
Optional<Pattern*> typeFromPattern) {
auto &ctx = cs.getASTContext();
Type fromType = cs.getType(expr);
TypeChecker::requireOptionalIntrinsics(ctx, expr->getLoc());
SmallVector<Type, 4> fromOptionals;
(void)fromType->lookThroughAllOptionalTypes(fromOptionals);
SmallVector<Type, 4> toOptionals;
(void)toType->lookThroughAllOptionalTypes(toOptionals);
assert(!toOptionals.empty());
assert(!fromOptionals.empty());
// If we are adding optionals but the types are equivalent up to the common
// depth, peephole the optional-to-optional conversion into a series of nested
// injections.
auto toDepth = toOptionals.size();
auto fromDepth = fromOptionals.size();
if (toDepth > fromDepth &&
toOptionals[toOptionals.size() - fromDepth]->isEqual(fromType)) {
auto diff = toDepth - fromDepth;
while (diff--) {
Type type = toOptionals[diff];
expr = cs.cacheType(new (ctx) InjectIntoOptionalExpr(expr, type));
diagnoseOptionalInjection(cast<InjectIntoOptionalExpr>(expr));
}
return expr;
}
Type fromValueType = fromType->getOptionalObjectType();
Type toValueType = toType->getOptionalObjectType();
// The depth we use here will get patched after we apply the coercion.
auto bindOptional =
new (ctx) BindOptionalExpr(expr, expr->getSourceRange().End,
/*depth*/ 0, fromValueType);
expr = cs.cacheType(bindOptional);
expr->setImplicit(true);
expr = coerceToType(expr, toValueType, locator, typeFromPattern);
if (!expr) return nullptr;
unsigned depth = getOptionalEvaluationDepth(expr, bindOptional);
bindOptional->setDepth(depth);
expr = cs.cacheType(new (ctx) InjectIntoOptionalExpr(expr, toType));
expr = cs.cacheType(new (ctx) OptionalEvaluationExpr(expr, toType));
expr->setImplicit(true);
return expr;
}
Expr *ExprRewriter::coerceImplicitlyUnwrappedOptionalToValue(Expr *expr, Type objTy) {
auto optTy = cs.getType(expr);
// Preserve l-valueness of the result.
if (optTy->is<LValueType>())
objTy = LValueType::get(objTy);
expr = new (cs.getASTContext()) ForceValueExpr(expr, expr->getEndLoc(),
/* forcedIUO=*/ true);
cs.setType(expr, objTy);
expr->setImplicit();
return expr;
}
/// Determine whether the given expression is a reference to an
/// unbound instance member of a type.
static bool isReferenceToMetatypeMember(ConstraintSystem &cs, Expr *expr) {
expr = expr->getSemanticsProvidingExpr();
if (auto dotIgnored = dyn_cast<DotSyntaxBaseIgnoredExpr>(expr))
return cs.getType(dotIgnored->getLHS())->is<AnyMetatypeType>();
if (auto dotSyntax = dyn_cast<DotSyntaxCallExpr>(expr))
return cs.getType(dotSyntax->getBase())->is<AnyMetatypeType>();
return false;
}
static bool hasCurriedSelf(ConstraintSystem &cs, ConcreteDeclRef callee,
ApplyExpr *apply) {
// If we do not have a callee, return false.
if (!callee) {
return false;
}
// Only calls to members of types can have curried 'self'.
auto calleeDecl = callee.getDecl();
if (!calleeDecl->getDeclContext()->isTypeContext()) {
return false;
}
// Would have `self`, if we're not applying it.
if (auto *call = dyn_cast<CallExpr>(apply)) {
if (!calleeDecl->isInstanceMember() ||
!isReferenceToMetatypeMember(cs, call->getDirectCallee())) {
return true;
}
return false;
}
// Operators have curried self.
if (isa<PrefixUnaryExpr>(apply) || isa<PostfixUnaryExpr>(apply) ||
isa<BinaryExpr>(apply)) {
return true;
}
// Otherwise, we have a normal application.
return false;
}
Expr *ExprRewriter::coerceCallArguments(
Expr *arg, AnyFunctionType *funcType,
ConcreteDeclRef callee,
ApplyExpr *apply,
ArrayRef<Identifier> argLabels,
ConstraintLocatorBuilder locator) {
auto &ctx = getConstraintSystem().getASTContext();
auto params = funcType->getParams();
// Local function to produce a locator to refer to the given parameter.
auto getArgLocator =
[&](unsigned argIdx, unsigned paramIdx,
ParameterTypeFlags flags) -> ConstraintLocatorBuilder {
return locator.withPathElement(
LocatorPathElt::ApplyArgToParam(argIdx, paramIdx, flags));
};
bool matchCanFail =
llvm::any_of(params, [](const AnyFunctionType::Param &param) {
return param.getPlainType()->hasUnresolvedType();
});
// Determine whether this application has curried self.
bool skipCurriedSelf = apply ? hasCurriedSelf(cs, callee, apply) : true;
// Determine the parameter bindings.
ParameterListInfo paramInfo(params, callee.getDecl(), skipCurriedSelf);
SmallVector<AnyFunctionType::Param, 8> args;
AnyFunctionType::decomposeInput(cs.getType(arg), args);
// If this application is an init(wrappedValue:) call that needs an injected
// wrapped value placeholder, the first non-defaulted argument must be
// wrapped in an OpaqueValueExpr.
bool shouldInjectWrappedValuePlaceholder =
target->shouldInjectWrappedValuePlaceholder(apply);
auto injectWrappedValuePlaceholder =
[&](Expr *arg, bool isAutoClosure = false) -> Expr * {
auto *placeholder = PropertyWrapperValuePlaceholderExpr::create(
ctx, arg->getSourceRange(), cs.getType(arg),
target->propertyWrapperHasInitialWrappedValue() ? arg : nullptr,
isAutoClosure);
cs.cacheType(placeholder);
cs.cacheType(placeholder->getOpaqueValuePlaceholder());
shouldInjectWrappedValuePlaceholder = false;
return placeholder;
};
// Quickly test if any further fix-ups for the argument types are necessary.
if (AnyFunctionType::equalParams(args, params) &&
!shouldInjectWrappedValuePlaceholder)
return arg;
// Apply labels to arguments.
AnyFunctionType::relabelParams(args, argLabels);
MatchCallArgumentListener listener;
auto unlabeledTrailingClosureIndex =
arg->getUnlabeledTrailingClosureIndexOfPackedArgument();
// Determine the trailing closure matching rule that was applied. This
// is only relevant for explicit calls and subscripts.
auto trailingClosureMatching = TrailingClosureMatching::Forward;
{
SmallVector<LocatorPathElt, 4> path;
auto anchor = locator.getLocatorParts(path);
if (!path.empty() && path.back().is<LocatorPathElt::ApplyArgument>() &&
!anchor.isExpr(ExprKind::UnresolvedDot)) {
auto locatorPtr = cs.getConstraintLocator(locator);
assert(solution.trailingClosureMatchingChoices.count(locatorPtr) == 1);
trailingClosureMatching = solution.trailingClosureMatchingChoices.find(
locatorPtr)->second;
}
}
auto callArgumentMatch = constraints::matchCallArguments(
args, params, paramInfo, unlabeledTrailingClosureIndex,
/*allowFixes=*/false, listener, trailingClosureMatching);
assert((matchCanFail || callArgumentMatch) &&
"Call arguments did not match up?");
(void)matchCanFail;
auto parameterBindings = std::move(callArgumentMatch->parameterBindings);
// We should either have parentheses or a tuple.
auto *argTuple = dyn_cast<TupleExpr>(arg);
auto *argParen = dyn_cast<ParenExpr>(arg);
// FIXME: Eventually, we want to enforce that we have either argTuple or
// argParen here.
SourceLoc lParenLoc, rParenLoc;
if (argTuple) {
lParenLoc = argTuple->getLParenLoc();
rParenLoc = argTuple->getRParenLoc();
} else if (argParen) {
lParenLoc = argParen->getLParenLoc();
rParenLoc = argParen->getRParenLoc();
}
// Local function to extract the ith argument expression, which papers
// over some of the weirdness with tuples vs. parentheses.
auto getArg = [&](unsigned i) -> Expr * {
if (argTuple)
return argTuple->getElement(i);
assert(i == 0 && "Scalar only has a single argument");
if (argParen)
return argParen->getSubExpr();
return arg;
};
auto getLabelLoc = [&](unsigned i) -> SourceLoc {
if (argTuple)
return argTuple->getElementNameLoc(i);
assert(i == 0 && "Scalar only has a single argument");
return SourceLoc();
};
SmallVector<Expr *, 4> newArgs;
SmallVector<Identifier, 4> newLabels;
SmallVector<SourceLoc, 4> newLabelLocs;
SmallVector<AnyFunctionType::Param, 4> newParams;
for (unsigned paramIdx = 0, numParams = parameterBindings.size();
paramIdx != numParams; ++paramIdx) {
// Extract the parameter.
const auto &param = params[paramIdx];
newLabels.push_back(param.getLabel());
// Handle variadic parameters.
if (param.isVariadic()) {
assert(!param.isInOut());
SmallVector<Expr *, 4> variadicArgs;
// The first argument of this vararg parameter may have had a label;
// save its location.
auto &varargIndices = parameterBindings[paramIdx];
if (!varargIndices.empty())
newLabelLocs.push_back(getLabelLoc(varargIndices[0]));
else
newLabelLocs.push_back(SourceLoc());
// Convert the arguments.
for (auto argIdx : varargIndices) {
auto arg = getArg(argIdx);
auto argType = cs.getType(arg);
// If the argument type exactly matches, this just works.
if (argType->isEqual(param.getPlainType())) {
variadicArgs.push_back(arg);
continue;
}
// Convert the argument.
auto convertedArg = coerceToType(
arg, param.getPlainType(),
getArgLocator(argIdx, paramIdx, param.getParameterFlags()));
if (!convertedArg)
return nullptr;
// Add the converted argument.
variadicArgs.push_back(convertedArg);
}
SourceLoc start, end;
if (!variadicArgs.empty()) {
start = variadicArgs.front()->getStartLoc();
end = variadicArgs.back()->getEndLoc();
}
// Collect them into an ArrayExpr.
auto *arrayExpr = ArrayExpr::create(ctx, start, variadicArgs, {}, end,
param.getParameterType());
arrayExpr->setImplicit();
cs.cacheType(arrayExpr);
// Wrap the ArrayExpr in a VarargExpansionExpr.
auto *varargExpansionExpr = new (ctx)
VarargExpansionExpr(arrayExpr,
/*implicit=*/true, arrayExpr->getType());
cs.cacheType(varargExpansionExpr);
newArgs.push_back(varargExpansionExpr);
newParams.push_back(param);
continue;
}
// Handle default arguments.
if (parameterBindings[paramIdx].empty()) {
auto owner = getDefaultArgOwner(callee, paramIdx);
auto paramTy = param.getParameterType();
auto *defArg = new (ctx)
DefaultArgumentExpr(owner, paramIdx, arg->getStartLoc(), paramTy, dc);
cs.cacheType(defArg);
newArgs.push_back(defArg);
newParams.push_back(param);
newLabelLocs.push_back(SourceLoc());
continue;
}
// Otherwise, we have a plain old ordinary argument.
// Extract the argument used to initialize this parameter.
assert(parameterBindings[paramIdx].size() == 1);
unsigned argIdx = parameterBindings[paramIdx].front();
auto arg = getArg(argIdx);
auto argType = cs.getType(arg);
// Save the original label location.
newLabelLocs.push_back(getLabelLoc(argIdx));
// If the types exactly match, this is easy.
auto paramType = param.getOldType();
if (argType->isEqual(paramType) && !shouldInjectWrappedValuePlaceholder) {
newArgs.push_back(arg);
newParams.push_back(param);
continue;
}
Expr *convertedArg = nullptr;
auto argRequiresAutoClosureExpr = [&](const AnyFunctionType::Param &param,
Type argType) {
if (!param.isAutoClosure())
return false;
// Since it was allowed to pass function types to @autoclosure
// parameters in Swift versions < 5, it has to be handled as
// a regular function coversion by `coerceToType`.
if (isAutoClosureArgument(arg)) {
// In Swift >= 5 mode we only allow `@autoclosure` arguments
// to be used by value if parameter would return a function
// type (it just needs to get wrapped into autoclosure expr),
// otherwise argument must always form a call.
return cs.getASTContext().isSwiftVersionAtLeast(5);
}
return true;
};
if (argRequiresAutoClosureExpr(param, argType)) {
assert(!param.isInOut());
// If parameter is an autoclosure, we need to make sure that:
// - argument type is coerced to parameter result type
// - impilict autoclosure is created to wrap argument expression
// - new types are propagated to constraint system
auto *closureType = param.getPlainType()->castTo<FunctionType>();
auto argLoc = getArgLocator(argIdx, paramIdx, param.getParameterFlags());
arg = coerceToType(
arg, closureType->getResult(),
argLoc.withPathElement(ConstraintLocator::AutoclosureResult));
if (shouldInjectWrappedValuePlaceholder) {
// If init(wrappedValue:) takes an autoclosure, then we want
// the effect of autoclosure forwarding of the placeholder
// autoclosure. The only way to do this is to call the placeholder
// autoclosure when passing it to the init.
bool isDefaultWrappedValue =
target->propertyWrapperHasInitialWrappedValue();
auto *placeholder = injectWrappedValuePlaceholder(
cs.buildAutoClosureExpr(arg, closureType, isDefaultWrappedValue),
/*isAutoClosure=*/true);
arg = CallExpr::createImplicit(ctx, placeholder, {}, {});
arg->setType(closureType->getResult());
cs.cacheType(arg);
}
convertedArg = cs.buildAutoClosureExpr(arg, closureType);
} else {
convertedArg = coerceToType(
arg, paramType,
getArgLocator(argIdx, paramIdx, param.getParameterFlags()));
}
// Perform the wrapped value placeholder injection
if (shouldInjectWrappedValuePlaceholder)
convertedArg = injectWrappedValuePlaceholder(convertedArg);
if (!convertedArg)
return nullptr;
newArgs.push_back(convertedArg);
// Make an effort to preserve the sugared type of the argument in the
// case where there was no conversion, instead of using the parameter
// type.
newParams.emplace_back(cs.getType(convertedArg)->getInOutObjectType(),
param.getLabel(),
param.getParameterFlags());
}
assert(newArgs.size() == newParams.size());
assert(newArgs.size() == newLabels.size());
assert(newArgs.size() == newLabelLocs.size());
// This is silly. SILGen gets confused if a 'self' parameter is wrapped
// in a ParenExpr sometimes.
if (!argTuple && !argParen &&
(params[0].getValueOwnership() == ValueOwnership::Default ||
params[0].getValueOwnership() == ValueOwnership::InOut)) {
assert(newArgs.size() == 1);
assert(!unlabeledTrailingClosureIndex);
return newArgs[0];
}
// Rebuild the argument list, sharing as much structure as possible.
auto paramType = AnyFunctionType::composeInput(ctx, newParams,
/*canonicalVararg=*/false);
if (isa<ParenType>(paramType.getPointer())) {
if (argParen) {
// We already had a ParenExpr, so replace it's sub-expression.
argParen->setSubExpr(newArgs[0]);
} else {
bool isImplicit = arg->isImplicit();
arg = new (ctx) ParenExpr(
lParenLoc, newArgs[0], rParenLoc,
static_cast<bool>(unlabeledTrailingClosureIndex));
arg->setImplicit(isImplicit);
}
} else {
assert(isa<TupleType>(paramType.getPointer()));
if (argTuple && newArgs.size() == argTuple->getNumElements()) {
// The existing TupleExpr has the right number of elements,
// replace them.
for (unsigned i = 0, e = newArgs.size(); i != e; ++i) {
argTuple->setElement(i, newArgs[i]);
}
} else {
// Build a new TupleExpr, re-using source location information.
arg = TupleExpr::create(ctx, lParenLoc, rParenLoc, newArgs, newLabels,
newLabelLocs, unlabeledTrailingClosureIndex,
/*implicit=*/arg->isImplicit());
}
}
arg->setType(paramType);
return cs.cacheType(arg);
}
static bool isClosureLiteralExpr(Expr *expr) {
expr = expr->getSemanticsProvidingExpr();
return (isa<CaptureListExpr>(expr) || isa<ClosureExpr>(expr));
}
/// If the expression is an explicit closure expression (potentially wrapped in
/// IdentityExprs), change the type of the closure and identities to the
/// specified type and return true. Otherwise, return false with no effect.
static bool applyTypeToClosureExpr(ConstraintSystem &cs,
Expr *expr, Type toType) {
// Look through identity expressions, like parens.
if (auto IE = dyn_cast<IdentityExpr>(expr)) {
if (!applyTypeToClosureExpr(cs, IE->getSubExpr(), toType)) return false;
cs.setType(IE, toType);
return true;
}
// Look through capture lists.
if (auto CLE = dyn_cast<CaptureListExpr>(expr)) {
if (!applyTypeToClosureExpr(cs, CLE->getClosureBody(), toType)) return false;
cs.setType(CLE, toType);
return true;
}
// If we found an explicit ClosureExpr, update its type.
if (auto CE = dyn_cast<ClosureExpr>(expr)) {
cs.setType(CE, toType);
// If this closure isn't type-checked in its enclosing expression, write
// the type into the ClosureExpr directly here, since the visitor won't.
if (!shouldTypeCheckInEnclosingExpression(CE))
CE->setType(toType);
return true;
}
// Otherwise fail.
return false;
}
// Look through sugar and DotSyntaxBaseIgnoredExprs.
static Expr *
getSemanticExprForDeclOrMemberRef(Expr *expr) {
auto semanticExpr = expr->getSemanticsProvidingExpr();
while (auto ignoredBase = dyn_cast<DotSyntaxBaseIgnoredExpr>(semanticExpr)){
semanticExpr = ignoredBase->getRHS()->getSemanticsProvidingExpr();
}
return semanticExpr;
}
static void
maybeDiagnoseUnsupportedDifferentiableConversion(ConstraintSystem &cs,
Expr *expr,
AnyFunctionType *toType) {
ASTContext &ctx = cs.getASTContext();
Type fromType = cs.getType(expr);
auto fromFnType = fromType->getAs<AnyFunctionType>();
auto isToTypeLinear =
toType->getDifferentiabilityKind() == DifferentiabilityKind::Linear;
// Conversion from a `@differentiable` function to a `@differentiable(linear)`
// function is not allowed, because the from-expression will never be a
// closure expression or a declaration/member reference.
if (fromFnType->getDifferentiabilityKind() == DifferentiabilityKind::Normal &&
toType->getDifferentiabilityKind() == DifferentiabilityKind::Linear) {
ctx.Diags.diagnose(expr->getLoc(),
diag::invalid_differentiable_function_conversion_expr,
isToTypeLinear);
return;
}
// Conversion from a non-`@differentiable` function to a `@differentiable` is
// only allowed from a closure expression or a declaration/member reference.
if (!fromFnType->isDifferentiable() && toType->isDifferentiable()) {
std::function<void(Expr *)> maybeDiagnoseFunctionRef;
maybeDiagnoseFunctionRef = [&](Expr *semanticExpr) {
if (auto *capture = dyn_cast<CaptureListExpr>(semanticExpr))
semanticExpr = capture->getClosureBody();
if (isa<ClosureExpr>(semanticExpr)) return;
if (auto *declRef = dyn_cast<DeclRefExpr>(semanticExpr)) {
if (isa<AbstractFunctionDecl>(declRef->getDecl())) return;
// If the referenced decl is a function parameter, the user may want
// to change the declaration to be a '@differentiable' closure. Emit a
// note with a fix-it.
if (auto *paramDecl = dyn_cast<ParamDecl>(declRef->getDecl())) {
ctx.Diags.diagnose(
expr->getLoc(),
diag::invalid_differentiable_function_conversion_expr,
isToTypeLinear);
if (paramDecl->getType()->is<AnyFunctionType>()) {
auto *typeRepr = paramDecl->getTypeRepr();
while (auto *attributed = dyn_cast<AttributedTypeRepr>(typeRepr))
typeRepr = attributed->getTypeRepr();
std::string attributeString = "@differentiable";
if (isToTypeLinear)
attributeString += "(linear)";
auto *funcTypeRepr = cast<FunctionTypeRepr>(typeRepr);
auto paramListLoc = funcTypeRepr->getArgsTypeRepr()->getStartLoc();
ctx.Diags.diagnose(paramDecl->getLoc(),
diag::invalid_differentiable_function_conversion_parameter,
attributeString)
.highlight(paramDecl->getTypeRepr()->getSourceRange())
.fixItInsert(paramListLoc, attributeString + " ");
}
return;
}
} else if (auto *memberRef = dyn_cast<MemberRefExpr>(semanticExpr)) {
if (isa<FuncDecl>(memberRef->getMember().getDecl())) return;
} else if (auto *dotSyntaxCall =
dyn_cast<DotSyntaxCallExpr>(semanticExpr)) {
// Recurse on the function expression.
auto *fnExpr = dotSyntaxCall->getFn()->getSemanticsProvidingExpr();
maybeDiagnoseFunctionRef(fnExpr);
return;
} else if (auto *autoclosureExpr = dyn_cast<AutoClosureExpr>(semanticExpr)) {
// Peer through curry thunks.
if (auto *unwrappedFnExpr = autoclosureExpr->getUnwrappedCurryThunkExpr()) {
maybeDiagnoseFunctionRef(unwrappedFnExpr);
return;
}
}
ctx.Diags.diagnose(expr->getLoc(),
diag::invalid_differentiable_function_conversion_expr,
isToTypeLinear);
};
maybeDiagnoseFunctionRef(getSemanticExprForDeclOrMemberRef(expr));
}
}
static void
maybeDiagnoseUnsupportedFunctionConversion(ConstraintSystem &cs, Expr *expr,
AnyFunctionType *toType) {
auto &de = cs.getASTContext().Diags;
Type fromType = cs.getType(expr);
auto fromFnType = fromType->getAs<AnyFunctionType>();
// Conversions to C function pointer type are limited. Since a C function
// pointer captures no context, we can only do the necessary thunking or
// codegen if the original function is a direct reference to a global function
// or context-free closure or local function.
if (toType->getRepresentation()
== AnyFunctionType::Representation::CFunctionPointer) {
// Can convert from an ABI-compatible C function pointer.
if (fromFnType
&& fromFnType->getRepresentation()
== AnyFunctionType::Representation::CFunctionPointer)
return;
// Can convert a decl ref to a global or local function that doesn't
// capture context. Look through ignored bases too.
// TODO: Look through static method applications to the type.
auto semanticExpr = getSemanticExprForDeclOrMemberRef(expr);
auto maybeDiagnoseFunctionRef = [&](FuncDecl *fn) {
// TODO: We could allow static (or class final) functions too by
// "capturing" the metatype in a thunk.
if (fn->getDeclContext()->isTypeContext()) {
de.diagnose(expr->getLoc(), diag::c_function_pointer_from_method);
} else if (fn->getGenericParams()) {
de.diagnose(expr->getLoc(),
diag::c_function_pointer_from_generic_function);
}
};
if (auto declRef = dyn_cast<DeclRefExpr>(semanticExpr)) {
if (auto fn = dyn_cast<FuncDecl>(declRef->getDecl())) {
return maybeDiagnoseFunctionRef(fn);
}
}
if (auto memberRef = dyn_cast<MemberRefExpr>(semanticExpr)) {
if (auto fn = dyn_cast<FuncDecl>(memberRef->getMember().getDecl())) {
return maybeDiagnoseFunctionRef(fn);
}
}
// Unwrap closures with explicit capture lists.
if (auto capture = dyn_cast<CaptureListExpr>(semanticExpr))
semanticExpr = capture->getClosureBody();
// Can convert a literal closure that doesn't capture context.
if (auto closure = dyn_cast<ClosureExpr>(semanticExpr))
return;
de.diagnose(expr->getLoc(),
diag::invalid_c_function_pointer_conversion_expr);
}
}
/// Build the conversion of an element in a collection upcast.
static Expr *buildElementConversion(ExprRewriter &rewriter,
SourceRange srcRange, Type srcType,
Type destType, bool bridged,
ConstraintLocatorBuilder locator,
Expr *element) {
auto &cs = rewriter.getConstraintSystem();
if (bridged &&
TypeChecker::typeCheckCheckedCast(srcType, destType,
CheckedCastContextKind::None, cs.DC,
SourceLoc(), nullptr, SourceRange())
!= CheckedCastKind::Coercion) {
if (auto conversion =
rewriter.buildObjCBridgeExpr(element, destType, locator))
return conversion;
}
return rewriter.coerceToType(element, destType, locator);
}
static CollectionUpcastConversionExpr::ConversionPair
buildOpaqueElementConversion(ExprRewriter &rewriter, SourceRange srcRange,
Type srcCollectionType, Type destCollectionType,
bool bridged, ConstraintLocatorBuilder locator,
unsigned typeArgIndex) {
// We don't need this stuff unless we've got generalized casts.
Type srcType = srcCollectionType->castTo<BoundGenericType>()
->getGenericArgs()[typeArgIndex];
Type destType = destCollectionType->castTo<BoundGenericType>()
->getGenericArgs()[typeArgIndex];
// Build the conversion.
auto &cs = rewriter.getConstraintSystem();
ASTContext &ctx = cs.getASTContext();
auto opaque =
rewriter.cs.cacheType(new (ctx) OpaqueValueExpr(srcRange, srcType));
Expr *conversion = buildElementConversion(
rewriter, srcRange, srcType, destType, bridged,
locator.withPathElement(LocatorPathElt::GenericArgument(typeArgIndex)),
opaque);
return { opaque, conversion };
}
void ExprRewriter::peepholeArrayUpcast(ArrayExpr *expr, Type toType,
bool bridged, Type elementType,
ConstraintLocatorBuilder locator) {
// Update the type of the array literal.
cs.setType(expr, toType);
// FIXME: finish{Array,Dictionary}Expr invoke cacheExprTypes after forming
// the semantic expression for the dictionary literal, which will undo the
// type we set here if this dictionary literal is nested unless we update
// the expr type as well.
expr->setType(toType);
// Convert the elements.
ConstraintLocatorBuilder innerLocator =
locator.withPathElement(LocatorPathElt::GenericArgument(0));
for (auto &element : expr->getElements()) {
if (auto newElement = buildElementConversion(*this, expr->getLoc(),
cs.getType(element),
elementType,
bridged, innerLocator,
element)) {
element = newElement;
}
}
(void)finishArrayExpr(expr);
}
void ExprRewriter::peepholeDictionaryUpcast(DictionaryExpr *expr,
Type toType, bool bridged,
Type keyType, Type valueType,
ConstraintLocatorBuilder locator) {
// Update the type of the dictionary literal.
cs.setType(expr, toType);
// FIXME: finish{Array,Dictionary}Expr invoke cacheExprTypes after forming
// the semantic expression for the dictionary literal, which will undo the
// type we set here if this dictionary literal is nested unless we update
// the expr type as well.
expr->setType(toType);
ConstraintLocatorBuilder valueLocator =
locator.withPathElement(LocatorPathElt::GenericArgument(1));
// Convert the elements.
TupleTypeElt tupleTypeElts[2] = { keyType, valueType };
auto tupleType = TupleType::get(tupleTypeElts, cs.getASTContext());
for (auto element : expr->getElements()) {
if (auto tuple = dyn_cast<TupleExpr>(element)) {
auto key = tuple->getElement(0);
if (auto newKey = buildElementConversion(*this, expr->getLoc(),
cs.getType(key), keyType,
bridged, valueLocator, key))
tuple->setElement(0, newKey);
auto value = tuple->getElement(1);
if (auto newValue = buildElementConversion(*this, expr->getLoc(),
cs.getType(value), valueType,
bridged, valueLocator,
value)) {
tuple->setElement(1, newValue);
}
cs.setType(tuple, tupleType);
// FIXME: finish{Array,Dictionary}Expr invoke cacheExprTypes after forming
// the semantic expression for the dictionary literal, which will undo the
// type we set here if this dictionary literal is nested unless we update
// the expr type as well.
tuple->setType(tupleType);
}
}
(void)finishDictionaryExpr(expr);
}
bool ExprRewriter::peepholeCollectionUpcast(Expr *expr, Type toType,
bool bridged,
ConstraintLocatorBuilder locator) {
// Recur into parenthesized expressions.
if (auto paren = dyn_cast<ParenExpr>(expr)) {
// If we can't peephole the subexpression, we're done.
if (!peepholeCollectionUpcast(paren->getSubExpr(), toType, bridged,
locator))
return false;
// Update the type of this expression.
auto parenTy = ParenType::get(cs.getASTContext(),
cs.getType(paren->getSubExpr()));
cs.setType(paren, parenTy);
// FIXME: finish{Array,Dictionary}Expr invoke cacheExprTypes after forming
// the semantic expression for the dictionary literal, which will undo the
// type we set here if this dictionary literal is nested unless we update
// the expr type as well.
paren->setType(parenTy);
return true;
}
// Array literals.
if (auto arrayLiteral = dyn_cast<ArrayExpr>(expr)) {
if (Optional<Type> elementType = ConstraintSystem::isArrayType(toType)) {
peepholeArrayUpcast(arrayLiteral, toType, bridged, *elementType, locator);
return true;
}
if (Optional<Type> elementType = ConstraintSystem::isSetType(toType)) {
peepholeArrayUpcast(arrayLiteral, toType, bridged, *elementType, locator);
return true;
}
return false;
}
// Dictionary literals.
if (auto dictLiteral = dyn_cast<DictionaryExpr>(expr)) {
if (auto elementType = ConstraintSystem::isDictionaryType(toType)) {
peepholeDictionaryUpcast(dictLiteral, toType, bridged,
elementType->first, elementType->second,
locator);
return true;
}
return false;
}
return false;
}
Expr *ExprRewriter::buildCollectionUpcastExpr(
Expr *expr, Type toType,
bool bridged,
ConstraintLocatorBuilder locator) {
if (peepholeCollectionUpcast(expr, toType, bridged, locator))
return expr;
ASTContext &ctx = cs.getASTContext();
// Build the first value conversion.
auto conv =
buildOpaqueElementConversion(*this, expr->getLoc(), cs.getType(expr),
toType, bridged, locator, 0);
// For single-parameter collections, form the upcast.
if (ConstraintSystem::isArrayType(toType) ||
ConstraintSystem::isSetType(toType)) {
return cs.cacheType(
new (ctx) CollectionUpcastConversionExpr(expr, toType, {}, conv));
}
assert(ConstraintSystem::isDictionaryType(toType) &&
"Unhandled collection upcast");
// Build the second value conversion.
auto conv2 =
buildOpaqueElementConversion(*this, expr->getLoc(), cs.getType(expr),
toType, bridged, locator, 1);
return cs.cacheType(
new (ctx) CollectionUpcastConversionExpr(expr, toType, conv, conv2));
}
Expr *ExprRewriter::buildObjCBridgeExpr(Expr *expr, Type toType,
ConstraintLocatorBuilder locator) {
Type fromType = cs.getType(expr);
// Bridged collection casts always succeed, so we treat them as
// collection "upcasts".
if ((ConstraintSystem::isArrayType(fromType) &&
ConstraintSystem::isArrayType(toType)) ||
(ConstraintSystem::isDictionaryType(fromType) &&
ConstraintSystem::isDictionaryType(toType)) ||
(ConstraintSystem::isSetType(fromType) &&
ConstraintSystem::isSetType(toType))) {
return buildCollectionUpcastExpr(expr, toType, /*bridged=*/true, locator);
}
// Bridging from a Swift type to an Objective-C class type.
if (toType->isAnyObject() ||
(fromType->getRValueType()->isPotentiallyBridgedValueType() &&
(toType->isBridgeableObjectType() || toType->isExistentialType()))) {
// Bridging to Objective-C.
Expr *objcExpr = bridgeToObjectiveC(expr, toType);
if (!objcExpr)
return nullptr;
// We might have a coercion of a Swift type to a CF type toll-free
// bridged to Objective-C.
//
// FIXME: Ideally we would instead have already recorded a restriction
// when solving the constraint, and we wouldn't need to duplicate this
// part of coerceToType() here.
if (auto foreignClass = toType->getClassOrBoundGenericClass()) {
if (foreignClass->getForeignClassKind() ==
ClassDecl::ForeignKind::CFType) {
return cs.cacheType(new (cs.getASTContext())
ForeignObjectConversionExpr(objcExpr, toType));
}
}
return coerceToType(objcExpr, toType, locator);
}
// Bridging from an Objective-C class type to a Swift type.
return forceBridgeFromObjectiveC(expr, toType);
}
Expr *ConstraintSystem::addImplicitLoadExpr(Expr *expr) {
return TypeChecker::addImplicitLoadExpr(
getASTContext(), expr, [this](Expr *expr) { return getType(expr); },
[this](Expr *expr, Type type) { setType(expr, type); });
}
Expr *ExprRewriter::coerceToType(Expr *expr, Type toType,
ConstraintLocatorBuilder locator,
Optional<Pattern*> typeFromPattern) {
auto &ctx = cs.getASTContext();
// The type we're converting from.
Type fromType = cs.getType(expr);
// If the types are already equivalent, we don't have to do anything.
if (fromType->isEqual(toType))
return expr;
// If the solver recorded what we should do here, just do it immediately.
auto knownRestriction = solution.ConstraintRestrictions.find(
{ fromType->getCanonicalType(),
toType->getCanonicalType() });
if (knownRestriction != solution.ConstraintRestrictions.end()) {
switch (knownRestriction->second) {
case ConversionRestrictionKind::DeepEquality: {
if (toType->hasUnresolvedType())
break;
// HACK: Fix problem related to Swift 4 mode (with assertions),
// since Swift 4 mode allows passing arguments with extra parens
// to parameters which don't expect them, it should be supported
// by "deep equality" type - Optional<T> e.g.
// ```swift
// func foo(_: (() -> Void)?) {}
// func bar() -> ((()) -> Void)? { return nil }
// foo(bar) // This expression should compile in Swift 3 mode
// ```
//
// See also: https://bugs.swift.org/browse/SR-6796
if (cs.getASTContext().isSwiftVersionAtLeast(4) &&
!cs.getASTContext().isSwiftVersionAtLeast(5)) {
auto obj1 = fromType->getOptionalObjectType();
auto obj2 = toType->getOptionalObjectType();
if (obj1 && obj2) {
auto *fn1 = obj1->getAs<AnyFunctionType>();
auto *fn2 = obj2->getAs<AnyFunctionType>();
if (fn1 && fn2) {
auto params1 = fn1->getParams();
auto params2 = fn2->getParams();
// This handles situations like argument: (()), parameter: ().
if (params1.size() == 1 && params2.empty()) {
auto tupleTy = params1.front().getOldType()->getAs<TupleType>();
if (tupleTy && tupleTy->getNumElements() == 0)
break;
}
}
}
}
auto &err = llvm::errs();
err << "fromType->getCanonicalType() = ";
fromType->getCanonicalType()->dump(err);
err << "toType->getCanonicalType() = ";
toType->getCanonicalType()->dump(err);
llvm_unreachable("Should be handled above");
}
case ConversionRestrictionKind::Superclass:
case ConversionRestrictionKind::ExistentialMetatypeToMetatype:
return coerceSuperclass(expr, toType);
case ConversionRestrictionKind::Existential:
case ConversionRestrictionKind::MetatypeToExistentialMetatype:
return coerceExistential(expr, toType);
case ConversionRestrictionKind::ClassMetatypeToAnyObject: {
assert(ctx.LangOpts.EnableObjCInterop &&
"metatypes can only be cast to objects w/ objc runtime!");
return cs.cacheType(new (ctx) ClassMetatypeToObjectExpr(expr, toType));
}
case ConversionRestrictionKind::ExistentialMetatypeToAnyObject: {
assert(ctx.LangOpts.EnableObjCInterop &&
"metatypes can only be cast to objects w/ objc runtime!");
return cs.cacheType(new (ctx)
ExistentialMetatypeToObjectExpr(expr, toType));
}
case ConversionRestrictionKind::ProtocolMetatypeToProtocolClass: {
return cs.cacheType(new (ctx) ProtocolMetatypeToObjectExpr(expr, toType));
}
case ConversionRestrictionKind::ValueToOptional: {
auto toGenericType = toType->castTo<BoundGenericType>();
assert(toGenericType->getDecl()->isOptionalDecl());
TypeChecker::requireOptionalIntrinsics(cs.getASTContext(),
expr->getLoc());
Type valueType = toGenericType->getGenericArgs()[0];
expr = coerceToType(expr, valueType, locator);
if (!expr) return nullptr;
auto *result =
cs.cacheType(new (ctx) InjectIntoOptionalExpr(expr, toType));
diagnoseOptionalInjection(result);
return result;
}
case ConversionRestrictionKind::OptionalToOptional:
return coerceOptionalToOptional(expr, toType, locator, typeFromPattern);
case ConversionRestrictionKind::ArrayUpcast: {
// Build the value conversion.
return buildCollectionUpcastExpr(expr, toType, /*bridged=*/false,
locator);
}
case ConversionRestrictionKind::HashableToAnyHashable: {
// We want to check conformance on the rvalue, as that's what has
// the Hashable conformance
expr = cs.coerceToRValue(expr);
// Find the conformance of the source type to Hashable.
auto hashable = ctx.getProtocol(KnownProtocolKind::Hashable);
auto conformance =
TypeChecker::conformsToProtocol(
cs.getType(expr), hashable, cs.DC);
assert(conformance && "must conform to Hashable");
return cs.cacheType(
new (ctx) AnyHashableErasureExpr(expr, toType, conformance));
}
case ConversionRestrictionKind::DictionaryUpcast: {
// Build the value conversion.
return buildCollectionUpcastExpr(expr, toType, /*bridged=*/false,
locator);
}
case ConversionRestrictionKind::SetUpcast: {
// Build the value conversion.
return buildCollectionUpcastExpr(expr, toType, /*bridged=*/false, locator);
}
case ConversionRestrictionKind::InoutToPointer: {
bool isOptional = false;
Type unwrappedTy = toType;
if (Type unwrapped = toType->getOptionalObjectType()) {
isOptional = true;
unwrappedTy = unwrapped;
}
PointerTypeKind pointerKind;
auto toEltType = unwrappedTy->getAnyPointerElementType(pointerKind);
assert(toEltType && "not a pointer type?"); (void) toEltType;
TypeChecker::requirePointerArgumentIntrinsics(ctx, expr->getLoc());
Expr *result =
cs.cacheType(new (ctx) InOutToPointerExpr(expr, unwrappedTy));
if (isOptional)
result = cs.cacheType(new (ctx) InjectIntoOptionalExpr(result, toType));
return result;
}
case ConversionRestrictionKind::ArrayToPointer: {
bool isOptional = false;
Type unwrappedTy = toType;
if (Type unwrapped = toType->getOptionalObjectType()) {
isOptional = true;
unwrappedTy = unwrapped;
}
TypeChecker::requirePointerArgumentIntrinsics(ctx, expr->getLoc());
Expr *result =
cs.cacheType(new (ctx) ArrayToPointerExpr(expr, unwrappedTy));
if (isOptional)
result = cs.cacheType(new (ctx) InjectIntoOptionalExpr(result, toType));
return result;
}
case ConversionRestrictionKind::StringToPointer: {
bool isOptional = false;
Type unwrappedTy = toType;
if (Type unwrapped = toType->getOptionalObjectType()) {
isOptional = true;
unwrappedTy = unwrapped;
}
TypeChecker::requirePointerArgumentIntrinsics(ctx, expr->getLoc());
Expr *result =
cs.cacheType(new (ctx) StringToPointerExpr(expr, unwrappedTy));
if (isOptional)
result = cs.cacheType(new (ctx) InjectIntoOptionalExpr(result, toType));
return result;
}
case ConversionRestrictionKind::PointerToPointer: {
TypeChecker::requirePointerArgumentIntrinsics(ctx, expr->getLoc());
Type unwrappedToTy = toType->getOptionalObjectType();
// Optional to optional.
if (Type unwrappedFromTy = cs.getType(expr)->getOptionalObjectType()) {
assert(unwrappedToTy && "converting optional to non-optional");
Expr *boundOptional = cs.cacheType(
new (ctx) BindOptionalExpr(expr, SourceLoc(),
/*depth*/ 0, unwrappedFromTy));
Expr *converted = cs.cacheType(
new (ctx) PointerToPointerExpr(boundOptional, unwrappedToTy));
Expr *rewrapped =
cs.cacheType(new (ctx) InjectIntoOptionalExpr(converted, toType));
return cs.cacheType(new (ctx)
OptionalEvaluationExpr(rewrapped, toType));
}
// Non-optional to optional.
if (unwrappedToTy) {
Expr *converted =
cs.cacheType(new (ctx) PointerToPointerExpr(expr, unwrappedToTy));
return cs.cacheType(new (ctx)
InjectIntoOptionalExpr(converted, toType));
}
// Non-optional to non-optional.
return cs.cacheType(new (ctx) PointerToPointerExpr(expr, toType));
}
case ConversionRestrictionKind::CFTollFreeBridgeToObjC: {
auto foreignClass = fromType->getClassOrBoundGenericClass();
auto objcType = foreignClass->getAttrs().getAttribute<ObjCBridgedAttr>()
->getObjCClass()->getDeclaredInterfaceType();
auto asObjCClass =
cs.cacheType(new (ctx) ForeignObjectConversionExpr(expr, objcType));
return coerceToType(asObjCClass, toType, locator);
}
case ConversionRestrictionKind::ObjCTollFreeBridgeToCF: {
auto foreignClass = toType->getClassOrBoundGenericClass();
auto objcType = foreignClass->getAttrs().getAttribute<ObjCBridgedAttr>()
->getObjCClass()->getDeclaredInterfaceType();
Expr *result = coerceToType(expr, objcType, locator);
if (!result)
return nullptr;
return cs.cacheType(new (ctx)
ForeignObjectConversionExpr(result, toType));
}
}
}
// Handle "from specific" coercions before "catch all" coercions.
auto desugaredFromType = fromType->getDesugaredType();
switch (desugaredFromType->getKind()) {
// Coercions from an lvalue: load or perform implicit address-of. We perform
// these coercions first because they are often the first step in a multi-step
// coercion.
case TypeKind::LValue: {
auto fromLValue = cast<LValueType>(desugaredFromType);
auto toIO = toType->getAs<InOutType>();
if (!toIO)
return coerceToType(cs.addImplicitLoadExpr(expr), toType, locator);
// In an 'inout' operator like "i += 1", the operand is converted from
// an implicit lvalue to an inout argument.
assert(toIO->getObjectType()->isEqual(fromLValue->getObjectType()));
return cs.cacheType(new (ctx) InOutExpr(expr->getStartLoc(), expr,
toIO->getObjectType(),
/*isImplicit*/ true));
}
// Coerce from a tuple to a tuple.
case TypeKind::Tuple: {
auto fromTuple = cast<TupleType>(desugaredFromType);
auto toTuple = toType->getAs<TupleType>();
if (!toTuple)
break;
if (fromTuple->hasLValueType() && !toTuple->hasLValueType())
return coerceToType(cs.coerceToRValue(expr), toType, locator);
SmallVector<unsigned, 4> sources;
if (!computeTupleShuffle(fromTuple, toTuple, sources)) {
return coerceTupleToTuple(expr, fromTuple, toTuple,
locator, sources);
}
break;
}
case TypeKind::PrimaryArchetype:
case TypeKind::OpenedArchetype:
case TypeKind::NestedArchetype:
case TypeKind::OpaqueTypeArchetype:
if (!cast<ArchetypeType>(desugaredFromType)->requiresClass())
break;
LLVM_FALLTHROUGH;
// Coercion from a subclass to a superclass.
//
// FIXME: Can we rig things up so that we always have a Superclass
// conversion restriction in this case?
case TypeKind::DynamicSelf:
case TypeKind::BoundGenericClass:
case TypeKind::Class: {
if (!toType->getClassOrBoundGenericClass())
break;
for (auto fromSuperClass = fromType->getSuperclass();
fromSuperClass;
fromSuperClass = fromSuperClass->getSuperclass()) {
if (fromSuperClass->isEqual(toType)) {
return coerceSuperclass(expr, toType);
}
}
break;
}
// Coercion from one function type to another, this produces a
// FunctionConversionExpr in its full generality.
case TypeKind::Function: {
auto fromFunc = cast<FunctionType>(desugaredFromType);
auto toFunc = toType->getAs<FunctionType>();
if (!toFunc)
break;
// Default argument generator must return escaping functions. Therefore, we
// leave an explicit escape to noescape cast here such that SILGen can skip
// the cast and emit a code for the escaping function.
bool isInDefaultArgumentContext = false;
if (auto initalizerCtx = dyn_cast<Initializer>(cs.DC))
isInDefaultArgumentContext = (initalizerCtx->getInitializerKind() ==
InitializerKind::DefaultArgument);
auto toEI = toFunc->getExtInfo();
assert(toType->is<FunctionType>());
// Handle implicit conversions between non-@differentiable and
// @differentiable functions.
{
auto fromEI = fromFunc->getExtInfo();
auto isFromDifferentiable = fromEI.isDifferentiable();
auto isToDifferentiable = toEI.isDifferentiable();
// Handle implicit conversion from @differentiable.
if (isFromDifferentiable && !isToDifferentiable) {
fromFunc = fromFunc->getWithoutDifferentiability()
->castTo<FunctionType>();
switch (fromEI.getDifferentiabilityKind()) {
case DifferentiabilityKind::Normal:
expr = cs.cacheType(new (ctx)
DifferentiableFunctionExtractOriginalExpr(expr, fromFunc));
break;
case DifferentiabilityKind::Linear:
expr = cs.cacheType(new (ctx)
LinearFunctionExtractOriginalExpr(expr, fromFunc));
break;
case DifferentiabilityKind::NonDifferentiable:
llvm_unreachable("Cannot be NonDifferentiable");
}
}
// Handle implicit conversion from @differentiable(linear) to
// @differentiable.
else if (fromEI.getDifferentiabilityKind() ==
DifferentiabilityKind::Linear &&
toEI.getDifferentiabilityKind() == DifferentiabilityKind::Normal) {
// TODO(TF-908): Create a `LinearToDifferentiableFunctionExpr` and SILGen
// it as thunk application. Remove the diagnostic.
ctx.Diags.diagnose(expr->getLoc(),
diag::unsupported_linear_to_differentiable_conversion);
}
// Handle implicit conversion from non-@differentiable to @differentiable.
maybeDiagnoseUnsupportedDifferentiableConversion(cs, expr, toFunc);
if (!isFromDifferentiable && isToDifferentiable) {
auto newEI =
fromEI.intoBuilder()
.withDifferentiabilityKind(toEI.getDifferentiabilityKind())
.build();
fromFunc = FunctionType::get(toFunc->getParams(), fromFunc->getResult())
->withExtInfo(newEI)
->castTo<FunctionType>();
switch (toEI.getDifferentiabilityKind()) {
case DifferentiabilityKind::Normal:
expr = cs.cacheType(new (ctx)
DifferentiableFunctionExpr(expr, fromFunc));
break;
case DifferentiabilityKind::Linear:
expr = cs.cacheType(new (ctx)
LinearFunctionExpr(expr, fromFunc));
break;
case DifferentiabilityKind::NonDifferentiable:
llvm_unreachable("Cannot be NonDifferentiable");
}
}
}
// If we have a ClosureExpr, then we can safely propagate the 'no escape'
// bit to the closure without invalidating prior analysis.
auto fromEI = fromFunc->getExtInfo();
if (toEI.isNoEscape() && !fromEI.isNoEscape()) {
auto newFromFuncType = fromFunc->withExtInfo(fromEI.withNoEscape());
if (!isInDefaultArgumentContext &&
applyTypeToClosureExpr(cs, expr, newFromFuncType)) {
fromFunc = newFromFuncType->castTo<FunctionType>();
// Propagating the 'no escape' bit might have satisfied the entire
// conversion. If so, we're done, otherwise keep converting.
if (fromFunc->isEqual(toType))
return expr;
} else if (isInDefaultArgumentContext) {
// First apply the conversion *without* noescape attribute.
if (!newFromFuncType->isEqual(toType)) {
auto escapingToFuncTy =
toFunc->withExtInfo(toEI.withNoEscape(false));
maybeDiagnoseUnsupportedFunctionConversion(cs, expr, toFunc);
expr = cs.cacheType(
new (ctx) FunctionConversionExpr(expr, escapingToFuncTy));
}
// Apply an explict function conversion *only* for the escape to
// noescape conversion. This conversion will be stripped by the
// default argument generator. (We can't return a @noescape function)
auto newExpr =
cs.cacheType(new (ctx) FunctionConversionExpr(expr, toFunc));
return newExpr;
}
}
maybeDiagnoseUnsupportedFunctionConversion(cs, expr, toFunc);
return cs.cacheType(new (ctx) FunctionConversionExpr(expr, toType));
}
// Coercions from one metatype to another.
case TypeKind::Metatype: {
if (auto toMeta = toType->getAs<MetatypeType>())
return cs.cacheType(new (ctx) MetatypeConversionExpr(expr, toMeta));
LLVM_FALLTHROUGH;
}
// Coercions from metatype to objects.
case TypeKind::ExistentialMetatype: {
auto fromMeta = cast<AnyMetatypeType>(desugaredFromType);
if (toType->isAnyObject()) {
assert(cs.getASTContext().LangOpts.EnableObjCInterop
&& "metatype-to-object conversion requires objc interop");
if (fromMeta->is<MetatypeType>()) {
assert(fromMeta->getInstanceType()->mayHaveSuperclass()
&& "metatype-to-object input should be a class metatype");
return cs.cacheType(new (ctx) ClassMetatypeToObjectExpr(expr, toType));
}
if (fromMeta->is<ExistentialMetatypeType>()) {
assert(fromMeta->getInstanceType()->getCanonicalType()
->getExistentialLayout().requiresClass()
&& "metatype-to-object input should be a class metatype");
return cs.cacheType(new (ctx)
ExistentialMetatypeToObjectExpr(expr, toType));
}
llvm_unreachable("unhandled metatype kind");
}
if (auto toClass = toType->getClassOrBoundGenericClass()) {
if (toClass->getName() == cs.getASTContext().Id_Protocol
&& toClass->getModuleContext()->getName()
== cs.getASTContext().Id_ObjectiveC) {
assert(cs.getASTContext().LangOpts.EnableObjCInterop
&& "metatype-to-object conversion requires objc interop");
assert(fromMeta->is<MetatypeType>()
&& fromMeta->getInstanceType()->is<ProtocolType>()
&& "protocol-metatype-to-Protocol only works for single "
"protocols");
return cs.cacheType(new (ctx)
ProtocolMetatypeToObjectExpr(expr, toType));
}
}
break;
}
#define SUGARED_TYPE(Name, Parent) case TypeKind::Name:
#define BUILTIN_TYPE(Name, Parent) case TypeKind::Name:
#define UNCHECKED_TYPE(Name, Parent) case TypeKind::Name:
#define ARTIFICIAL_TYPE(Name, Parent) case TypeKind::Name:
#define TYPE(Name, Parent)
#include "swift/AST/TypeNodes.def"
case TypeKind::Error:
case TypeKind::InOut:
case TypeKind::Module:
case TypeKind::Enum:
case TypeKind::Struct:
case TypeKind::Protocol:
case TypeKind::ProtocolComposition:
case TypeKind::BoundGenericEnum:
case TypeKind::BoundGenericStruct:
case TypeKind::GenericFunction:
case TypeKind::GenericTypeParam:
case TypeKind::DependentMember:
break;
}
// "Catch all" coercions.
auto desugaredToType = toType->getDesugaredType();
switch (desugaredToType->getKind()) {
// Coercions from a type to an existential type.
case TypeKind::ExistentialMetatype:
case TypeKind::ProtocolComposition:
case TypeKind::Protocol:
return coerceExistential(expr, toType);
// Coercion to Optional<T>.
case TypeKind::BoundGenericEnum: {
auto toGenericType = cast<BoundGenericEnumType>(desugaredToType);
if (!toGenericType->getDecl()->isOptionalDecl())
break;
TypeChecker::requireOptionalIntrinsics(ctx, expr->getLoc());
if (cs.getType(expr)->getOptionalObjectType())
return coerceOptionalToOptional(expr, toType, locator, typeFromPattern);
Type valueType = toGenericType->getGenericArgs()[0];
expr = coerceToType(expr, valueType, locator);
if (!expr) return nullptr;
auto *result = cs.cacheType(new (ctx) InjectIntoOptionalExpr(expr, toType));
diagnoseOptionalInjection(result);
return result;
}
#define SUGARED_TYPE(Name, Parent) case TypeKind::Name:
#define BUILTIN_TYPE(Name, Parent) case TypeKind::Name:
#define UNCHECKED_TYPE(Name, Parent) case TypeKind::Name:
#define ARTIFICIAL_TYPE(Name, Parent) case TypeKind::Name:
#define TYPE(Name, Parent)
#include "swift/AST/TypeNodes.def"
case TypeKind::Error:
case TypeKind::Module:
case TypeKind::Tuple:
case TypeKind::Enum:
case TypeKind::Struct:
case TypeKind::Class:
case TypeKind::BoundGenericClass:
case TypeKind::BoundGenericStruct:
case TypeKind::Metatype:
case TypeKind::DynamicSelf:
case TypeKind::PrimaryArchetype:
case TypeKind::OpenedArchetype:
case TypeKind::NestedArchetype:
case TypeKind::OpaqueTypeArchetype:
case TypeKind::GenericTypeParam:
case TypeKind::DependentMember:
case TypeKind::Function:
case TypeKind::GenericFunction:
case TypeKind::LValue:
case TypeKind::InOut:
break;
}
// Unresolved types come up in diagnostics for lvalue and inout types.
if (fromType->hasUnresolvedType() || toType->hasUnresolvedType())
return cs.cacheType(new (ctx) UnresolvedTypeConversionExpr(expr, toType));
// Use an opaque type to abstract a value of the underlying concrete type.
if (toType->getAs<OpaqueTypeArchetypeType>()) {
return cs.cacheType(new (ctx) UnderlyingToOpaqueExpr(expr, toType));
}
llvm_unreachable("Unhandled coercion");
}
/// Detect if the expression is an assignment to a `self` wrapped property that
/// has a nonmutating setter, inside a constructor.
///
/// We use this to decide when to produce an inout_expr instead of a load_expr
/// for the sake of emitting a reference required by the assign_by_wrapper
/// instruction.
static bool isNonMutatingSetterPWAssignInsideInit(Expr *baseExpr,
ValueDecl *member,
DeclContext *UseDC) {
// Setter is mutating
if (cast<AbstractStorageDecl>(member)->isSetterMutating())
return false;
// Member is not a wrapped property
auto *VD = dyn_cast<VarDecl>(member);
if (!(VD && VD->hasAttachedPropertyWrapper()))
return false;
// This is not an expression inside a constructor
auto *CD = dyn_cast<ConstructorDecl>(UseDC);
if (!CD)
return false;
// This is not an assignment on self
if (!baseExpr->isSelfExprOf(CD))
return false;
return true;
}
/// Adjust the given type to become the self type when referring to
/// the given member.
static Type adjustSelfTypeForMember(Expr *baseExpr,
Type baseTy, ValueDecl *member,
DeclContext *UseDC) {
assert(!baseTy->is<LValueType>());
auto inOutTy = baseTy->getAs<InOutType>();
if (!inOutTy)
return baseTy;
auto baseObjectTy = inOutTy->getObjectType();
if (isa<ConstructorDecl>(member))
return baseObjectTy;
if (auto func = dyn_cast<FuncDecl>(member)) {
// If 'self' is an inout type, turn the base type into an lvalue
// type with the same qualifiers.
if (func->isMutating())
return baseTy;
// Otherwise, return the rvalue type.
return baseObjectTy;
}
// If the base of the access is mutable, then we may be invoking a getter or
// setter that requires the base to be mutable.
auto *SD = cast<AbstractStorageDecl>(member);
bool isSettableFromHere =
SD->isSettable(UseDC) && SD->isSetterAccessibleFrom(UseDC);
// If neither the property's getter nor its setter are mutating, and
// this is not a nonmutating property wrapper setter,
// the base can be an rvalue.
// With the exception of assignments to a wrapped property inside a
// constructor, where we need to produce a reference to be used on
// the assign_by_wrapper instruction.
if (!SD->isGetterMutating() &&
(!isSettableFromHere || !SD->isSetterMutating()) &&
!isNonMutatingSetterPWAssignInsideInit(baseExpr, member, UseDC))
return baseObjectTy;
if (isa<SubscriptDecl>(member))
return baseTy;
return LValueType::get(baseObjectTy);
}
Expr *
ExprRewriter::coerceSelfArgumentToType(Expr *expr,
Type baseTy, ValueDecl *member,
ConstraintLocatorBuilder locator) {
Type toType = adjustSelfTypeForMember(expr, baseTy, member, dc);
// If our expression already has the right type, we're done.
Type fromType = cs.getType(expr);
if (fromType->isEqual(toType))
return expr;
// If we're coercing to an rvalue type, just do it.
auto toInOutTy = toType->getAs<InOutType>();
if (!toInOutTy)
return coerceToType(expr, toType, locator);
assert(fromType->is<LValueType>() && "Can only convert lvalues to inout");
auto &ctx = cs.getASTContext();
// Use InOutExpr to convert it to an explicit inout argument for the
// receiver.
return cs.cacheType(new (ctx) InOutExpr(expr->getStartLoc(), expr,
toInOutTy->getInOutObjectType(),
/*isImplicit*/ true));
}
Expr *ExprRewriter::convertLiteralInPlace(
LiteralExpr *literal, Type type, ProtocolDecl *protocol,
Identifier literalType, DeclName literalFuncName,
ProtocolDecl *builtinProtocol, DeclName builtinLiteralFuncName,
Diag<> brokenProtocolDiag, Diag<> brokenBuiltinProtocolDiag) {
// If coercing a literal to an unresolved type, we don't try to look up the
// witness members, just do it.
if (type->is<UnresolvedType>()) {
cs.setType(literal, type);
return literal;
}
// Check whether this literal type conforms to the builtin protocol. If so,
// initialize via the builtin protocol.
if (builtinProtocol) {
auto builtinConformance = TypeChecker::conformsToProtocol(
type, builtinProtocol, cs.DC);
if (builtinConformance) {
// Find the witness that we'll use to initialize the type via a builtin
// literal.
auto witness = builtinConformance.getWitnessByName(
type->getRValueType(), builtinLiteralFuncName);
if (!witness || !isa<AbstractFunctionDecl>(witness.getDecl()))
return nullptr;
// Form a reference to the builtin conversion function.
// Set the builtin initializer.
dyn_cast<BuiltinLiteralExpr>(literal)->setBuiltinInitializer(witness);
// The literal expression has this type.
cs.setType(literal, type);
return literal;
}
}
// This literal type must conform to the (non-builtin) protocol.
assert(protocol && "requirements should have stopped recursion");
auto conformance = TypeChecker::conformsToProtocol(type, protocol, cs.DC);
assert(conformance && "must conform to literal protocol");
// Dig out the literal type and perform a builtin literal conversion to it.
if (!literalType.empty()) {
// Extract the literal type.
Type builtinLiteralType =
conformance.getTypeWitnessByName(type, literalType);
if (builtinLiteralType->hasError())
return nullptr;
// Perform the builtin conversion.
if (!convertLiteralInPlace(literal, builtinLiteralType, nullptr,
Identifier(), DeclName(), builtinProtocol,
builtinLiteralFuncName, brokenProtocolDiag,
brokenBuiltinProtocolDiag))
return nullptr;
}
// Find the witness that we'll use to initialize the literal value.
auto witness =
conformance.getWitnessByName(type->getRValueType(), literalFuncName);
if (!witness || !isa<AbstractFunctionDecl>(witness.getDecl()))
return nullptr;
// Set the initializer.
literal->setInitializer(witness);
// The literal expression has this type.
cs.setType(literal, type);
return literal;
}
// Returns true if the given method and method type are a valid
// `@dynamicCallable` required `func dynamicallyCall` method.
static bool isValidDynamicCallableMethod(FuncDecl *method,
AnyFunctionType *methodType) {
auto &ctx = method->getASTContext();
if (method->getBaseIdentifier() != ctx.Id_dynamicallyCall)
return false;
if (methodType->getParams().size() != 1)
return false;
auto argumentLabel = methodType->getParams()[0].getLabel();
if (argumentLabel != ctx.Id_withArguments &&
argumentLabel != ctx.Id_withKeywordArguments)
return false;
return true;
}
// Build a reference to a `callAsFunction` method.
static Expr *buildCallAsFunctionMethodRef(
ExprRewriter &rewriter, ApplyExpr *apply, SelectedOverload selected,
ConstraintLocator *calleeLoc) {
assert(calleeLoc->isLastElement<LocatorPathElt::ImplicitCallAsFunction>());
assert(cast<FuncDecl>(selected.choice.getDecl())->isCallAsFunctionMethod());
// Create direct reference to `callAsFunction` method.
auto *fn = apply->getFn();
auto *arg = apply->getArg();
// HACK: Temporarily push the fn expr onto the expr stack to make sure we
// don't try to prematurely close an existential when applying the curried
// member ref. This can be removed once existential opening is refactored not
// to rely on the shape of the AST prior to rewriting.
rewriter.ExprStack.push_back(fn);
SWIFT_DEFER {
rewriter.ExprStack.pop_back();
};
auto *declRef = rewriter.buildMemberRef(
fn, /*dotLoc*/ SourceLoc(), selected, DeclNameLoc(arg->getStartLoc()),
calleeLoc, calleeLoc, /*implicit*/ true, AccessSemantics::Ordinary);
if (!declRef)
return nullptr;
declRef->setImplicit(apply->isImplicit());
return declRef;
}
// Resolve `@dynamicCallable` applications.
std::pair<Expr *, Expr *>
ExprRewriter::buildDynamicCallable(ApplyExpr *apply, SelectedOverload selected,
FuncDecl *method,
AnyFunctionType *methodType,
ConstraintLocatorBuilder loc) {
auto &ctx = cs.getASTContext();
auto *fn = apply->getFn();
TupleExpr *arg = dyn_cast<TupleExpr>(apply->getArg());
if (auto parenExpr = dyn_cast<ParenExpr>(apply->getArg()))
arg = TupleExpr::createImplicit(ctx, parenExpr->getSubExpr(), {});
// Get resolved `dynamicallyCall` method and verify it.
assert(isValidDynamicCallableMethod(method, methodType));
auto params = methodType->getParams();
auto argumentType = params[0].getParameterType();
// Determine which method was resolved: a `withArguments` method or a
// `withKeywordArguments` method.
auto argumentLabel = methodType->getParams()[0].getLabel();
bool useKwargsMethod = argumentLabel == ctx.Id_withKeywordArguments;
// HACK: Temporarily push the fn expr onto the expr stack to make sure we
// don't try to prematurely close an existential when applying the curried
// member ref. This can be removed once existential opening is refactored not
// to rely on the shape of the AST prior to rewriting.
ExprStack.push_back(fn);
SWIFT_DEFER {
ExprStack.pop_back();
};
// Construct expression referencing the `dynamicallyCall` method.
auto member = buildMemberRef(fn, SourceLoc(), selected,
DeclNameLoc(), loc, loc,
/*implicit=*/true, AccessSemantics::Ordinary);
// Construct argument to the method (either an array or dictionary
// expression).
Expr *argument = nullptr;
if (!useKwargsMethod) {
argument = ArrayExpr::create(ctx, SourceLoc(), arg->getElements(),
{}, SourceLoc());
cs.setType(argument, argumentType);
finishArrayExpr(cast<ArrayExpr>(argument));
} else {
auto dictLitProto =
ctx.getProtocol(KnownProtocolKind::ExpressibleByDictionaryLiteral);
auto conformance =
TypeChecker::conformsToProtocol(argumentType, dictLitProto, cs.DC);
auto keyType = conformance.getTypeWitnessByName(argumentType, ctx.Id_Key);
auto valueType =
conformance.getTypeWitnessByName(argumentType, ctx.Id_Value);
SmallVector<Identifier, 4> names;
SmallVector<Expr *, 4> dictElements;
for (unsigned i = 0, n = arg->getNumElements(); i < n; ++i) {
Expr *labelExpr =
new (ctx) StringLiteralExpr(arg->getElementName(i).get(),
arg->getElementNameLoc(i),
/*Implicit*/ true);
cs.setType(labelExpr, keyType);
handleStringLiteralExpr(cast<LiteralExpr>(labelExpr));
Expr *valueExpr = coerceToType(arg->getElement(i), valueType, loc);
assert(valueExpr && "Failed to coerce?");
Expr *pair = TupleExpr::createImplicit(ctx, {labelExpr, valueExpr}, {});
auto eltTypes = { TupleTypeElt(keyType), TupleTypeElt(valueType) };
cs.setType(pair, TupleType::get(eltTypes, ctx));
dictElements.push_back(pair);
}
argument = DictionaryExpr::create(ctx, SourceLoc(), dictElements, {},
SourceLoc());
cs.setType(argument, argumentType);
finishDictionaryExpr(cast<DictionaryExpr>(argument));
}
argument->setImplicit();
// Build the argument list expr.
argument = TupleExpr::createImplicit(ctx, {argument}, {argumentLabel});
cs.setType(argument,
TupleType::get({TupleTypeElt(argumentType, argumentLabel)}, ctx));
return std::make_pair(member, argument);
}
Expr *ExprRewriter::finishApply(ApplyExpr *apply, Type openedType,
ConstraintLocatorBuilder locator,
ConstraintLocatorBuilder calleeLocator) {
auto &ctx = cs.getASTContext();
auto *arg = apply->getArg();
auto *fn = apply->getFn();
auto finishApplyOfDeclWithSpecialTypeCheckingSemantics
= [&](ApplyExpr *apply,
ConcreteDeclRef declRef,
Type openedType) -> Expr* {
switch (TypeChecker::getDeclTypeCheckingSemantics(declRef.getDecl())) {
case DeclTypeCheckingSemantics::TypeOf: {
// Resolve into a DynamicTypeExpr.
auto arg = apply->getArg();
SmallVector<Identifier, 2> argLabelsScratch;
auto fnType = cs.getType(fn)->getAs<FunctionType>();
arg = coerceCallArguments(arg, fnType, declRef,
apply,
apply->getArgumentLabels(argLabelsScratch),
locator.withPathElement(
ConstraintLocator::ApplyArgument));
if (!arg) {
return nullptr;
}
if (auto tuple = dyn_cast<TupleExpr>(arg))
arg = tuple->getElements()[0];
auto replacement = new (ctx)
DynamicTypeExpr(apply->getFn()->getLoc(),
apply->getArg()->getStartLoc(),
arg,
apply->getArg()->getEndLoc(),
Type());
cs.setType(replacement, simplifyType(openedType));
return replacement;
}
case DeclTypeCheckingSemantics::WithoutActuallyEscaping: {
// Resolve into a MakeTemporarilyEscapableExpr.
auto arg = cast<TupleExpr>(apply->getArg());
assert(arg->getNumElements() == 2 && "should have two arguments");
auto nonescaping = arg->getElements()[0];
auto body = arg->getElements()[1];
auto bodyTy = cs.getType(body)->getWithoutSpecifierType();
auto bodyFnTy = bodyTy->castTo<FunctionType>();
auto escapableParams = bodyFnTy->getParams();
auto resultType = bodyFnTy->getResult();
// The body is immediately called, so is obviously noescape.
bodyFnTy = cast<FunctionType>(
bodyFnTy->withExtInfo(bodyFnTy->getExtInfo().withNoEscape()));
body = coerceToType(body, bodyFnTy, locator);
assert(body && "can't make nonescaping?!");
auto escapable = new (ctx)
OpaqueValueExpr(apply->getFn()->getSourceRange(), Type());
cs.setType(escapable, escapableParams[0].getOldType());
auto getType = [&](Expr *E) -> Type { return cs.getType(E); };
auto callSubExpr = CallExpr::createImplicit(ctx, body,
{escapable}, {}, getType);
cs.cacheSubExprTypes(callSubExpr);
cs.setType(callSubExpr->getArg(),
AnyFunctionType::composeInput(ctx,
escapableParams, false));
cs.setType(callSubExpr, resultType);
auto replacement = new (ctx)
MakeTemporarilyEscapableExpr(apply->getFn()->getLoc(),
apply->getArg()->getStartLoc(),
nonescaping,
callSubExpr,
apply->getArg()->getEndLoc(),
escapable,
apply);
cs.setType(replacement, resultType);
return replacement;
}
case DeclTypeCheckingSemantics::OpenExistential: {
// Resolve into an OpenExistentialExpr.
auto arg = cast<TupleExpr>(apply->getArg());
assert(arg->getNumElements() == 2 && "should have two arguments");
auto existential = cs.coerceToRValue(arg->getElements()[0]);
auto body = cs.coerceToRValue(arg->getElements()[1]);
auto bodyFnTy = cs.getType(body)->castTo<FunctionType>();
auto openedTy = getBaseType(bodyFnTy, /*wantsRValue*/ false);
auto resultTy = bodyFnTy->getResult();
// The body is immediately called, so is obviously noescape.
bodyFnTy = cast<FunctionType>(
bodyFnTy->withExtInfo(bodyFnTy->getExtInfo().withNoEscape()));
body = coerceToType(body, bodyFnTy, locator);
assert(body && "can't make nonescaping?!");
auto openedInstanceTy = openedTy;
auto existentialInstanceTy = cs.getType(existential);
if (auto metaTy = openedTy->getAs<MetatypeType>()) {
openedInstanceTy = metaTy->getInstanceType();
existentialInstanceTy = existentialInstanceTy
->castTo<ExistentialMetatypeType>()
->getInstanceType();
}
assert(openedInstanceTy->castTo<OpenedArchetypeType>()
->getOpenedExistentialType()
->isEqual(existentialInstanceTy));
auto opaqueValue =
new (ctx) OpaqueValueExpr(apply->getSourceRange(), openedTy);
cs.setType(opaqueValue, openedTy);
auto getType = [&](Expr *E) -> Type { return cs.getType(E); };
auto callSubExpr = CallExpr::createImplicit(ctx, body, {opaqueValue}, {}, getType);
cs.cacheSubExprTypes(callSubExpr);
cs.setType(callSubExpr, resultTy);
auto replacement = new (ctx)
OpenExistentialExpr(existential, opaqueValue, callSubExpr,
resultTy);
cs.setType(replacement, resultTy);
return replacement;
}
case DeclTypeCheckingSemantics::Normal:
return nullptr;
}
llvm_unreachable("Unhandled DeclTypeCheckingSemantics in switch.");
};
// Resolve the callee for the application if we have one.
ConcreteDeclRef callee;
auto *calleeLoc = cs.getConstraintLocator(calleeLocator);
auto overload = solution.getOverloadChoiceIfAvailable(calleeLoc);
if (overload) {
auto *decl = overload->choice.getDeclOrNull();
callee = resolveConcreteDeclRef(decl, calleeLoc);
}
// If this is an implicit call to a `callAsFunction` method, build the
// appropriate member reference.
if (cs.getType(fn)->getRValueType()->isCallableNominalType(dc)) {
fn = buildCallAsFunctionMethodRef(*this, apply, *overload, calleeLoc);
if (!fn)
return nullptr;
}
// Resolve a `@dynamicCallable` application.
auto applyFunctionLoc =
locator.withPathElement(ConstraintLocator::ApplyFunction);
if (auto selected = solution.getOverloadChoiceIfAvailable(
cs.getConstraintLocator(applyFunctionLoc))) {
auto *method = dyn_cast<FuncDecl>(selected->choice.getDecl());
auto methodType =
simplifyType(selected->openedType)->getAs<AnyFunctionType>();
if (method && methodType) {
// Handle a call to a @dynamicCallable method.
if (isValidDynamicCallableMethod(method, methodType))
std::tie(fn, arg) = buildDynamicCallable(
apply, *selected, method, methodType, applyFunctionLoc);
}
}
// The function is always an rvalue.
fn = cs.coerceToRValue(fn);
// Resolve applications of decls with special semantics.
if (auto declRef =
dyn_cast<DeclRefExpr>(getSemanticExprForDeclOrMemberRef(fn))) {
if (auto special =
finishApplyOfDeclWithSpecialTypeCheckingSemantics(apply,
declRef->getDeclRef(),
openedType)) {
return special;
}
}
bool unwrapResult = false;
if (auto *IUOFnTy = dyn_cast<ImplicitlyUnwrappedFunctionConversionExpr>(fn)) {
unwrapResult = true;
fn = IUOFnTy->getSubExpr();
}
// If we're applying a function that resulted from a covariant
// function conversion, strip off that conversion.
// FIXME: It would be nicer if we could build the ASTs properly in the
// first shot.
Type covariantResultType;
if (auto covariant = dyn_cast<CovariantFunctionConversionExpr>(fn)) {
// Strip off one layer of application from the covariant result.
covariantResultType
= cs.getType(covariant)->castTo<AnyFunctionType>()->getResult();
// Use the subexpression as the function.
fn = covariant->getSubExpr();
}
// An immediate application of a closure literal is always noescape.
if (isClosureLiteralExpr(fn)) {
if (auto fnTy = cs.getType(fn)->getAs<FunctionType>()) {
fnTy = cast<FunctionType>(
fnTy->withExtInfo(fnTy->getExtInfo().withNoEscape()));
fn = coerceToType(fn, fnTy, locator);
}
}
apply->setFn(fn);
// Check whether the argument is 'super'.
bool isSuper = apply->getArg()->isSuperExpr();
// For function application, convert the argument to the input type of
// the function.
SmallVector<Identifier, 2> argLabelsScratch;
if (auto fnType = cs.getType(fn)->getAs<FunctionType>()) {
arg = coerceCallArguments(arg, fnType, callee, apply,
apply->getArgumentLabels(argLabelsScratch),
locator.withPathElement(
ConstraintLocator::ApplyArgument));
if (!arg) {
return nullptr;
}
apply->setArg(arg);
cs.setType(apply, fnType->getResult());
apply->setIsSuper(isSuper);
solution.setExprTypes(apply);
Expr *result = TypeChecker::substituteInputSugarTypeForResult(apply);
cs.cacheExprTypes(result);
// If we have a covariant result type, perform the conversion now.
if (covariantResultType) {
if (covariantResultType->is<FunctionType>())
result = cs.cacheType(new (ctx) CovariantFunctionConversionExpr(
result, covariantResultType));
else
result = cs.cacheType(new (ctx) CovariantReturnConversionExpr(
result, covariantResultType));
}
// Try closing the existential, if there is one.
closeExistential(result, locator);
if (unwrapResult)
return forceUnwrapResult(result);
return result;
}
// FIXME: handle unwrapping everywhere else
assert(!unwrapResult);
// If this is an UnresolvedType in the system, preserve it.
if (cs.getType(fn)->is<UnresolvedType>()) {
cs.setType(apply, cs.getType(fn));
return apply;
}
// We have a type constructor.
auto metaTy = cs.getType(fn)->castTo<AnyMetatypeType>();
auto ty = metaTy->getInstanceType();
// If we're "constructing" a tuple type, it's simply a conversion.
if (auto tupleTy = ty->getAs<TupleType>()) {
// FIXME: Need an AST to represent this properly.
return coerceToType(apply->getArg(), tupleTy, locator);
}
// We're constructing a value of nominal type. Look for the constructor or
// enum element to use.
auto *ctorLocator =
cs.getConstraintLocator(locator, {ConstraintLocator::ApplyFunction,
ConstraintLocator::ConstructorMember});
auto selected = solution.getOverloadChoiceIfAvailable(ctorLocator);
if (!selected) {
assert(ty->hasError() || ty->hasUnresolvedType());
cs.setType(apply, ty);
return apply;
}
assert(ty->getNominalOrBoundGenericNominal() || ty->is<DynamicSelfType>() ||
ty->isExistentialType() || ty->is<ArchetypeType>());
// Consider the constructor decl reference expr 'implicit', but the
// constructor call expr itself has the apply's 'implicitness'.
Expr *declRef = buildMemberRef(fn, /*dotLoc=*/SourceLoc(), *selected,
DeclNameLoc(fn->getEndLoc()), locator,
ctorLocator, /*implicit=*/true,
AccessSemantics::Ordinary);
if (!declRef)
return nullptr;
declRef->setImplicit(apply->isImplicit());
apply->setFn(declRef);
// Tail-recur to actually call the constructor.
return finishApply(apply, openedType, locator, ctorLocator);
}
// Return the precedence-yielding parent of 'expr', along with the index of
// 'expr' as the child of that parent. The precedence-yielding parent is the
// nearest ancestor of 'expr' which imposes a minimum precedence on 'expr'.
// Right now that just means skipping over TupleExpr instances that only exist
// to hold arguments to binary operators.
static std::pair<Expr *, unsigned> getPrecedenceParentAndIndex(Expr *expr,
Expr *rootExpr)
{
auto parentMap = rootExpr->getParentMap();
auto it = parentMap.find(expr);
if (it == parentMap.end()) {
return { nullptr, 0 };
}
Expr *parent = it->second;
// Handle all cases where the answer isn't just going to be { parent, 0 }.
if (auto tuple = dyn_cast<TupleExpr>(parent)) {
// Get index of expression in tuple.
auto tupleElems = tuple->getElements();
auto elemIt = std::find(tupleElems.begin(), tupleElems.end(), expr);
assert(elemIt != tupleElems.end() && "expr not found in parent TupleExpr");
unsigned index = elemIt - tupleElems.begin();
it = parentMap.find(parent);
if (it != parentMap.end()) {
Expr *gparent = it->second;
// Was this tuple just constructed for a binop?
if (isa<BinaryExpr>(gparent)) {
return { gparent, index };
}
}
// Must be a tuple literal, function arg list, collection, etc.
return { parent, index };
} else if (auto ifExpr = dyn_cast<IfExpr>(parent)) {
unsigned index;
if (expr == ifExpr->getCondExpr()) {
index = 0;
} else if (expr == ifExpr->getThenExpr()) {
index = 1;
} else if (expr == ifExpr->getElseExpr()) {
index = 2;
} else {
llvm_unreachable("expr not found in parent IfExpr");
}
return { ifExpr, index };
} else if (auto assignExpr = dyn_cast<AssignExpr>(parent)) {
unsigned index;
if (expr == assignExpr->getSrc()) {
index = 0;
} else if (expr == assignExpr->getDest()) {
index = 1;
} else {
llvm_unreachable("expr not found in parent AssignExpr");
}
return { assignExpr, index };
}
return { parent, 0 };
}
/// Return true if, when replacing "<expr>" with "<expr> op <something>",
/// parentheses must be added around "<expr>" to allow the new operator
/// to bind correctly.
bool swift::exprNeedsParensInsideFollowingOperator(
DeclContext *DC, Expr *expr,
PrecedenceGroupDecl *followingPG) {
if (expr->isInfixOperator()) {
auto exprPG = TypeChecker::lookupPrecedenceGroupForInfixOperator(DC, expr);
if (!exprPG) return true;
return DC->getASTContext().associateInfixOperators(exprPG, followingPG)
!= Associativity::Left;
}
// We want to parenthesize a 'try?' on the LHS, but we don't care about
// capturing the new operator inside a 'try' or 'try!'.
if (isa<OptionalTryExpr>(expr))
return true;
return false;
}
/// Return true if, when replacing "<expr>" with "<expr> op <something>"
/// within the given root expression, parentheses must be added around
/// the new operator to prevent it from binding incorrectly in the
/// surrounding context.
bool swift::exprNeedsParensOutsideFollowingOperator(
DeclContext *DC, Expr *expr, Expr *rootExpr,
PrecedenceGroupDecl *followingPG) {
Expr *parent;
unsigned index;
std::tie(parent, index) = getPrecedenceParentAndIndex(expr, rootExpr);
if (!parent || isa<TupleExpr>(parent)) {
return false;
}
if (auto parenExp = dyn_cast<ParenExpr>(parent))
if (!parenExp->isImplicit())
return false;
if (parent->isInfixOperator()) {
auto parentPG = TypeChecker::lookupPrecedenceGroupForInfixOperator(DC,
parent);
if (!parentPG) return true;
// If the index is 0, this is on the LHS of the parent.
auto &Context = DC->getASTContext();
if (index == 0) {
return Context.associateInfixOperators(followingPG, parentPG)
!= Associativity::Left;
} else {
return Context.associateInfixOperators(parentPG, followingPG)
!= Associativity::Right;
}
}
return true;
}
bool swift::exprNeedsParensBeforeAddingNilCoalescing(DeclContext *DC,
Expr *expr) {
auto &ctx = DC->getASTContext();
auto asPG = TypeChecker::lookupPrecedenceGroup(
DC, ctx.Id_NilCoalescingPrecedence, SourceLoc())
.getSingle();
if (!asPG)
return true;
return exprNeedsParensInsideFollowingOperator(DC, expr, asPG);
}
bool swift::exprNeedsParensAfterAddingNilCoalescing(DeclContext *DC,
Expr *expr,
Expr *rootExpr) {
auto &ctx = DC->getASTContext();
auto asPG = TypeChecker::lookupPrecedenceGroup(
DC, ctx.Id_NilCoalescingPrecedence, SourceLoc())
.getSingle();
if (!asPG)
return true;
return exprNeedsParensOutsideFollowingOperator(DC, expr, rootExpr, asPG);
}
namespace {
class SetExprTypes : public ASTWalker {
const Solution &solution;
public:
explicit SetExprTypes(const Solution &solution)
: solution(solution) {}
Expr *walkToExprPost(Expr *expr) override {
auto &cs = solution.getConstraintSystem();
auto exprType = cs.getType(expr);
exprType = solution.simplifyType(exprType);
// assert((!expr->getType() || expr->getType()->isEqual(exprType)) &&
// "Mismatched types!");
assert(!exprType->hasTypeVariable() &&
"Should not write type variable into expression!");
assert(!exprType->hasHole() &&
"Should not write type holes into expression!");
expr->setType(exprType);
if (auto kp = dyn_cast<KeyPathExpr>(expr)) {
for (auto i : indices(kp->getComponents())) {
Type componentType;
if (cs.hasType(kp, i)) {
componentType = solution.simplifyType(cs.getType(kp, i));
assert(!componentType->hasTypeVariable() &&
"Should not write type variable into key-path component");
assert(!componentType->hasHole() &&
"Should not write type hole into key-path component");
kp->getMutableComponents()[i].setComponentType(componentType);
}
}
}
return expr;
}
/// Ignore statements.
std::pair<bool, Stmt *> walkToStmtPre(Stmt *stmt) override {
return { false, stmt };
}
/// Ignore declarations.
bool walkToDeclPre(Decl *decl) override { return false; }
};
class ExprWalker : public ASTWalker {
ExprRewriter &Rewriter;
SmallVector<ClosureExpr *, 4> ClosuresToTypeCheck;
SmallVector<std::pair<TapExpr *, DeclContext *>, 4> TapsToTypeCheck;
public:
ExprWalker(ExprRewriter &Rewriter) : Rewriter(Rewriter) { }
const SmallVectorImpl<ClosureExpr *> &getClosuresToTypeCheck() const {
return ClosuresToTypeCheck;
}
const SmallVectorImpl<std::pair<TapExpr *, DeclContext *>> &getTapsToTypeCheck() const {
return TapsToTypeCheck;
}
std::pair<bool, Expr *> walkToExprPre(Expr *expr) override {
// For closures, update the parameter types and check the body.
if (auto closure = dyn_cast<ClosureExpr>(expr)) {
rewriteFunction(closure);
return { false, closure };
}
if (auto tap = dyn_cast_or_null<TapExpr>(expr)) {
// We remember the DeclContext because the code to handle
// single-expression-body closures above changes it.
TapsToTypeCheck.push_back(std::make_pair(tap, Rewriter.dc));
}
if (auto captureList = dyn_cast<CaptureListExpr>(expr)) {
// Rewrite captures.
for (const auto &capture : captureList->getCaptureList()) {
(void)rewriteTarget(SolutionApplicationTarget(capture.Init));
}
}
Rewriter.walkToExprPre(expr);
return { true, expr };
}
Expr *walkToExprPost(Expr *expr) override {
return Rewriter.walkToExprPost(expr);
}
/// Ignore statements.
std::pair<bool, Stmt *> walkToStmtPre(Stmt *stmt) override {
return { false, stmt };
}
/// Ignore declarations.
bool walkToDeclPre(Decl *decl) override { return false; }
/// Rewrite the target, producing a new target.
Optional<SolutionApplicationTarget>
rewriteTarget(SolutionApplicationTarget target);
/// Rewrite the function for the given solution.
///
/// \returns true if an error occurred.
bool rewriteFunction(AnyFunctionRef fn) {
auto result = Rewriter.cs.applySolution(
Rewriter.solution, fn, Rewriter.dc,
[&](SolutionApplicationTarget target) {
auto resultTarget = rewriteTarget(target);
if (resultTarget) {
if (auto expr = resultTarget->getAsExpr())
Rewriter.solution.setExprTypes(expr);
}
return resultTarget;
});
switch (result) {
case SolutionApplicationToFunctionResult::Success:
return false;
case SolutionApplicationToFunctionResult::Failure:
return true;
case SolutionApplicationToFunctionResult::Delay: {
if (!Rewriter.cs.Options
.contains(ConstraintSystemFlags::LeaveClosureBodyUnchecked)) {
auto closure = cast<ClosureExpr>(fn.getAbstractClosureExpr());
ClosuresToTypeCheck.push_back(closure);
}
return false;
}
}
}
};
} // end anonymous namespace
Expr *ConstraintSystem::coerceToRValue(Expr *expr) {
return TypeChecker::coerceToRValue(
getASTContext(), expr, [&](Expr *expr) { return getType(expr); },
[&](Expr *expr, Type type) { setType(expr, type); });
}
namespace {
/// Function object to compare source locations, putting invalid
/// locations at the end.
class CompareExprSourceLocs {
SourceManager &sourceMgr;
public:
explicit CompareExprSourceLocs(SourceManager &sourceMgr)
: sourceMgr(sourceMgr) { }
bool operator()(ASTNode lhs, ASTNode rhs) const {
if (static_cast<bool>(lhs) != static_cast<bool>(rhs)) {
return static_cast<bool>(lhs);
}
auto lhsLoc = getLoc(lhs);
auto rhsLoc = getLoc(rhs);
if (lhsLoc.isValid() != rhsLoc.isValid())
return lhsLoc.isValid();
return sourceMgr.isBeforeInBuffer(lhsLoc, rhsLoc);
}
};
}
/// Emit the fixes computed as part of the solution, returning true if we were
/// able to emit an error message, or false if none of the fixits worked out.
bool ConstraintSystem::applySolutionFixes(const Solution &solution) {
/// Collect the fixes on a per-expression basis.
llvm::SmallDenseMap<ASTNode, SmallVector<ConstraintFix *, 4>> fixesPerAnchor;
for (auto *fix : solution.Fixes) {
fixesPerAnchor[fix->getAnchor()].push_back(fix);
}
// Collect all of the expressions that have fixes, and sort them by
// source ordering.
SmallVector<ASTNode, 4> orderedAnchors;
for (const auto &fix : fixesPerAnchor) {
orderedAnchors.push_back(fix.getFirst());
}
std::sort(orderedAnchors.begin(), orderedAnchors.end(),
CompareExprSourceLocs(Context.SourceMgr));
// Walk over each of the expressions, diagnosing fixes.
bool diagnosedAnyErrors = false;
for (auto anchor : orderedAnchors) {
// Coalesce fixes with the same locator to avoid duplicating notes.
auto fixes = fixesPerAnchor[anchor];
using ConstraintFixVector = llvm::SmallVector<ConstraintFix *, 4>;
llvm::SmallMapVector<ConstraintLocator *,
llvm::SmallMapVector<FixKind, ConstraintFixVector, 4>, 4> aggregatedFixes;
for (auto *fix : fixes)
aggregatedFixes[fix->getLocator()][fix->getKind()].push_back(fix);
for (auto fixesPerLocator : aggregatedFixes) {
for (auto fixesPerKind : fixesPerLocator.second) {
auto fixes = fixesPerKind.second;
auto *primaryFix = fixes[0];
ArrayRef<ConstraintFix *> secondaryFixes{fixes.begin() + 1, fixes.end()};
auto diagnosed =
primaryFix->coalesceAndDiagnose(solution, secondaryFixes);
if (primaryFix->isWarning()) {
assert(diagnosed && "warnings should always be diagnosed");
(void)diagnosed;
} else {
diagnosedAnyErrors |= diagnosed;
}
}
}
}
return diagnosedAnyErrors;
}
/// For the initializer of an `async let`, wrap it in an autoclosure and then
/// a call to that autoclosure, so that the code for the child task is captured
/// entirely within the autoclosure. This captures the semantics of the
/// operation but not the timing, e.g., the call itself will actually occur
/// when one of the variables in the async let is referenced.
static Expr *wrapAsyncLetInitializer(
ConstraintSystem &cs, Expr *initializer, DeclContext *dc) {
// Form the autoclosure type. It is always 'async', and will be 'throws'.
Type initializerType = initializer->getType();
bool throws = TypeChecker::canThrow(initializer);
auto extInfo = ASTExtInfoBuilder()
.withAsync()
.withThrows(throws)
.build();
// Form the autoclosure expression. The actual closure here encapsulates the
// child task.
auto closureType = FunctionType::get({ }, initializerType, extInfo);
ASTContext &ctx = dc->getASTContext();
Expr *autoclosureExpr = cs.buildAutoClosureExpr(
initializer, closureType, /*isDefaultWrappedValue=*/false,
/*isAsyncLetWrapper=*/true);
// Call the autoclosure so that the AST types line up. SILGen will ignore the
// actual calls and translate them into a different mechanism.
auto autoclosureCall = CallExpr::createImplicit(
ctx, autoclosureExpr, { }, { });
autoclosureCall->setType(initializerType);
autoclosureCall->setThrows(throws);
// For a throwing expression, wrap the call in a 'try'.
Expr *resultInit = autoclosureCall;
if (throws) {
resultInit = new (ctx) TryExpr(
SourceLoc(), resultInit, initializerType, /*implicit=*/true);
}
// Wrap the call in an 'await'.
resultInit = new (ctx) AwaitExpr(
SourceLoc(), resultInit, initializerType, /*implicit=*/true);
cs.cacheExprTypes(resultInit);
return resultInit;
}
/// Apply the given solution to the initialization target.
///
/// \returns the resulting initialization expression.
static Optional<SolutionApplicationTarget> applySolutionToInitialization(
Solution &solution, SolutionApplicationTarget target,
Expr *initializer) {
auto wrappedVar = target.getInitializationWrappedVar();
Type initType;
if (wrappedVar) {
initType = solution.getType(initializer);
} else {
initType = solution.getType(target.getInitializationPattern());
}
{
// Figure out what type the constraints decided on.
auto ty = solution.simplifyType(initType);
initType = ty->getRValueType()->reconstituteSugar(/*recursive =*/false);
}
// Convert the initializer to the type of the pattern.
auto &cs = solution.getConstraintSystem();
auto locator =
cs.getConstraintLocator(initializer, LocatorPathElt::ContextualType());
initializer = solution.coerceToType(initializer, initType, locator);
if (!initializer)
return None;
SolutionApplicationTarget resultTarget = target;
resultTarget.setExpr(initializer);
// Record the property wrapper type and note that the initializer has
// been subsumed by the backing property.
if (wrappedVar) {
ASTContext &ctx = cs.getASTContext();
wrappedVar->getParentPatternBinding()->setInitializerSubsumed(0);
ctx.setSideCachedPropertyWrapperBackingPropertyType(
wrappedVar, initType->mapTypeOutOfContext());
// Record the semantic initializer on the outermost property wrapper.
wrappedVar->getAttachedPropertyWrappers().front()
->setSemanticInit(initializer);
}
// Coerce the pattern to the type of the initializer.
TypeResolutionOptions options =
isa<EditorPlaceholderExpr>(initializer->getSemanticsProvidingExpr())
? TypeResolverContext::EditorPlaceholderExpr
: target.getInitializationPatternBindingDecl()
? TypeResolverContext::PatternBindingDecl
: TypeResolverContext::InExpression;
options |= TypeResolutionFlags::OverrideType;
// Determine the type of the pattern.
Type finalPatternType = initializer->getType();
if (wrappedVar) {
if (!finalPatternType->hasError() && !finalPatternType->is<TypeVariableType>())
finalPatternType = computeWrappedValueType(wrappedVar, finalPatternType);
}
if (finalPatternType->hasDependentMember())
return None;
finalPatternType = finalPatternType->reconstituteSugar(/*recursive =*/false);
// Apply the solution to the pattern as well.
auto contextualPattern = target.getContextualPattern();
if (auto coercedPattern = TypeChecker::coercePatternToType(
contextualPattern, finalPatternType, options)) {
resultTarget.setPattern(coercedPattern);
} else {
return None;
}
// For an async let, wrap the initializer appropriately to make it a child
// task.
if (auto patternBinding = target.getInitializationPatternBindingDecl()) {
if (patternBinding->isAsyncLet()) {
resultTarget.setExpr(
wrapAsyncLetInitializer(
cs, resultTarget.getAsExpr(), resultTarget.getDeclContext()));
}
}
return resultTarget;
}
/// Apply the given solution to the for-each statement target.
///
/// \returns the resulting initialization expression.
static Optional<SolutionApplicationTarget> applySolutionToForEachStmt(
Solution &solution, SolutionApplicationTarget target, Expr *sequence) {
auto resultTarget = target;
auto &forEachStmtInfo = resultTarget.getForEachStmtInfo();
// Simplify the various types.
forEachStmtInfo.elementType =
solution.simplifyType(forEachStmtInfo.elementType);
forEachStmtInfo.iteratorType =
solution.simplifyType(forEachStmtInfo.iteratorType);
forEachStmtInfo.initType =
solution.simplifyType(forEachStmtInfo.initType);
forEachStmtInfo.sequenceType =
solution.simplifyType(forEachStmtInfo.sequenceType);
// Coerce the sequence to the sequence type.
auto &cs = solution.getConstraintSystem();
auto locator = cs.getConstraintLocator(target.getAsExpr());
sequence = solution.coerceToType(
sequence, forEachStmtInfo.sequenceType, locator);
if (!sequence)
return None;
resultTarget.setExpr(sequence);
// Get the conformance of the sequence type to the Sequence protocol.
auto stmt = forEachStmtInfo.stmt;
auto sequenceProto = TypeChecker::getProtocol(
cs.getASTContext(), stmt->getForLoc(), KnownProtocolKind::Sequence);
auto contextualLocator = cs.getConstraintLocator(
target.getAsExpr(), LocatorPathElt::ContextualType());
auto sequenceConformance = solution.resolveConformance(
contextualLocator, sequenceProto);
assert(!sequenceConformance.isInvalid() &&
"Couldn't find sequence conformance");
// Coerce the pattern to the element type.
TypeResolutionOptions options(TypeResolverContext::ForEachStmt);
options |= TypeResolutionFlags::OverrideType;
// Apply the solution to the pattern as well.
auto contextualPattern = target.getContextualPattern();
if (auto coercedPattern = TypeChecker::coercePatternToType(
contextualPattern, forEachStmtInfo.initType, options)) {
resultTarget.setPattern(coercedPattern);
} else {
return None;
}
// Apply the solution to the filtering condition, if there is one.
auto dc = target.getDeclContext();
if (forEachStmtInfo.whereExpr) {
auto *boolDecl = dc->getASTContext().getBoolDecl();
assert(boolDecl);
Type boolType = boolDecl->getDeclaredInterfaceType();
assert(boolType);
SolutionApplicationTarget whereTarget(
forEachStmtInfo.whereExpr, dc, CTP_Condition, boolType,
/*isDiscarded=*/false);
auto newWhereTarget = cs.applySolution(solution, whereTarget);
if (!newWhereTarget)
return None;
forEachStmtInfo.whereExpr = newWhereTarget->getAsExpr();
}
// Invoke iterator() to get an iterator from the sequence.
ASTContext &ctx = cs.getASTContext();
VarDecl *iterator;
Type nextResultType = OptionalType::get(forEachStmtInfo.elementType);
{
// Create a local variable to capture the iterator.
std::string name;
if (auto np = dyn_cast_or_null<NamedPattern>(stmt->getPattern()))
name = "$"+np->getBoundName().str().str();
name += "$generator";
iterator = new (ctx) VarDecl(
/*IsStatic*/ false, VarDecl::Introducer::Var, stmt->getInLoc(),
ctx.getIdentifier(name), dc);
iterator->setInterfaceType(
forEachStmtInfo.iteratorType->mapTypeOutOfContext());
iterator->setImplicit();
auto genPat = new (ctx) NamedPattern(iterator);
genPat->setImplicit();
// TODO: test/DebugInfo/iteration.swift requires this extra info to
// be around.
PatternBindingDecl::createImplicit(
ctx, StaticSpellingKind::None, genPat,
new (ctx) OpaqueValueExpr(stmt->getInLoc(), nextResultType),
dc, /*VarLoc*/ stmt->getForLoc());
}
// Create the iterator variable.
auto *varRef = TypeChecker::buildCheckedRefExpr(
iterator, dc, DeclNameLoc(stmt->getInLoc()), /*implicit*/ true);
// Convert that Optional<Element> value to the type of the pattern.
auto optPatternType = OptionalType::get(forEachStmtInfo.initType);
if (!optPatternType->isEqual(nextResultType)) {
OpaqueValueExpr *elementExpr =
new (ctx) OpaqueValueExpr(stmt->getInLoc(), nextResultType,
/*isPlaceholder=*/true);
Expr *convertElementExpr = elementExpr;
if (TypeChecker::typeCheckExpression(
convertElementExpr, dc,
/*contextualInfo=*/{optPatternType, CTP_CoerceOperand})
.isNull()) {
return None;
}
elementExpr->setIsPlaceholder(false);
stmt->setElementExpr(elementExpr);
stmt->setConvertElementExpr(convertElementExpr);
}
// Write the result back into the AST.
stmt->setSequence(resultTarget.getAsExpr());
stmt->setPattern(resultTarget.getContextualPattern().getPattern());
stmt->setSequenceConformance(sequenceConformance);
stmt->setWhere(forEachStmtInfo.whereExpr);
stmt->setIteratorVar(iterator);
stmt->setIteratorVarRef(varRef);
return resultTarget;
}
Optional<SolutionApplicationTarget>
ExprWalker::rewriteTarget(SolutionApplicationTarget target) {
auto &solution = Rewriter.solution;
// Apply the solution to the target.
SolutionApplicationTarget result = target;
if (auto expr = target.getAsExpr()) {
Expr *rewrittenExpr = expr->walk(*this);
if (!rewrittenExpr)
return None;
/// Handle special cases for expressions.
switch (target.getExprContextualTypePurpose()) {
case CTP_Initialization: {
auto initResultTarget = applySolutionToInitialization(
solution, target, rewrittenExpr);
if (!initResultTarget)
return None;
result = *initResultTarget;
break;
}
case CTP_ForEachStmt: {
auto forEachResultTarget = applySolutionToForEachStmt(
solution, target, rewrittenExpr);
if (!forEachResultTarget)
return None;
result = *forEachResultTarget;
break;
}
case CTP_Unused:
case CTP_ReturnStmt:
case swift::CTP_ReturnSingleExpr:
case swift::CTP_YieldByValue:
case swift::CTP_YieldByReference:
case swift::CTP_ThrowStmt:
case swift::CTP_EnumCaseRawValue:
case swift::CTP_DefaultParameter:
case swift::CTP_AutoclosureDefaultParameter:
case swift::CTP_CalleeResult:
case swift::CTP_CallArgument:
case swift::CTP_ClosureResult:
case swift::CTP_ArrayElement:
case swift::CTP_DictionaryKey:
case swift::CTP_DictionaryValue:
case swift::CTP_CoerceOperand:
case swift::CTP_AssignSource:
case swift::CTP_SubscriptAssignSource:
case swift::CTP_Condition:
case swift::CTP_WrappedProperty:
case swift::CTP_ComposedPropertyWrapper:
case swift::CTP_CannotFail:
result.setExpr(rewrittenExpr);
break;
}
} else if (auto stmtCondition = target.getAsStmtCondition()) {
for (auto &condElement : *stmtCondition) {
switch (condElement.getKind()) {
case StmtConditionElement::CK_Availability:
continue;
case StmtConditionElement::CK_Boolean: {
auto condExpr = condElement.getBoolean();
auto finalCondExpr = condExpr->walk(*this);
if (!finalCondExpr)
return None;
// Load the condition if needed.
solution.setExprTypes(finalCondExpr);
if (finalCondExpr->getType()->hasLValueType()) {
ASTContext &ctx = solution.getConstraintSystem().getASTContext();
finalCondExpr = TypeChecker::addImplicitLoadExpr(ctx, finalCondExpr);
}
condElement.setBoolean(finalCondExpr);
continue;
}
case StmtConditionElement::CK_PatternBinding: {
ConstraintSystem &cs = solution.getConstraintSystem();
auto target = *cs.getSolutionApplicationTarget(&condElement);
auto resolvedTarget = rewriteTarget(target);
if (!resolvedTarget)
return None;
solution.setExprTypes(resolvedTarget->getAsExpr());
condElement.setInitializer(resolvedTarget->getAsExpr());
condElement.setPattern(resolvedTarget->getInitializationPattern());
continue;
}
}
}
return target;
} else if (auto caseLabelItem = target.getAsCaseLabelItem()) {
ConstraintSystem &cs = solution.getConstraintSystem();
auto info = *cs.getCaseLabelItemInfo(*caseLabelItem);
// Figure out the pattern type.
Type patternType = solution.simplifyType(solution.getType(info.pattern));
patternType = patternType->reconstituteSugar(/*recursive=*/false);
// Coerce the pattern to its appropriate type.
TypeResolutionOptions patternOptions(TypeResolverContext::InExpression);
patternOptions |= TypeResolutionFlags::OverrideType;
auto contextualPattern =
ContextualPattern::forRawPattern(info.pattern,
target.getDeclContext());
if (auto coercedPattern = TypeChecker::coercePatternToType(
contextualPattern, patternType, patternOptions)) {
(*caseLabelItem)->setPattern(coercedPattern, /*resolved=*/true);
} else {
return None;
}
// If there is a guard expression, coerce that.
if (auto guardExpr = info.guardExpr) {
guardExpr = guardExpr->walk(*this);
if (!guardExpr)
return None;
// FIXME: Feels like we could leverage existing code more.
Type boolType = cs.getASTContext().getBoolDecl()->getDeclaredInterfaceType();
guardExpr = solution.coerceToType(
guardExpr, boolType, cs.getConstraintLocator(info.guardExpr));
if (!guardExpr)
return None;
(*caseLabelItem)->setGuardExpr(guardExpr);
solution.setExprTypes(guardExpr);
}
return target;
} else if (auto patternBinding = target.getAsPatternBinding()) {
ConstraintSystem &cs = solution.getConstraintSystem();
for (unsigned index : range(patternBinding->getNumPatternEntries())) {
// Find the solution application target for this.
auto knownTarget = *cs.getSolutionApplicationTarget(
{patternBinding, index});
// Rewrite the target.
auto resultTarget = rewriteTarget(knownTarget);
if (!resultTarget)
return None;
patternBinding->setPattern(
index, resultTarget->getInitializationPattern(),
resultTarget->getDeclContext());
patternBinding->setInit(index, resultTarget->getAsExpr());
}
return target;
} else if (auto *wrappedVar = target.getAsUninitializedWrappedVar()) {
// Get the outermost wrapper type from the solution
auto outermostWrapper = wrappedVar->getAttachedPropertyWrappers().front();
auto backingType = solution.simplifyType(
solution.getType(outermostWrapper->getTypeRepr()));
auto &ctx = solution.getConstraintSystem().getASTContext();
ctx.setSideCachedPropertyWrapperBackingPropertyType(
wrappedVar, backingType->mapTypeOutOfContext());
return target;
} else {
auto fn = *target.getAsFunction();
if (rewriteFunction(fn))
return None;
result.setFunctionBody(fn.getBody());
}
// Follow-up tasks.
auto &cs = solution.getConstraintSystem();
if (auto resultExpr = result.getAsExpr()) {
Expr *expr = target.getAsExpr();
assert(expr && "Can't have expression result without expression target");
// We are supposed to use contextual type only if it is present and
// this expression doesn't represent the implicit return of the single
// expression function which got deduced to be `Never`.
Type convertType = target.getExprConversionType();
auto shouldCoerceToContextualType = [&]() {
return convertType &&
!target.isOptionalSomePatternInit() &&
!(solution.getType(resultExpr)->isUninhabited() &&
cs.getContextualTypePurpose(target.getAsExpr())
== CTP_ReturnSingleExpr);
};
// If we're supposed to convert the expression to some particular type,
// do so now.
if (shouldCoerceToContextualType()) {
resultExpr = Rewriter.coerceToType(resultExpr,
solution.simplifyType(convertType),
cs.getConstraintLocator(expr));
} else if (cs.getType(resultExpr)->hasLValueType() &&
!target.isDiscardedExpr()) {
// We referenced an lvalue. Load it.
resultExpr = Rewriter.coerceToType(
resultExpr,
cs.getType(resultExpr)->getRValueType(),
cs.getConstraintLocator(expr));
}
if (!resultExpr)
return None;
// For an @autoclosure default parameter type, add the autoclosure
// conversion.
if (FunctionType *autoclosureParamType =
target.getAsAutoclosureParamType()) {
resultExpr = cs.buildAutoClosureExpr(resultExpr, autoclosureParamType);
}
solution.setExprTypes(resultExpr);
result.setExpr(resultExpr);
if (cs.isDebugMode()) {
auto &log = llvm::errs();
log << "---Type-checked expression---\n";
resultExpr->dump(log);
log << "\n";
}
}
return result;
}
/// Apply a given solution to the expression, producing a fully
/// type-checked expression.
Optional<SolutionApplicationTarget> ConstraintSystem::applySolution(
Solution &solution, SolutionApplicationTarget target) {
// If any fixes needed to be applied to arrive at this solution, resolve
// them to specific expressions.
if (!solution.Fixes.empty()) {
if (shouldSuppressDiagnostics())
return None;
bool diagnosedErrorsViaFixes = applySolutionFixes(solution);
// If all of the available fixes would result in a warning,
// we can go ahead and apply this solution to AST.
if (!llvm::all_of(solution.Fixes, [](const ConstraintFix *fix) {
return fix->isWarning();
})) {
// If we already diagnosed any errors via fixes, that's it.
if (diagnosedErrorsViaFixes)
return None;
// If we didn't manage to diagnose anything well, so fall back to
// diagnosing mining the system to construct a reasonable error message.
diagnoseFailureFor(target);
return None;
}
}
// If there are no fixes recorded but score indicates that there
// should have been at least one, let's fail application and
// produce a fallback diagnostic to highlight the problem.
{
const auto &score = solution.getFixedScore();
if (score.Data[SK_Fix] > 0 || score.Data[SK_Hole] > 0) {
maybeProduceFallbackDiagnostic(target);
return None;
}
}
ExprRewriter rewriter(*this, solution, target, shouldSuppressDiagnostics());
ExprWalker walker(rewriter);
auto resultTarget = walker.rewriteTarget(target);
if (!resultTarget)
return None;
// Visit closures that have non-single expression bodies.
bool hadError = false;
for (auto *closure : walker.getClosuresToTypeCheck())
hadError |= TypeChecker::typeCheckClosureBody(closure);
// Tap expressions too; they should or should not be
// type-checked under the same conditions as closure bodies.
for (auto tuple : walker.getTapsToTypeCheck()) {
auto tap = std::get<0>(tuple);
auto tapDC = std::get<1>(tuple);
hadError |= TypeChecker::typeCheckTapBody(tap, tapDC);
}
// If any of them failed to type check, bail.
if (hadError)
return None;
rewriter.finalize();
return resultTarget;
}
Expr *Solution::coerceToType(Expr *expr, Type toType,
ConstraintLocator *locator,
Optional<Pattern*> typeFromPattern) {
auto &cs = getConstraintSystem();
ExprRewriter rewriter(cs, *this, None, /*suppressDiagnostics=*/false);
Expr *result = rewriter.coerceToType(expr, toType, locator, typeFromPattern);
if (!result)
return nullptr;
setExprTypes(result);
rewriter.finalize();
return result;
}
ProtocolConformanceRef Solution::resolveConformance(
ConstraintLocator *locator, ProtocolDecl *proto) {
for (const auto &conformance : Conformances) {
if (conformance.first != locator)
continue;
if (conformance.second.getRequirement() != proto)
continue;
// If the conformance doesn't require substitution, return it immediately.
auto conformanceRef = conformance.second;
if (conformanceRef.isAbstract())
return conformanceRef;
auto concrete = conformanceRef.getConcrete();
auto conformingType = concrete->getType();
if (!conformingType->hasTypeVariable())
return conformanceRef;
// Substitute into the conformance type, then look for a conformance
// again.
// FIXME: Should be able to perform the substitution using the Solution
// itself rather than another conforms-to-protocol check.
Type substConformingType = simplifyType(conformingType);
return TypeChecker::conformsToProtocol(
substConformingType, proto, constraintSystem->DC);
}
return ProtocolConformanceRef::forInvalid();
}
bool Solution::hasType(ASTNode node) const {
auto result = nodeTypes.find(node);
if (result != nodeTypes.end())
return true;
auto &cs = getConstraintSystem();
return cs.hasType(node);
}
Type Solution::getType(ASTNode node) const {
auto result = nodeTypes.find(node);
if (result != nodeTypes.end())
return result->second;
auto &cs = getConstraintSystem();
return cs.getType(node);
}
Type Solution::getResolvedType(ASTNode node) const {
return simplifyType(getType(node));
}
void Solution::setExprTypes(Expr *expr) const {
if (!expr)
return;
SetExprTypes SET(*this);
expr->walk(SET);
}
/// MARK: SolutionResult implementation.
SolutionResult SolutionResult::forSolved(Solution &&solution) {
SolutionResult result(Kind::Success);
void *memory = malloc(sizeof(Solution));
result.solutions = new (memory) Solution(std::move(solution));
result.numSolutions = 1;
return result;
}
SolutionResult SolutionResult::forAmbiguous(
MutableArrayRef<Solution> solutions) {
assert(solutions.size() > 1 && "Not actually ambiguous");
SolutionResult result(Kind::Ambiguous);
result.solutions =
(Solution *)malloc(sizeof(Solution) * solutions.size());
result.numSolutions = solutions.size();
std::uninitialized_copy(std::make_move_iterator(solutions.begin()),
std::make_move_iterator(solutions.end()),
result.solutions);
return result;
}
SolutionResult::~SolutionResult() {
assert((!requiresDiagnostic() || emittedDiagnostic) &&
"SolutionResult was destroyed without emitting a diagnostic");
for (unsigned i : range(numSolutions)) {
solutions[i].~Solution();
}
free(solutions);
}
const Solution &SolutionResult::getSolution() const {
assert(numSolutions == 1 && "Wrong number of solutions");
return solutions[0];
}
Solution &&SolutionResult::takeSolution() && {
assert(numSolutions == 1 && "Wrong number of solutions");
return std::move(solutions[0]);
}
ArrayRef<Solution> SolutionResult::getAmbiguousSolutions() const {
assert(getKind() == Ambiguous);
return makeArrayRef(solutions, numSolutions);
}
MutableArrayRef<Solution> SolutionResult::takeAmbiguousSolutions() && {
assert(getKind() == Ambiguous);
markAsDiagnosed();
return MutableArrayRef<Solution>(solutions, numSolutions);
}
SolutionApplicationTarget SolutionApplicationTarget::walk(ASTWalker &walker) {
switch (kind) {
case Kind::expression: {
SolutionApplicationTarget result = *this;
result.setExpr(getAsExpr()->walk(walker));
return result;
}
case Kind::function:
return SolutionApplicationTarget(
*getAsFunction(),
cast_or_null<BraceStmt>(getFunctionBody()->walk(walker)));
case Kind::stmtCondition:
for (auto &condElement : stmtCondition.stmtCondition) {
condElement = *condElement.walk(walker);
}
return *this;
case Kind::caseLabelItem:
if (auto newPattern =
caseLabelItem.caseLabelItem->getPattern()->walk(walker)) {
caseLabelItem.caseLabelItem->setPattern(
newPattern, caseLabelItem.caseLabelItem->isPatternResolved());
}
if (auto guardExpr = caseLabelItem.caseLabelItem->getGuardExpr()) {
if (auto newGuardExpr = guardExpr->walk(walker))
caseLabelItem.caseLabelItem->setGuardExpr(newGuardExpr);
}
return *this;
case Kind::patternBinding:
return *this;
case Kind::uninitializedWrappedVar:
return *this;
}
llvm_unreachable("invalid target kind");
}