Skip to content
Permalink
51267754fc
Switch branches/tags
Go to file
 
 
Cannot retrieve contributors at this time
8362 lines (7118 sloc) 321 KB
//===--- 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 "ConstraintSystem.h"
#include "CodeSynthesis.h"
#include "CSDiagnostics.h"
#include "MiscDiagnostics.h"
#include "SolutionResult.h"
#include "TypeCheckProtocol.h"
#include "TypeCheckType.h"
#include "swift/AST/ASTVisitor.h"
#include "swift/AST/ASTWalker.h"
#include "swift/AST/ExistentialLayout.h"
#include "swift/AST/Initializer.h"
#include "swift/AST/GenericEnvironment.h"
#include "swift/AST/GenericSignature.h"
#include "swift/AST/ParameterList.h"
#include "swift/AST/ProtocolConformance.h"
#include "swift/AST/SubstitutionMap.h"
#include "swift/Basic/StringExtras.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,
ConformanceCheckFlags::InExpression);
};
return SubstitutionMap::get(sig,
QueryTypeSubstitutionMap{subs},
lookupConformanceFn);
}
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();
return ConcreteDeclRef(decl, computeSubstitutions(sig, locator));
}
static bool shouldAccessStorageDirectly(Expr *base, VarDecl *member,
DeclContext *DC) {
// This only matters for stored properties.
if (!member->hasStorage())
return false;
// ... referenced from constructors and destructors.
auto *AFD = dyn_cast<AbstractFunctionDecl>(DC);
if (AFD == nullptr)
return false;
if (!isa<ConstructorDecl>(AFD) && !isa<DestructorDecl>(AFD))
return false;
// ... via a "self.property" reference.
auto *DRE = dyn_cast<DeclRefExpr>(base);
if (DRE == nullptr)
return false;
if (AFD->getImplicitSelfDecl() != cast<DeclRefExpr>(base)->getDecl())
return false;
// Convenience initializers do not require special handling.
// FIXME: This is a language change -- for now, keep the old behavior
#if 0
if (auto *CD = dyn_cast<ConstructorDecl>(AFD))
if (!CD->isDesignatedInit())
return false;
#endif
// Ctor or dtor are for immediate class, not a derived class.
if (!AFD->getParent()->getDeclaredInterfaceType()->isEqual(
member->getDeclContext()->getDeclaredInterfaceType()))
return false;
// If the storage is resilient, we cannot access it directly at all.
if (member->isResilient(DC->getParentModule(),
DC->getResilienceExpansion()))
return false;
return true;
}
ConstraintLocator *Solution::getCalleeLocator(ConstraintLocator *locator,
bool lookThroughApply) const {
auto &cs = getConstraintSystem();
return cs.getCalleeLocator(
locator, lookThroughApply,
[&](const Expr *expr) -> Type { return getType(expr); },
[&](Type type) -> Type { return simplifyType(type)->getRValueType(); },
[&](ConstraintLocator *locator) -> Optional<SelectedOverload> {
return getOverloadChoiceIfAvailable(locator);
});
}
ConstraintLocator *
Solution::getConstraintLocator(Expr *anchor,
ArrayRef<LocatorPathElt> path) const {
auto &cs = getConstraintSystem();
return cs.getConstraintLocator(anchor, 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) {
// Properties that have storage and accessors are frequently accessed through
// accessors. However, in the init and destructor methods for the type
// immediately containing the property, accesses are done direct.
if (shouldAccessStorageDirectly(base, member, DC)) {
// Access this directly instead of going through (e.g.) observing or
// trivial accessors.
return AccessSemantics::DirectToStorage;
}
// 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(const Expr *E) {
return E->isTypeReference(
[&](const Expr *E) -> Type { return simplifyType(getType(E)); },
[&](const 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 ConstraintSystem::isStaticallyDerivedMetatype(const Expr *E) {
return E->isStaticallyDerivedMetatype(
[&](const Expr *E) -> Type { return simplifyType(getType(E)); },
[&](const Expr *E) -> bool { return isTypeReference(E); });
}
Type ConstraintSystem::getInstanceType(const TypeExpr *E) {
return E->getInstanceType([&](const Expr *E) -> bool { return hasType(E); },
[&](const Expr *E) -> Type { return getType(E); });
}
Type ConstraintSystem::getResultType(const AbstractClosureExpr *E) {
return E->getResultType([&](const 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;
}
}
// 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;
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();
}
// 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},
TypeChecker::LookUpConformance(cs.DC));
}
public:
/// Build a reference to the given declaration.
Expr *buildDeclRef(SelectedOverload overload, DeclNameLoc loc,
ConstraintLocatorBuilder locator, bool implicit,
AccessSemantics semantics) {
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();
// 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,
/*extraUncurryLevel=*/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,
ConformanceCheckFlags::InExpression);
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, /*extraUncurryLevel=*/false,
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);
assert(ref.getDecl() == decl);
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) {
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,
bool extraUncurryLevel) {
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 1;
}
// Similarly, ".foo(...)" really applies two argument lists.
if (auto *unresolvedMemberExpr = dyn_cast<UnresolvedMemberExpr>(prev)) {
if (unresolvedMemberExpr->hasArguments() ||
unresolvedMemberExpr->hasTrailingClosure())
return 1;
return 0;
}
return getArgCount(maxArgCount);
}();
// Sometimes we build a member reference that has an implicit
// level of function application in the AST. For example,
// @dynamicCallable and callAsFunction are handled this way.
//
// FIXME: It would be nice to simplify this and the argCount
// computation above somehow.
if (extraUncurryLevel)
argCount++;
// 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 (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;
// We build either a CallExpr or a DotSyntaxCallExpr depending on whether
// the base is implicit or not. This helps maintain some invariants around
// source ranges.
if (selfParamRef->isImplicit()) {
selfCall =
CallExpr::createImplicit(context, ref, selfOpenedRef, { },
[&](const Expr *E) { return cs.getType(E); });
selfCall->setType(refTy->getResult());
cs.cacheType(selfCall);
// FIXME: This is a holdover from the old tuple-based function call
// representation.
auto selfArgTy = ParenType::get(context,
selfParam.getPlainType(),
selfParam.getParameterFlags());
selfCall->getArg()->setType(selfArgTy);
cs.cacheType(selfCall->getArg());
} else {
selfCall = new (context) DotSyntaxCallExpr(ref, SourceLoc(), selfOpenedRef);
selfCall->setImplicit(false);
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().throws()) {
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,
bool extraUncurryLevel, AccessSemantics semantics) {
auto choice = overload.choice;
auto openedType = overload.openedType;
auto openedFullType = overload.openedFullType;
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 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, simplifyType(openedFullType));
ref->setFunctionRefKind(choice.getFunctionRefKind());
auto *DSBI = cs.cacheType(new (context) DotSyntaxBaseIgnoredExpr(
base, dotLoc, ref, cs.getType(ref)));
return forceUnwrapIfExpected(DSBI, choice, 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, /*isImplicit=*/false);
cs.setType(ref, refType);
auto *result = new (context) DotSyntaxBaseIgnoredExpr(
base, dotLoc, ref, refType);
cs.setType(result, refType);
return result;
}
bool isUnboundInstanceMember =
(!baseIsInstance && member->isInstanceMember());
bool isPartialApplication =
shouldBuildCurryThunk(choice, baseIsInstance, extraUncurryLevel);
auto refTy = simplifyType(openedFullType);
// 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 = coerceObjectArgumentToType(
base, selfParamTy, member, semantics,
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->getFullName(),
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 (isa<VarDecl>(member)) {
if (isUnboundInstanceMember) {
assert(memberLocator.getBaseLocator() &&
cs.UnevaluatedRootExprs.count(
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 memberRefExpr
= new (context) MemberRefExpr(base, dotLoc, memberRef,
memberLoc, Implicit, semantics);
memberRefExpr->setIsSuper(isSuper);
cs.setType(memberRefExpr, simplifyType(openedType));
Expr *result = memberRefExpr;
closeExistential(result, locator);
if (cast<VarDecl>(member)->getValueInterfaceType()
->hasDynamicSelfType()) {
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(Expr *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);
// Resolve `@dynamicCallable` applications.
Expr *finishApplyDynamicCallable(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 a closure expression with a non-Void return type to a
/// contextual function type with a Void return type.
///
/// This operation cannot fail.
///
/// \param expr The closure expression to coerce.
///
/// \returns The coerced closure expression.
///
ClosureExpr *coerceClosureExprToVoid(ClosureExpr *expr);
/// Coerce a closure expression with a Never return type to a
/// contextual function type with some other return type.
///
/// This operation cannot fail.
///
/// \param expr The closure expression to coerce.
///
/// \returns The coerced closure expression.
///
ClosureExpr *coerceClosureExprFromNever(ClosureExpr *expr);
/// 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 hasTrailingClosure Whether the last argument is a trailing
/// closure.
/// \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,
bool hasTrailingClosure,
ConstraintLocatorBuilder locator);
/// Coerce the given object 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 semantics The kind of access we've been asked to perform.
///
/// \param locator Locator used to describe where in this expression we are.
Expr *coerceObjectArgumentToType(Expr *expr,
Type baseTy, ValueDecl *member,
AccessSemantics semantics,
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 &&
!isa<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 = isa<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, hasTrailingClosure,
locator.withPathElement(
ConstraintLocator::ApplyArgument));
if (!index)
return nullptr;
auto getType = [&](const Expr *E) -> Type {
return cs.getType(E);
};
// Handle dynamic lookup.
if (choice.getKind() == OverloadChoiceKind::DeclViaDynamic ||
subscript->getAttrs().hasAttribute<OptionalAttr>()) {
base = coerceObjectArgumentToType(base, baseTy, subscript,
AccessSemantics::Ordinary, 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 = coerceObjectArgumentToType(
base, containerTy, subscript, AccessSemantics::Ordinary,
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 = 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,
[&](const 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());
}
Expr *trailingClosure = nullptr;
if (SE->hasTrailingClosure())
trailingClosure = arguments.back();
componentExpr = SubscriptExpr::create(
ctx, dotExpr, SE->getStartLoc(), arguments,
SE->getArgumentLabels(), SE->getArgumentLabelLocs(),
SE->getEndLoc(), trailingClosure,
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);
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,
ConformanceCheckFlags::InExpression);
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,
bool suppressDiagnostics)
: cs(cs), dc(cs.DC), solution(solution),
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, ConformanceCheckFlags::InExpression)) {
// 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, ConformanceCheckFlags::InExpression)) {
// ... 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,
ConformanceCheckFlags::InExpression);
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->setResultInit(resultInit);
// Make the integer literals for the parameters.
auto buildExprFromUnsigned = [&](unsigned value) {
LiteralExpr *expr = IntegerLiteralExpr::createFromUnsigned(ctx, value);
cs.setType(expr, TypeChecker::getIntType(ctx));
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()) {
case MagicIdentifierLiteralExpr::File:
case MagicIdentifierLiteralExpr::FilePath:
case MagicIdentifierLiteralExpr::Function:
return handleStringLiteralExpr(expr);
case MagicIdentifierLiteralExpr::Line:
case MagicIdentifierLiteralExpr::Column:
return handleIntegerLiteralExpr(expr);
case MagicIdentifierLiteralExpr::DSOHandle:
return expr;
}
llvm_unreachable("Unhandled MagicIdentifierLiteralExpr in switch.");
}
Expr *visitObjectLiteralExpr(ObjectLiteralExpr *expr) {
if (cs.getType(expr) && !cs.getType(expr)->hasTypeVariable())
return expr;
auto &ctx = cs.getASTContext();
// 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;
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(cs.getASTContext(), expr);
assert(proto && "Missing object literal protocol?");
auto conformance =
TypeChecker::conformsToProtocol(conformingType, proto, cs.DC,
ConformanceCheckFlags::InExpression);
assert(conformance && "object literal type conforms to protocol");
auto constrName = TypeChecker::getObjectLiteralConstructorName(ctx, expr);
ConcreteDeclRef witness = conformance.getWitnessByName(
conformingType->getRValueType(), constrName);
if (!witness || !isa<AbstractFunctionDecl>(witness.getDecl()))
return nullptr;
expr->setInitializer(witness);
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->getAccessSemantics());
}
Expr *visitSuperRefExpr(SuperRefExpr *expr) {
simplifyExprType(expr);
return expr;
}
Expr *visitTypeExpr(TypeExpr *expr) {
auto toType = simplifyType(cs.getType(expr->getTypeLoc()));
expr->getTypeLoc().setType(toType);
cs.setType(expr, MetatypeType::get(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(), AccessSemantics::Ordinary);
}
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(),
/*extraUncurryLevel=*/false, expr->getAccessSemantics());
}
Expr *visitDynamicMemberRefExpr(DynamicMemberRefExpr *expr) {
llvm_unreachable("already type-checked?");
}
Expr *visitUnresolvedMemberExpr(UnresolvedMemberExpr *expr) {
// Dig out the type of the base, which will be the result type of this
// expression. 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->getRValueType()->is<UnresolvedType>()) {
cs.setType(expr, resultTy);
return expr;
}
Type baseTy = resultTy->getRValueType();
auto &ctx = cs.getASTContext();
// Find the selected member.
auto memberLocator = cs.getConstraintLocator(
expr, ConstraintLocator::UnresolvedMember);
auto selected = solution.getOverloadChoice(memberLocator);
// If the member came by optional unwrapping, then unwrap the base type.
if (selected.choice.getKind()
== OverloadChoiceKind::DeclViaUnwrappedOptional) {
baseTy = baseTy->getOptionalObjectType();
assert(baseTy
&& "got unwrapped optional decl from non-optional base?!");
}
// 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(), /*extraUncurryLevel=*/true,
AccessSemantics::Ordinary);
if (!result)
return nullptr;
auto getType = [&](const Expr *E) -> Type {
return cs.getType(E);
};
// If there was an argument, apply it.
if (auto arg = expr->getArgument()) {
// Get the callee locator. Note this may be different to the locator for
// the member being referenced for things like callAsFunction.
auto *calleeLoc = cs.getCalleeLocator(exprLoc);
// Build and finish the apply.
ApplyExpr *apply = CallExpr::create(
ctx, result, arg, expr->getArgumentLabels(),
expr->getArgumentLabelLocs(), expr->hasTrailingClosure(),
/*implicit=*/expr->isImplicit(), Type(), getType);
result = finishApply(apply, Type(), exprLoc, calleeLoc);
// FIXME: Application could fail, because some of the solutions
// are not expressible in AST (yet?), like certain tuple-to-tuple
// conversions. Better solution here would be not to form solutions
// which couldn't be applied by e.g. detecting situations like that
// and inserting fixes early.
if (!result)
return nullptr;
}
// Check for ambiguous member if the base is an Optional
if (baseTy->getOptionalObjectType()) {
diagnoseAmbiguousNominalMember(baseTy, result);
}
return coerceToType(result, resultTy, cs.getConstraintLocator(expr));
}
/// Diagnose if the base type is optional, we're referring to a nominal
/// type member via the dot syntax and the member name matches
/// Optional<T>.{member name}
void diagnoseAmbiguousNominalMember(Type baseTy, Expr *result) {
if (auto baseTyUnwrapped = baseTy->lookThroughAllOptionalTypes()) {
// Return if the base type doesn't have a nominal type decl
if (!baseTyUnwrapped->getNominalOrBoundGenericNominal()) {
return;
}
// Otherwise, continue digging
if (auto DSCE = dyn_cast<DotSyntaxCallExpr>(result)) {
auto calledValue = DSCE->getCalledValue();
auto isOptional = false;
Identifier memberName;
// Try cast the assigned value to an enum case
//
// This will always succeed if the base is Optional<T> & the
// assigned case comes from Optional<T>
if (auto EED = dyn_cast<EnumElementDecl>(calledValue)) {
isOptional = EED->getParentEnum()->isOptionalDecl();
memberName = EED->getBaseIdentifier();
}
// Return if the enum case doesn't come from Optional<T>
if (!isOptional) {
return;
}
// Look up the enum case in the unwrapped type to check if it exists
// as a member
auto baseTyNominalDecl = baseTyUnwrapped
->getNominalOrBoundGenericNominal();
auto results = TypeChecker::lookupMember(
baseTyNominalDecl->getModuleContext(), baseTyUnwrapped,
DeclNameRef(memberName), defaultMemberLookupOptions);
// Filter out any functions, instance members, enum cases with
// associated values or variables whose type does not match the
// contextual type.
results.filter([&](const LookupResultEntry entry, bool isOuter) {
if (auto member = entry.getValueDecl()) {
if (isa<FuncDecl>(member))
return false;
if (member->isInstanceMember())
return false;
if (auto EED = dyn_cast<EnumElementDecl>(member)) {
return !EED->hasAssociatedValues();
}
if (auto VD = dyn_cast<VarDecl>(member)) {
auto baseType = DSCE->getType()->lookThroughAllOptionalTypes();
return VD->getInterfaceType()->isEqual(baseType);
}
}
// Filter out anything that's not one of the above. We don't care
// if we have a typealias named 'none' or a struct/class named
// 'none'.
return false;
});
if (results.empty()) {
return;
}
auto &de = cs.getASTContext().Diags;
if (auto member = results.front().getValueDecl()) {
// Emit a diagnostic with some fix-its
auto baseTyName = baseTy->getCanonicalType().getString();
auto baseTyUnwrappedName = baseTyUnwrapped->getString();
auto loc = DSCE->getLoc();
auto startLoc = DSCE->getStartLoc();
de.diagnoseWithNotes(
de.diagnose(loc, swift::diag::optional_ambiguous_case_ref,
baseTyName, baseTyUnwrappedName, memberName.str()),
[&]() {
de.diagnose(loc,
swift::diag::optional_fixit_ambiguous_case_ref)
.fixItInsert(startLoc, "Optional");
de.diagnose(
loc,
swift::diag::type_fixit_optional_ambiguous_case_ref,
baseTyUnwrappedName, memberName.str())
.fixItInsert(startLoc, baseTyUnwrappedName);
});
}
}
}
}
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, /*extraUncurryLevel=*/true,
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()->getFullName() == 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())