//===--- CSGen.cpp - Constraint Generator ---------------------------------===// // // 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 constraint generation for the type checker. // //===----------------------------------------------------------------------===// #include "TypeCheckType.h" #include "TypeChecker.h" #include "swift/AST/ASTVisitor.h" #include "swift/AST/ASTWalker.h" #include "swift/AST/Expr.h" #include "swift/AST/GenericSignature.h" #include "swift/AST/ParameterList.h" #include "swift/AST/PrettyStackTrace.h" #include "swift/AST/SubstitutionMap.h" #include "swift/AST/TypeCheckRequests.h" #include "swift/Sema/ConstraintGraph.h" #include "swift/Sema/ConstraintSystem.h" #include "swift/Sema/IDETypeChecking.h" #include "swift/Subsystems.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringSwitch.h" #include using namespace swift; using namespace swift::constraints; static bool isArithmeticOperatorDecl(ValueDecl *vd) { return vd && (vd->getBaseName() == "+" || vd->getBaseName() == "-" || vd->getBaseName() == "*" || vd->getBaseName() == "/" || vd->getBaseName() == "%"); } static bool mergeRepresentativeEquivalenceClasses(ConstraintSystem &CS, TypeVariableType* tyvar1, TypeVariableType* tyvar2) { if (tyvar1 && tyvar2) { auto rep1 = CS.getRepresentative(tyvar1); auto rep2 = CS.getRepresentative(tyvar2); if (rep1 != rep2) { auto fixedType2 = CS.getFixedType(rep2); // If the there exists fixed type associated with the second // type variable, and we simply merge two types together it would // mean that portion of the constraint graph previously associated // with that (second) variable is going to be disconnected from its // new equivalence class, which is going to lead to incorrect solutions, // so we need to make sure to re-bind fixed to the new representative. if (fixedType2) { CS.addConstraint(ConstraintKind::Bind, fixedType2, rep1, rep1->getImpl().getLocator()); } CS.mergeEquivalenceClasses(rep1, rep2, /*updateWorkList*/ false); return true; } } return false; } namespace { /// Internal struct for tracking information about types within a series /// of "linked" expressions. (Such as a chain of binary operator invocations.) struct LinkedTypeInfo { bool hasLiteral = false; llvm::SmallSet collectedTypes; llvm::SmallVector binaryExprs; }; /// Walks an expression sub-tree, and collects information about expressions /// whose types are mutually dependent upon one another. class LinkedExprCollector : public ASTWalker { llvm::SmallVectorImpl &LinkedExprs; ConstraintSystem &CS; public: LinkedExprCollector(llvm::SmallVectorImpl &linkedExprs, ConstraintSystem &cs) : LinkedExprs(linkedExprs), CS(cs) {} std::pair walkToExprPre(Expr *expr) override { if (CS.shouldReusePrecheckedType() && !CS.getType(expr)->hasTypeVariable()) { return { false, expr }; } if (isa(expr)) return {false, expr}; // Store top-level binary exprs for further analysis. if (isa(expr) || // Literal exprs are contextually typed, so store them off as well. isa(expr) || // We'd like to look at the elements of arrays and dictionaries. isa(expr) || isa(expr) || // assignment expression can involve anonymous closure parameters // as source and destination, so it's beneficial for diagnostics if // we look at the assignment. isa(expr)) { LinkedExprs.push_back(expr); return {false, expr}; } return { true, expr }; } Expr *walkToExprPost(Expr *expr) override { return expr; } /// Ignore statements. std::pair walkToStmtPre(Stmt *stmt) override { return { false, stmt }; } /// Ignore declarations. bool walkToDeclPre(Decl *decl) override { return false; } /// Ignore patterns. std::pair walkToPatternPre(Pattern *pat) override { return { false, pat }; } /// Ignore types. bool walkToTypeReprPre(TypeRepr *T) override { return false; } }; /// Given a collection of "linked" expressions, analyzes them for /// commonalities regarding their types. This will help us compute a /// "best common type" from the expression types. class LinkedExprAnalyzer : public ASTWalker { LinkedTypeInfo <I; ConstraintSystem &CS; public: LinkedExprAnalyzer(LinkedTypeInfo <i, ConstraintSystem &cs) : LTI(lti), CS(cs) {} std::pair walkToExprPre(Expr *expr) override { if (CS.shouldReusePrecheckedType() && !CS.getType(expr)->hasTypeVariable()) { return { false, expr }; } if (isa(expr)) { LTI.hasLiteral = true; return { false, expr }; } if (isa(expr)) { return { true, expr }; } if (auto UDE = dyn_cast(expr)) { if (CS.hasType(UDE)) LTI.collectedTypes.insert(CS.getType(UDE).getPointer()); // Don't recurse into the base expression. return { false, expr }; } if (isa(expr)) { return {false, expr}; } if (auto FVE = dyn_cast(expr)) { LTI.collectedTypes.insert(CS.getType(FVE).getPointer()); return { false, expr }; } if (auto DRE = dyn_cast(expr)) { if (auto varDecl = dyn_cast(DRE->getDecl())) { if (CS.hasType(DRE)) { LTI.collectedTypes.insert(CS.getType(DRE).getPointer()); } return { false, expr }; } } // In the case of a function application, we would have already captured // the return type during constraint generation, so there's no use in // looking any further. if (isa(expr) && !(isa(expr) || isa(expr) || isa(expr))) { return { false, expr }; } if (isa(expr)) { LTI.binaryExprs.push_back(dyn_cast(expr)); } if (auto favoredType = CS.getFavoredType(expr)) { LTI.collectedTypes.insert(favoredType); return { false, expr }; } // Optimize branches of a conditional expression separately. if (auto IE = dyn_cast(expr)) { CS.optimizeConstraints(IE->getCondExpr()); CS.optimizeConstraints(IE->getThenExpr()); CS.optimizeConstraints(IE->getElseExpr()); return { false, expr }; } // For exprs of a structural type that are not modeling argument lists, // avoid merging the type variables. (We need to allow for cases like // (Int, Int32).) if (isa(expr) && !isa(Parent.getAsExpr())) { return { false, expr }; } // Coercion exprs have a rigid type, so there's no use in gathering info // about them. if (auto *coercion = dyn_cast(expr)) { // Let's not collect information about types initialized by // coercions just like we don't for regular initializer calls, // because that might lead to overly eager type variable merging. if (!coercion->isLiteralInit()) LTI.collectedTypes.insert(CS.getType(expr).getPointer()); return { false, expr }; } // Don't walk into subscript expressions - to do so would risk factoring // the index expression into edge contraction. (We don't want to do this // if the index expression is a literal type that differs from the return // type of the subscript operation.) if (isa(expr) || isa(expr)) { return { false, expr }; } // Don't walk into unresolved member expressions - we avoid merging type // variables inside UnresolvedMemberExpr and those outside, since they // should be allowed to behave independently in CS. if (isa(expr)) { return {false, expr }; } return { true, expr }; } /// Ignore statements. std::pair walkToStmtPre(Stmt *stmt) override { return { false, stmt }; } /// Ignore declarations. bool walkToDeclPre(Decl *decl) override { return false; } /// Ignore patterns. std::pair walkToPatternPre(Pattern *pat) override { return { false, pat }; } /// Ignore types. bool walkToTypeReprPre(TypeRepr *T) override { return false; } }; /// For a given expression, given information that is global to the /// expression, attempt to derive a favored type for it. bool computeFavoredTypeForExpr(Expr *expr, ConstraintSystem &CS) { LinkedTypeInfo lti; expr->walk(LinkedExprAnalyzer(lti, CS)); if (lti.collectedTypes.size() == 1) { // TODO: Compute the BCT. // It's only useful to favor the type instead of // binding it directly to arguments/result types, // which means in case it has been miscalculated // solver can still make progress. auto favoredTy = (*lti.collectedTypes.begin())->getWithoutSpecifierType(); CS.setFavoredType(expr, favoredTy.getPointer()); // If we have a chain of identical binop expressions with homogeneous // argument types, we can directly simplify the associated constraint // graph. auto simplifyBinOpExprTyVars = [&]() { // Don't attempt to do linking if there are // literals intermingled with other inferred types. if (lti.hasLiteral) return; for (auto binExp1 : lti.binaryExprs) { for (auto binExp2 : lti.binaryExprs) { if (binExp1 == binExp2) continue; auto fnTy1 = CS.getType(binExp1)->getAs(); auto fnTy2 = CS.getType(binExp2)->getAs(); if (!(fnTy1 && fnTy2)) return; auto ODR1 = dyn_cast(binExp1->getFn()); auto ODR2 = dyn_cast(binExp2->getFn()); if (!(ODR1 && ODR2)) return; // TODO: We currently limit this optimization to known arithmetic // operators, but we should be able to broaden this out to // logical operators as well. if (!isArithmeticOperatorDecl(ODR1->getDecls()[0])) return; if (ODR1->getDecls()[0]->getBaseName() != ODR2->getDecls()[0]->getBaseName()) return; // All things equal, we can merge the tyvars for the function // types. auto rep1 = CS.getRepresentative(fnTy1); auto rep2 = CS.getRepresentative(fnTy2); if (rep1 != rep2) { CS.mergeEquivalenceClasses(rep1, rep2, /*updateWorkList*/ false); } auto odTy1 = CS.getType(ODR1)->getAs(); auto odTy2 = CS.getType(ODR2)->getAs(); if (odTy1 && odTy2) { auto odRep1 = CS.getRepresentative(odTy1); auto odRep2 = CS.getRepresentative(odTy2); // Since we'll be choosing the same overload, we can merge // the overload tyvar as well. if (odRep1 != odRep2) CS.mergeEquivalenceClasses(odRep1, odRep2, /*updateWorkList*/ false); } } } }; simplifyBinOpExprTyVars(); return true; } return false; } /// Determine whether the given parameter type and argument should be /// "favored" because they match exactly. bool isFavoredParamAndArg(ConstraintSystem &CS, Type paramTy, Type argTy, Type otherArgTy = Type()) { // Determine the argument type. argTy = argTy->getWithoutSpecifierType(); // Do the types match exactly? if (paramTy->isEqual(argTy)) return true; llvm::SmallSetVector literalProtos; if (auto argTypeVar = argTy->getAs()) { auto constraints = CS.getConstraintGraph().gatherConstraints( argTypeVar, ConstraintGraph::GatheringKind::EquivalenceClass, [](Constraint *constraint) { return constraint->getKind() == ConstraintKind::LiteralConformsTo; }); for (auto constraint : constraints) { literalProtos.insert(constraint->getProtocol()); } } // Dig out the second argument type. if (otherArgTy) otherArgTy = otherArgTy->getWithoutSpecifierType(); for (auto literalProto : literalProtos) { // If there is another, concrete argument, check whether it's type // conforms to the literal protocol and test against it directly. // This helps to avoid 'widening' the favored type to the default type for // the literal. if (otherArgTy && otherArgTy->getAnyNominal()) { if (otherArgTy->isEqual(paramTy) && TypeChecker::conformsToProtocol( otherArgTy, literalProto, CS.DC)) { return true; } } else if (Type defaultType = TypeChecker::getDefaultType(literalProto, CS.DC)) { // If there is a default type for the literal protocol, check whether // it is the same as the parameter type. // Check whether there is a default type to compare against. if (paramTy->isEqual(defaultType)) return true; } } return false; } /// Favor certain overloads in a call based on some basic analysis /// of the overload set and call arguments. /// /// \param expr The application. /// \param isFavored Determine whether the given overload is favored, passing /// it the "effective" overload type when it's being called. /// \param mustConsider If provided, a function to detect the presence of /// overloads which inhibit any overload from being favored. void favorCallOverloads(ApplyExpr *expr, ConstraintSystem &CS, llvm::function_ref isFavored, std::function mustConsider = nullptr) { // Find the type variable associated with the function, if any. auto tyvarType = CS.getType(expr->getFn())->getAs(); if (!tyvarType || CS.getFixedType(tyvarType)) return; // This type variable is only currently associated with the function // being applied, and the only constraint attached to it should // be the disjunction constraint for the overload group. auto disjunction = CS.getUnboundBindOverloadDisjunction(tyvarType); if (!disjunction) return; // Find the favored constraints and mark them. SmallVector newlyFavoredConstraints; unsigned numFavoredConstraints = 0; Constraint *firstFavored = nullptr; for (auto constraint : disjunction->getNestedConstraints()) { auto *decl = constraint->getOverloadChoice().getDeclOrNull(); if (!decl) continue; if (mustConsider && mustConsider(decl)) { // Roll back any constraints we favored. for (auto favored : newlyFavoredConstraints) favored->setFavored(false); return; } Type overloadType = CS.getEffectiveOverloadType(constraint->getOverloadChoice(), /*allowMembers=*/true, CS.DC); if (!overloadType) continue; if (!CS.isDeclUnavailable(decl, constraint->getLocator()) && !decl->getAttrs().hasAttribute() && isFavored(decl, overloadType)) { // If we might need to roll back the favored constraints, keep // track of those we are favoring. if (mustConsider && !constraint->isFavored()) newlyFavoredConstraints.push_back(constraint); constraint->setFavored(); ++numFavoredConstraints; if (!firstFavored) firstFavored = constraint; } } // If there was one favored constraint, set the favored type based on its // result type. if (numFavoredConstraints == 1) { auto overloadChoice = firstFavored->getOverloadChoice(); auto overloadType = CS.getEffectiveOverloadType(overloadChoice, /*allowMembers=*/true, CS.DC); auto resultType = overloadType->castTo()->getResult(); if (!resultType->hasTypeParameter()) CS.setFavoredType(expr, resultType.getPointer()); } } size_t getOperandCount(Type t) { size_t nOperands = 0; if (auto parenTy = dyn_cast(t.getPointer())) { if (parenTy->getDesugaredType()) nOperands = 1; } else if (auto tupleTy = t->getAs()) { nOperands = tupleTy->getElementTypes().size(); } return nOperands; } /// Return a pair, containing the total parameter count of a function, coupled /// with the number of non-default parameters. std::pair getParamCount(ValueDecl *VD) { auto fTy = VD->getInterfaceType()->castTo(); size_t nOperands = fTy->getParams().size(); size_t nNoDefault = 0; if (auto AFD = dyn_cast(VD)) { assert(!AFD->hasImplicitSelfDecl()); for (auto param : *AFD->getParameters()) { if (!param->isDefaultArgument()) ++nNoDefault; } } else { nNoDefault = nOperands; } return { nOperands, nNoDefault }; } /// Favor unary operator constraints where we have exact matches /// for the operand and contextual type. void favorMatchingUnaryOperators(ApplyExpr *expr, ConstraintSystem &CS) { // Determine whether the given declaration is favored. auto isFavoredDecl = [&](ValueDecl *value, Type type) -> bool { auto fnTy = type->getAs(); if (!fnTy) return false; Type paramTy = FunctionType::composeInput(CS.getASTContext(), fnTy->getParams(), false); auto resultTy = fnTy->getResult(); auto contextualTy = CS.getContextualType(expr); return isFavoredParamAndArg( CS, paramTy, CS.getType(expr->getArg())->getWithoutParens()) && (!contextualTy || contextualTy->isEqual(resultTy)); }; favorCallOverloads(expr, CS, isFavoredDecl); } void favorMatchingOverloadExprs(ApplyExpr *expr, ConstraintSystem &CS) { // Find the argument type. size_t nArgs = getOperandCount(CS.getType(expr->getArg())); auto fnExpr = expr->getFn(); // Check to ensure that we have an OverloadedDeclRef, and that we're not // favoring multiple overload constraints. (Otherwise, in this case // favoring is useless. if (auto ODR = dyn_cast(fnExpr)) { bool haveMultipleApplicableOverloads = false; for (auto VD : ODR->getDecls()) { if (VD->getInterfaceType()->is()) { auto nParams = getParamCount(VD); if (nArgs == nParams.first) { if (haveMultipleApplicableOverloads) { return; } else { haveMultipleApplicableOverloads = true; } } } } // Determine whether the given declaration is favored. auto isFavoredDecl = [&](ValueDecl *value, Type type) -> bool { if (!type->is()) return false; auto paramCount = getParamCount(value); return nArgs == paramCount.first || nArgs == paramCount.second; }; favorCallOverloads(expr, CS, isFavoredDecl); } if (auto favoredTy = CS.getFavoredType(expr->getArg())) { // Determine whether the given declaration is favored. auto isFavoredDecl = [&](ValueDecl *value, Type type) -> bool { auto fnTy = type->getAs(); if (!fnTy) return false; auto paramTy = AnyFunctionType::composeInput(CS.getASTContext(), fnTy->getParams(), /*canonicalVararg*/ false); return favoredTy->isEqual(paramTy); }; // This is a hack to ensure we always consider the protocol requirement // itself when calling something that has a default implementation in an // extension. Otherwise, the extension method might be favored if we're // inside an extension context, since any archetypes in the parameter // list could match exactly. auto mustConsider = [&](ValueDecl *value) -> bool { return isa(value->getDeclContext()); }; favorCallOverloads(expr, CS, isFavoredDecl, mustConsider); } } /// Favor binary operator constraints where we have exact matches /// for the operands and contextual type. void favorMatchingBinaryOperators(ApplyExpr *expr, ConstraintSystem &CS) { // If we're generating constraints for a binary operator application, // there are two special situations to consider: // 1. If the type checker has any newly created functions with the // operator's name. If it does, the overloads were created after the // associated overloaded id expression was created, and we'll need to // add a new disjunction constraint for the new set of overloads. // 2. If any component argument expressions (nested or otherwise) are // literals, we can favor operator overloads whose argument types are // identical to the literal type, or whose return types are identical // to any contextual type associated with the application expression. // Find the argument types. auto argTy = CS.getType(expr->getArg()); auto argTupleTy = argTy->castTo(); auto argTupleExpr = dyn_cast(expr->getArg()); Type firstArgTy = argTupleTy->getElement(0).getType()->getWithoutParens(); Type secondArgTy = argTupleTy->getElement(1).getType()->getWithoutParens(); auto isOptionalWithMatchingObjectType = [](Type optional, Type object) -> bool { if (auto objTy = optional->getRValueType()->getOptionalObjectType()) return objTy->getRValueType()->isEqual(object->getRValueType()); return false; }; auto isPotentialForcingOpportunity = [&](Type first, Type second) -> bool { return isOptionalWithMatchingObjectType(first, second) || isOptionalWithMatchingObjectType(second, first); }; // Determine whether the given declaration is favored. auto isFavoredDecl = [&](ValueDecl *value, Type type) -> bool { auto fnTy = type->getAs(); if (!fnTy) return false; Expr *firstArg = argTupleExpr->getElement(0); auto firstFavoredTy = CS.getFavoredType(firstArg); Expr *secondArg = argTupleExpr->getElement(1); auto secondFavoredTy = CS.getFavoredType(secondArg); auto favoredExprTy = CS.getFavoredType(expr); if (isArithmeticOperatorDecl(value)) { // If the parent has been favored on the way down, propagate that // information to its children. // TODO: This is only valid for arithmetic expressions. if (!firstFavoredTy) { CS.setFavoredType(argTupleExpr->getElement(0), favoredExprTy); firstFavoredTy = favoredExprTy; } if (!secondFavoredTy) { CS.setFavoredType(argTupleExpr->getElement(1), favoredExprTy); secondFavoredTy = favoredExprTy; } } auto params = fnTy->getParams(); if (params.size() != 2) return false; auto firstParamTy = params[0].getOldType(); auto secondParamTy = params[1].getOldType(); auto resultTy = fnTy->getResult(); auto contextualTy = CS.getContextualType(expr); return (isFavoredParamAndArg(CS, firstParamTy, firstArgTy, secondArgTy) || isFavoredParamAndArg(CS, secondParamTy, secondArgTy, firstArgTy)) && firstParamTy->isEqual(secondParamTy) && !isPotentialForcingOpportunity(firstArgTy, secondArgTy) && (!contextualTy || contextualTy->isEqual(resultTy)); }; favorCallOverloads(expr, CS, isFavoredDecl); } class ConstraintOptimizer : public ASTWalker { ConstraintSystem &CS; public: ConstraintOptimizer(ConstraintSystem &cs) : CS(cs) {} std::pair walkToExprPre(Expr *expr) override { if (CS.shouldReusePrecheckedType() && !CS.getType(expr)->hasTypeVariable()) { return { false, expr }; } if (auto applyExpr = dyn_cast(expr)) { if (isa(applyExpr) || isa(applyExpr)) { favorMatchingUnaryOperators(applyExpr, CS); } else if (isa(applyExpr)) { favorMatchingBinaryOperators(applyExpr, CS); } else { favorMatchingOverloadExprs(applyExpr, CS); } } // If the paren expr has a favored type, and the subExpr doesn't, // propagate downwards. Otherwise, propagate upwards. if (auto parenExpr = dyn_cast(expr)) { if (!CS.getFavoredType(parenExpr->getSubExpr())) { CS.setFavoredType(parenExpr->getSubExpr(), CS.getFavoredType(parenExpr)); } else if (!CS.getFavoredType(parenExpr)) { CS.setFavoredType(parenExpr, CS.getFavoredType(parenExpr->getSubExpr())); } } if (isa(expr)) return {false, expr}; return { true, expr }; } Expr *walkToExprPost(Expr *expr) override { return expr; } /// Ignore statements. std::pair walkToStmtPre(Stmt *stmt) override { return { false, stmt }; } /// Ignore declarations. bool walkToDeclPre(Decl *decl) override { return false; } }; } // end anonymous namespace namespace { class ConstraintGenerator : public ExprVisitor { ConstraintSystem &CS; DeclContext *CurDC; ConstraintSystemPhase CurrPhase; static const unsigned numEditorPlaceholderVariables = 2; /// A buffer of type variables used for editor placeholders. We only /// use a small number of these (rotating through), to prevent expressions /// with a large number of editor placeholders from flooding the constraint /// system with type variables. TypeVariableType *editorPlaceholderVariables[numEditorPlaceholderVariables] = { nullptr, nullptr }; unsigned currentEditorPlaceholderVariable = 0; /// Keep track of acceptable DiscardAssignmentExpr's. llvm::SmallPtrSet CorrectDiscardAssignmentExprs; /// A map from each UnresolvedMemberExpr to the respective (implicit) base /// found during our walk. llvm::MapVector UnresolvedBaseTypes; /// Returns false and emits the specified diagnostic if the member reference /// base is a nil literal. Returns true otherwise. bool isValidBaseOfMemberRef(Expr *base, Diag<> diagnostic) { if (auto nilLiteral = dyn_cast(base)) { CS.getASTContext().Diags.diagnose(nilLiteral->getLoc(), diagnostic); return false; } return true; } /// Add constraints for a reference to a named member of the given /// base type, and return the type of such a reference. Type addMemberRefConstraints(Expr *expr, Expr *base, DeclNameRef name, FunctionRefKind functionRefKind, ArrayRef outerAlternatives) { // The base must have a member of the given name, such that accessing // that member through the base returns a value convertible to the type // of this expression. auto baseTy = CS.getType(base); auto tv = CS.createTypeVariable( CS.getConstraintLocator(expr, ConstraintLocator::Member), TVO_CanBindToLValue | TVO_CanBindToNoEscape); SmallVector outerChoices; for (auto decl : outerAlternatives) { outerChoices.push_back(OverloadChoice(Type(), decl, functionRefKind)); } CS.addValueMemberConstraint( baseTy, name, tv, CurDC, functionRefKind, outerChoices, CS.getConstraintLocator(expr, ConstraintLocator::Member)); return tv; } /// Add constraints for a reference to a specific member of the given /// base type, and return the type of such a reference. Type addMemberRefConstraints(Expr *expr, Expr *base, ValueDecl *decl, FunctionRefKind functionRefKind) { // If we're referring to an invalid declaration, fail. if (!decl) return nullptr; if (decl->isInvalid()) return nullptr; auto memberLocator = CS.getConstraintLocator(expr, ConstraintLocator::Member); auto tv = CS.createTypeVariable(memberLocator, TVO_CanBindToLValue | TVO_CanBindToNoEscape); OverloadChoice choice = OverloadChoice(CS.getType(base), decl, functionRefKind); auto locator = CS.getConstraintLocator(expr, ConstraintLocator::Member); CS.addBindOverloadConstraint(tv, choice, locator, CurDC); return tv; } /// Add constraints for a subscript operation. Type addSubscriptConstraints( Expr *anchor, Type baseTy, Expr *index, ValueDecl *declOrNull, ArrayRef argLabels, Optional unlabeledTrailingClosure, ConstraintLocator *locator = nullptr, SmallVectorImpl *addedTypeVars = nullptr) { // Locators used in this expression. if (locator == nullptr) locator = CS.getConstraintLocator(anchor); auto fnLocator = CS.getConstraintLocator(locator, ConstraintLocator::ApplyFunction); auto memberLocator = CS.getConstraintLocator(locator, ConstraintLocator::SubscriptMember); auto resultLocator = CS.getConstraintLocator(locator, ConstraintLocator::FunctionResult); associateArgumentLabels(memberLocator, {argLabels, unlabeledTrailingClosure}); Type outputTy; // For an integer subscript expression on an array slice type, instead of // introducing a new type variable we can easily obtain the element type. if (isa(anchor)) { auto isLValueBase = false; auto baseObjTy = baseTy; if (baseObjTy->is()) { isLValueBase = true; baseObjTy = baseObjTy->getWithoutSpecifierType(); } if (CS.isArrayType(baseObjTy.getPointer())) { if (auto arraySliceTy = dyn_cast(baseObjTy.getPointer())) { baseObjTy = arraySliceTy->getDesugaredType(); } auto indexExpr = index; if (auto parenExpr = dyn_cast(indexExpr)) { indexExpr = parenExpr->getSubExpr(); } if (isa(indexExpr)) { outputTy = baseObjTy->getAs()->getGenericArgs()[0]; if (isLValueBase) outputTy = LValueType::get(outputTy); } } else if (auto dictTy = CS.isDictionaryType(baseObjTy)) { auto keyTy = dictTy->first; auto valueTy = dictTy->second; if (isFavoredParamAndArg(CS, keyTy, CS.getType(index))) { outputTy = OptionalType::get(valueTy); if (isLValueBase) outputTy = LValueType::get(outputTy); } } } if (outputTy.isNull()) { outputTy = CS.createTypeVariable(resultLocator, TVO_CanBindToLValue | TVO_CanBindToNoEscape); if (addedTypeVars) addedTypeVars->push_back(outputTy->castTo()); } // FIXME: This can only happen when diagnostics successfully type-checked // sub-expression of the subscript and mutated AST, but under normal // circumstances subscript should never have InOutExpr as a direct child // until type checking is complete and expression is re-written. // Proper fix for such situation requires preventing diagnostics from // re-writing AST after successful type checking of the sub-expressions. if (auto inoutTy = baseTy->getAs()) { baseTy = LValueType::get(inoutTy->getObjectType()); } // Add the member constraint for a subscript declaration. // FIXME: weak name! auto memberTy = CS.createTypeVariable( memberLocator, TVO_CanBindToLValue | TVO_CanBindToNoEscape); if (addedTypeVars) addedTypeVars->push_back(memberTy); // FIXME: synthesizeMaterializeForSet() wants to statically dispatch to // a known subscript here. This might be cleaner if we split off a new // UnresolvedSubscriptExpr from SubscriptExpr. if (auto decl = declOrNull) { OverloadChoice choice = OverloadChoice(baseTy, decl, FunctionRefKind::DoubleApply); CS.addBindOverloadConstraint(memberTy, choice, memberLocator, CurDC); } else { CS.addValueMemberConstraint(baseTy, DeclNameRef::createSubscript(), memberTy, CurDC, FunctionRefKind::DoubleApply, /*outerAlternatives=*/{}, memberLocator); } // FIXME: Redesign the AST so that an ApplyExpr directly stores a list of // arguments together with their inout-ness, instead of a single // ParenExpr or TupleExpr. SmallVector params; AnyFunctionType::decomposeInput(CS.getType(index), params); // Add the constraint that the index expression's type be convertible // to the input type of the subscript operator. CS.addConstraint(ConstraintKind::ApplicableFunction, FunctionType::get(params, outputTy), memberTy, fnLocator); Type fixedOutputType = CS.getFixedTypeRecursive(outputTy, /*wantRValue=*/false); if (!fixedOutputType->isTypeVariableOrMember()) { CS.setFavoredType(anchor, fixedOutputType.getPointer()); outputTy = fixedOutputType; } return outputTy; } public: ConstraintGenerator(ConstraintSystem &CS, DeclContext *DC) : CS(CS), CurDC(DC ? DC : CS.DC), CurrPhase(CS.getPhase()) { // Although constraint system is initialized in `constraint // generation` phase, we have to set it here manually because e.g. // function builders could generate constraints for its body // in the middle of the solving. CS.setPhase(ConstraintSystemPhase::ConstraintGeneration); } virtual ~ConstraintGenerator() { CS.setPhase(CurrPhase); } ConstraintSystem &getConstraintSystem() const { return CS; } virtual Type visitErrorExpr(ErrorExpr *E) { if (!CS.isForCodeCompletion()) return nullptr; // For code completion, treat error expressions that don't contain // the completion location itself as holes. If an ErrorExpr contains the // code completion location, a fallback typecheck is called on the // ErrorExpr's OriginalExpr (valid sub-expression) if it had one, // independent of the wider expression containing the ErrorExpr, so // there's no point attempting to produce a solution for it. SourceRange range = E->getSourceRange(); if (range.isInvalid() || CS.getASTContext().SourceMgr.rangeContainsCodeCompletionLoc(range)) return nullptr; return HoleType::get(CS.getASTContext(), E); } virtual Type visitCodeCompletionExpr(CodeCompletionExpr *E) { CS.Options |= ConstraintSystemFlags::SuppressDiagnostics; auto locator = CS.getConstraintLocator(E); return CS.createTypeVariable(locator, TVO_CanBindToLValue | TVO_CanBindToNoEscape | TVO_CanBindToHole); } Type visitNilLiteralExpr(NilLiteralExpr *expr) { auto literalTy = visitLiteralExpr(expr); // Allow `nil` to be a hole so we can diagnose it via a fix // if it turns out that there is no contextual information. if (auto *typeVar = literalTy->getAs()) CS.recordPotentialHole(typeVar); return literalTy; } Type visitFloatLiteralExpr(FloatLiteralExpr *expr) { auto &ctx = CS.getASTContext(); // Get the _MaxBuiltinFloatType decl, or look for it if it's not cached. auto maxFloatTypeDecl = ctx.get_MaxBuiltinFloatTypeDecl(); if (!maxFloatTypeDecl || !maxFloatTypeDecl->getDeclaredInterfaceType()->is()) { ctx.Diags.diagnose(expr->getLoc(), diag::no_MaxBuiltinFloatType_found); return nullptr; } return visitLiteralExpr(expr); } Type visitLiteralExpr(LiteralExpr *expr) { // If the expression has already been assigned a type; just use that type. if (expr->getType()) return expr->getType(); auto protocol = TypeChecker::getLiteralProtocol(CS.getASTContext(), expr); if (!protocol) return nullptr; auto tv = CS.createTypeVariable(CS.getConstraintLocator(expr), TVO_PrefersSubtypeBinding | TVO_CanBindToNoEscape); CS.addConstraint(ConstraintKind::LiteralConformsTo, tv, protocol->getDeclaredInterfaceType(), CS.getConstraintLocator(expr)); return tv; } Type visitInterpolatedStringLiteralExpr(InterpolatedStringLiteralExpr *expr) { // Dig out the ExpressibleByStringInterpolation protocol. auto &ctx = CS.getASTContext(); auto interpolationProto = TypeChecker::getProtocol( ctx, expr->getLoc(), KnownProtocolKind::ExpressibleByStringInterpolation); if (!interpolationProto) { ctx.Diags.diagnose(expr->getStartLoc(), diag::interpolation_missing_proto); return nullptr; } // The type of the expression must conform to the // ExpressibleByStringInterpolation protocol. auto locator = CS.getConstraintLocator(expr); auto tv = CS.createTypeVariable(locator, TVO_PrefersSubtypeBinding | TVO_CanBindToNoEscape); CS.addConstraint(ConstraintKind::LiteralConformsTo, tv, interpolationProto->getDeclaredInterfaceType(), locator); if (auto appendingExpr = expr->getAppendingExpr()) { auto associatedTypeDecl = interpolationProto->getAssociatedType( ctx.Id_StringInterpolation); if (associatedTypeDecl == nullptr) { ctx.Diags.diagnose(expr->getStartLoc(), diag::interpolation_broken_proto); return nullptr; } auto interpolationTV = DependentMemberType::get(tv, associatedTypeDecl); auto appendingExprType = CS.getType(appendingExpr); auto appendingLocator = CS.getConstraintLocator(appendingExpr); // Must be Conversion; if it's Equal, then in semi-rare cases, the // interpolation temporary variable cannot be @lvalue. CS.addConstraint(ConstraintKind::Conversion, appendingExprType, interpolationTV, appendingLocator); } return tv; } Type visitMagicIdentifierLiteralExpr(MagicIdentifierLiteralExpr *expr) { switch (expr->getKind()) { // Magic pointer identifiers are of type UnsafeMutableRawPointer. #define MAGIC_POINTER_IDENTIFIER(NAME, STRING, SYNTAX_KIND) \ case MagicIdentifierLiteralExpr::NAME: #include "swift/AST/MagicIdentifierKinds.def" { auto &ctx = CS.getASTContext(); if (TypeChecker::requirePointerArgumentIntrinsics(ctx, expr->getLoc())) return nullptr; auto unsafeRawPointer = ctx.getUnsafeRawPointerDecl(); return unsafeRawPointer->getDeclaredInterfaceType(); } default: // Others are actual literals and should be handled like any literal. return visitLiteralExpr(expr); } llvm_unreachable("Unhandled MagicIdentifierLiteralExpr in switch."); } Type visitObjectLiteralExpr(ObjectLiteralExpr *expr) { auto *exprLoc = CS.getConstraintLocator(expr); associateArgumentLabels( exprLoc, {expr->getArgumentLabels(), expr->getUnlabeledTrailingClosureIndex()}); // If the expression has already been assigned a type; just use that type. if (expr->getType()) return expr->getType(); auto &ctx = CS.getASTContext(); auto &de = ctx.Diags; auto protocol = TypeChecker::getLiteralProtocol(ctx, expr); if (!protocol) { de.diagnose(expr->getLoc(), diag::use_unknown_object_literal_protocol, expr->getLiteralKindPlainName()); return nullptr; } auto witnessType = CS.createTypeVariable( exprLoc, TVO_PrefersSubtypeBinding | TVO_CanBindToNoEscape | TVO_CanBindToHole); CS.addConstraint(ConstraintKind::LiteralConformsTo, witnessType, protocol->getDeclaredInterfaceType(), exprLoc); // The arguments are required to be argument-convertible to the // idealized parameter type of the initializer, which generally // simplifies the first label (e.g. "colorLiteralRed:") by stripping // all the redundant stuff about literals (leaving e.g. "red:"). // Constraint application will quietly rewrite the type of 'args' to // use the right labels before forming the call to the initializer. auto constrName = TypeChecker::getObjectLiteralConstructorName(ctx, expr); assert(constrName); auto *constr = dyn_cast_or_null( protocol->getSingleRequirement(constrName)); if (!constr) { de.diagnose(protocol, diag::object_literal_broken_proto); return nullptr; } auto *memberLoc = CS.getConstraintLocator(expr, ConstraintLocator::ConstructorMember); auto *memberType = CS.createTypeVariable(memberLoc, TVO_CanBindToNoEscape); CS.addValueMemberConstraint(MetatypeType::get(witnessType, ctx), DeclNameRef(constrName), memberType, CurDC, FunctionRefKind::DoubleApply, {}, memberLoc); SmallVector args; AnyFunctionType::decomposeInput(CS.getType(expr->getArg()), args); auto resultType = CS.createTypeVariable( CS.getConstraintLocator(expr, ConstraintLocator::FunctionResult), TVO_CanBindToNoEscape); CS.addConstraint( ConstraintKind::ApplicableFunction, FunctionType::get(args, resultType), memberType, CS.getConstraintLocator(expr, ConstraintLocator::ApplyFunction)); if (constr->isFailable()) return OptionalType::get(witnessType); return witnessType; } Type visitDeclRefExpr(DeclRefExpr *E) { auto locator = CS.getConstraintLocator(E); Type knownType; if (auto *VD = dyn_cast(E->getDecl())) { knownType = CS.getTypeIfAvailable(VD); if (!knownType) knownType = CS.getVarType(VD); if (knownType) { // If the known type has an error, bail out. if (knownType->hasError()) { if (!CS.hasType(E)) CS.setType(E, knownType); return nullptr; } if (!knownType->hasHole()) { // Set the favored type for this expression to the known type. CS.setFavoredType(E, knownType.getPointer()); } } // This can only happen when failure diagnostics is trying // to type-check expressions inside of a single-statement // closure which refer to anonymous parameters, in this case // let's either use type as written or allocate a fresh type // variable, just like we do for closure type. // FIXME: We should eliminate this case. if (auto *PD = dyn_cast(VD)) { if (!CS.hasType(PD)) { if (knownType && knownType->hasUnboundGenericType()) knownType = CS.openUnboundGenericTypes(knownType, locator); CS.setType( PD, knownType ? knownType : CS.createTypeVariable(locator, TVO_CanBindToLValue | TVO_CanBindToNoEscape)); } } } // If we're referring to an invalid declaration, don't type-check. // // FIXME: If the decl is in error, we get no information from this. // We may, alternatively, want to use a type variable in that case, // and possibly infer the type of the variable that way. if (!knownType && E->getDecl()->isInvalid()) { CS.setType(E, E->getDecl()->getInterfaceType()); return nullptr; } // Create an overload choice referencing this declaration and immediately // resolve it. This records the overload for use later. auto tv = CS.createTypeVariable(locator, TVO_CanBindToLValue | TVO_CanBindToNoEscape); OverloadChoice choice = OverloadChoice(Type(), E->getDecl(), E->getFunctionRefKind()); CS.resolveOverload(locator, tv, choice, CurDC); return tv; } Type visitOtherConstructorDeclRefExpr(OtherConstructorDeclRefExpr *E) { return E->getType(); } Type visitSuperRefExpr(SuperRefExpr *E) { if (E->getType()) return E->getType(); // Resolve the super type of 'self'. return getSuperType(E->getSelf(), E->getLoc(), diag::super_not_in_class_method, diag::super_with_no_base_class); } Type resolveTypeReferenceInExpression(TypeRepr *repr, TypeResolverContext resCtx, const ConstraintLocatorBuilder &locator) { // Introduce type variables for unbound generics. const auto opener = OpenUnboundGenericType(CS, locator); const auto result = TypeResolution::forContextual(CS.DC, resCtx, opener) .resolveType(repr); if (result->hasError()) { return Type(); } return result; } Type visitTypeExpr(TypeExpr *E) { Type type; // If this is an implicit TypeExpr, don't validate its contents. auto *const locator = CS.getConstraintLocator(E); if (E->isImplicit()) { type = CS.getInstanceType(CS.cacheType(E)); assert(type && "Implicit type expr must have type set!"); type = CS.openUnboundGenericTypes(type, locator); } else if (CS.hasType(E)) { // If there's a type already set into the constraint system, honor it. // FIXME: This supports the function builder transform, which sneakily // stashes a type in the constraint system through a TypeExpr in order // to pass it down to the rest of CSGen. This is a terribly // unprincipled thing to do. return CS.getType(E); } else { auto *repr = E->getTypeRepr(); assert(repr && "Explicit node has no type repr!"); type = resolveTypeReferenceInExpression( repr, TypeResolverContext::InExpression, locator); } if (!type || type->hasError()) return Type(); return MetatypeType::get(type); } Type visitDotSyntaxBaseIgnoredExpr(DotSyntaxBaseIgnoredExpr *expr) { llvm_unreachable("Already type-checked"); } Type visitOverloadedDeclRefExpr(OverloadedDeclRefExpr *expr) { // For a reference to an overloaded declaration, we create a type variable // that will be equal to different types depending on which overload // is selected. auto locator = CS.getConstraintLocator(expr); auto tv = CS.createTypeVariable(locator, TVO_CanBindToLValue | TVO_CanBindToNoEscape); ArrayRef decls = expr->getDecls(); SmallVector choices; for (unsigned i = 0, n = decls.size(); i != n; ++i) { // If the result is invalid, skip it. // FIXME: Note this as invalid, in case we don't find a solution, // so we don't let errors cascade further. if (decls[i]->isInvalid()) continue; OverloadChoice choice = OverloadChoice(Type(), decls[i], expr->getFunctionRefKind()); choices.push_back(choice); } // If there are no valid overloads, give up. if (choices.empty()) return nullptr; // Record this overload set. CS.addOverloadSet(tv, choices, CurDC, locator); return tv; } Type visitUnresolvedDeclRefExpr(UnresolvedDeclRefExpr *expr) { // This is an error case, where we're trying to use type inference // to help us determine which declaration the user meant to refer to. // FIXME: Do we need to note that we're doing some kind of recovery? return CS.createTypeVariable(CS.getConstraintLocator(expr), TVO_CanBindToLValue | TVO_CanBindToNoEscape); } Type visitMemberRefExpr(MemberRefExpr *expr) { return addMemberRefConstraints(expr, expr->getBase(), expr->getMember().getDecl(), /*FIXME:*/FunctionRefKind::DoubleApply); } Type visitDynamicMemberRefExpr(DynamicMemberRefExpr *expr) { llvm_unreachable("Already typechecked"); } void setUnresolvedBaseType(UnresolvedMemberExpr *UME, Type ty) { UnresolvedBaseTypes.insert({UME, ty}); } Type getUnresolvedBaseType(UnresolvedMemberExpr *UME) { auto result = UnresolvedBaseTypes.find(UME); assert(result != UnresolvedBaseTypes.end()); return result->second; } virtual Type visitUnresolvedMemberExpr(UnresolvedMemberExpr *expr) { auto baseLocator = CS.getConstraintLocator( expr, ConstraintLocator::MemberRefBase); auto memberLocator = CS.getConstraintLocator(expr, ConstraintLocator::UnresolvedMember); // Since base type in this case is completely dependent on context it // should be marked as a potential hole. auto baseTy = CS.createTypeVariable(baseLocator, TVO_CanBindToNoEscape | TVO_CanBindToHole); setUnresolvedBaseType(expr, baseTy); auto memberTy = CS.createTypeVariable( memberLocator, TVO_CanBindToLValue | TVO_CanBindToNoEscape); // An unresolved member expression '.member' is modeled as a value member // constraint // // T0.Type[.member] == T1 // // for fresh type variables T0 and T1, which pulls out a static // member, i.e., an enum case or a static variable. auto baseMetaTy = MetatypeType::get(baseTy); CS.addUnresolvedValueMemberConstraint(baseMetaTy, expr->getName(), memberTy, CurDC, expr->getFunctionRefKind(), memberLocator); return memberTy; } Type visitUnresolvedMemberChainResultExpr( UnresolvedMemberChainResultExpr *expr) { auto *tail = expr->getSubExpr(); auto memberTy = CS.getType(tail); auto *base = expr->getChainBase(); assert(base == TypeChecker::getUnresolvedMemberChainBase(tail)); // The result type of the chain is is represented by a new type variable. auto locator = CS.getConstraintLocator( expr, ConstraintLocator::UnresolvedMemberChainResult); auto chainResultTy = CS.createTypeVariable( locator, TVO_CanBindToLValue | TVO_CanBindToHole | TVO_CanBindToNoEscape); auto chainBaseTy = getUnresolvedBaseType(base); // The result of the last element of the chain must be convertible to the // whole chain, and the type of the whole chain must be equal to the base. CS.addConstraint( ConstraintKind::Conversion, memberTy, chainBaseTy, CS.getConstraintLocator(tail, ConstraintLocator::RValueAdjustment)); CS.addConstraint(ConstraintKind::Conversion, memberTy, chainResultTy, locator); CS.addConstraint(ConstraintKind::Equal, chainBaseTy, chainResultTy, locator); return chainResultTy; } Type visitUnresolvedDotExpr(UnresolvedDotExpr *expr) { // If this is Builtin.type_join*, just return any type and move // on since we're going to discard this, and creating any type // variables for the reference will cause problems. auto &ctx = CS.getASTContext(); auto typeOperation = getTypeOperation(expr, ctx); if (typeOperation != TypeOperation::None) return ctx.TheAnyType; // If this is `Builtin.trigger_fallback_diagnostic()`, fail // without producing any diagnostics, in order to test fallback error. if (isTriggerFallbackDiagnosticBuiltin(expr, ctx)) return Type(); // Open a member constraint for constructor delegations on the // subexpr type. if (TypeChecker::getSelfForInitDelegationInConstructor(CS.DC, expr)) { auto baseTy = CS.getType(expr->getBase()) ->getWithoutSpecifierType(); // 'self' or 'super' will reference an instance, but the constructor // is semantically a member of the metatype. This: // self.init() // super.init() // is really more like: // self = Self.init() // self.super = Super.init() baseTy = MetatypeType::get(baseTy, ctx); auto methodTy = CS.createTypeVariable( CS.getConstraintLocator(expr, ConstraintLocator::ApplyFunction), TVO_CanBindToNoEscape); // FIXME: Once TVO_PrefersSubtypeBinding is replaced with something // better, we won't need the second type variable at all. { auto argTy = CS.createTypeVariable( CS.getConstraintLocator(expr, ConstraintLocator::ApplyArgument), (TVO_CanBindToLValue | TVO_CanBindToInOut | TVO_CanBindToNoEscape | TVO_PrefersSubtypeBinding)); CS.addConstraint( ConstraintKind::FunctionInput, methodTy, argTy, CS.getConstraintLocator(expr)); } CS.addValueMemberConstraint( baseTy, expr->getName(), methodTy, CurDC, expr->getFunctionRefKind(), /*outerAlternatives=*/{}, CS.getConstraintLocator(expr, ConstraintLocator::ConstructorMember)); // The result of the expression is the partial application of the // constructor to the subexpression. return methodTy; } return addMemberRefConstraints(expr, expr->getBase(), expr->getName(), expr->getFunctionRefKind(), expr->getOuterAlternatives()); } Type visitUnresolvedSpecializeExpr(UnresolvedSpecializeExpr *expr) { auto baseTy = CS.getType(expr->getSubExpr()); // We currently only support explicit specialization of generic types. // FIXME: We could support explicit function specialization. auto &de = CS.getASTContext().Diags; if (baseTy->is()) { de.diagnose(expr->getSubExpr()->getLoc(), diag::cannot_explicitly_specialize_generic_function); de.diagnose(expr->getLAngleLoc(), diag::while_parsing_as_left_angle_bracket); return Type(); } if (AnyMetatypeType *meta = baseTy->getAs()) { if (BoundGenericType *bgt = meta->getInstanceType()->getAs()) { ArrayRef typeVars = bgt->getGenericArgs(); auto specializations = expr->getUnresolvedParams(); // If we have too many generic arguments, complain. if (specializations.size() > typeVars.size()) { de.diagnose(expr->getSubExpr()->getLoc(), diag::type_parameter_count_mismatch, bgt->getDecl()->getName(), typeVars.size(), specializations.size(), false) .highlight(SourceRange(expr->getLAngleLoc(), expr->getRAngleLoc())); de.diagnose(bgt->getDecl(), diag::kind_declname_declared_here, DescriptiveDeclKind::GenericType, bgt->getDecl()->getName()); return Type(); } // Bind the specified generic arguments to the type variables in the // open type. auto *const locator = CS.getConstraintLocator(expr); const auto options = TypeResolutionOptions(TypeResolverContext::InExpression); for (size_t i = 0, size = specializations.size(); i < size; ++i) { const auto resolution = TypeResolution::forContextual( CS.DC, options, // Introduce type variables for unbound generics. OpenUnboundGenericType(CS, locator)); const auto result = resolution.resolveType(specializations[i]); if (result->hasError()) return Type(); CS.addConstraint(ConstraintKind::Bind, typeVars[i], result, locator); } return baseTy; } else { de.diagnose(expr->getSubExpr()->getLoc(), diag::not_a_generic_type, meta->getInstanceType()); de.diagnose(expr->getLAngleLoc(), diag::while_parsing_as_left_angle_bracket); return Type(); } } // FIXME: If the base type is a type variable, constrain it to a metatype // of a bound generic type. de.diagnose(expr->getSubExpr()->getLoc(), diag::not_a_generic_definition); de.diagnose(expr->getLAngleLoc(), diag::while_parsing_as_left_angle_bracket); return Type(); } Type visitSequenceExpr(SequenceExpr *expr) { // If a SequenceExpr survived until CSGen, then there was an upstream // error that was already reported. return Type(); } Type visitArrowExpr(ArrowExpr *expr) { // If an ArrowExpr survived until CSGen, then there was an upstream // error that was already reported. return Type(); } Type visitIdentityExpr(IdentityExpr *expr) { return CS.getType(expr->getSubExpr()); } Type visitAnyTryExpr(AnyTryExpr *expr) { return CS.getType(expr->getSubExpr()); } Type visitOptionalTryExpr(OptionalTryExpr *expr) { auto valueTy = CS.createTypeVariable(CS.getConstraintLocator(expr), TVO_PrefersSubtypeBinding | TVO_CanBindToNoEscape); Type optTy = getOptionalType(expr->getSubExpr()->getLoc(), valueTy); if (!optTy) return Type(); // Prior to Swift 5, 'try?' always adds an additional layer of optionality, // even if the sub-expression was already optional. if (CS.getASTContext().LangOpts.isSwiftVersionAtLeast(5)) { CS.addConstraint(ConstraintKind::Conversion, CS.getType(expr->getSubExpr()), optTy, CS.getConstraintLocator(expr)); } else { CS.addConstraint(ConstraintKind::OptionalObject, optTy, CS.getType(expr->getSubExpr()), CS.getConstraintLocator(expr)); } return optTy; } virtual Type visitParenExpr(ParenExpr *expr) { if (auto favoredTy = CS.getFavoredType(expr->getSubExpr())) { CS.setFavoredType(expr, favoredTy); } auto &ctx = CS.getASTContext(); auto parenType = CS.getType(expr->getSubExpr())->getInOutObjectType(); auto parenFlags = ParameterTypeFlags().withInOut(expr->isSemanticallyInOutExpr()); return ParenType::get(ctx, parenType, parenFlags); } Type visitTupleExpr(TupleExpr *expr) { // The type of a tuple expression is simply a tuple of the types of // its subexpressions. SmallVector elements; elements.reserve(expr->getNumElements()); for (unsigned i = 0, n = expr->getNumElements(); i != n; ++i) { auto *elt = expr->getElement(i); auto ty = CS.getType(elt); auto flags = ParameterTypeFlags() .withInOut(elt->isSemanticallyInOutExpr()) .withVariadic(isa(elt)); elements.push_back(TupleTypeElt(ty->getInOutObjectType(), expr->getElementName(i), flags)); } return TupleType::get(elements, CS.getASTContext()); } Type visitSubscriptExpr(SubscriptExpr *expr) { ValueDecl *decl = nullptr; if (expr->hasDecl()) { decl = expr->getDecl().getDecl(); if (decl->isInvalid()) return Type(); } auto *base = expr->getBase(); if (!isValidBaseOfMemberRef(base, diag::cannot_subscript_nil_literal)) return nullptr; return addSubscriptConstraints(expr, CS.getType(base), expr->getIndex(), decl, expr->getArgumentLabels(), expr->getUnlabeledTrailingClosureIndex()); } Type visitArrayExpr(ArrayExpr *expr) { // An array expression can be of a type T that conforms to the // ExpressibleByArrayLiteral protocol. ProtocolDecl *arrayProto = TypeChecker::getProtocol( CS.getASTContext(), expr->getLoc(), KnownProtocolKind::ExpressibleByArrayLiteral); if (!arrayProto) { return Type(); } // Assume that ExpressibleByArrayLiteral contains a single associated type. auto *elementAssocTy = arrayProto->getAssociatedTypeMembers()[0]; if (!elementAssocTy) return Type(); auto locator = CS.getConstraintLocator(expr); auto contextualType = CS.getContextualType(expr); auto joinElementTypes = [&](Optional elementType) { const auto elements = expr->getElements(); unsigned index = 0; using Iterator = decltype(elements)::iterator; CS.addJoinConstraint(locator, elements.begin(), elements.end(), elementType, [&](const auto it) { auto *locator = CS.getConstraintLocator(expr, LocatorPathElt::TupleElement(index++)); return std::make_pair(CS.getType(*it), locator); }); }; // If a contextual type exists for this expression, apply it directly. Optional arrayElementType; if (contextualType && (arrayElementType = ConstraintSystem::isArrayType(contextualType))) { CS.addConstraint(ConstraintKind::LiteralConformsTo, contextualType, arrayProto->getDeclaredInterfaceType(), locator); joinElementTypes(arrayElementType); return contextualType; } // Produce a specialized diagnostic if this is an attempt to initialize // or convert an array literal to a dictionary e.g. // `let _: [String: Int] = ["A", 0]` auto isDictionaryContextualType = [&](Type contextualType) -> bool { if (!contextualType) return false; auto type = contextualType->lookThroughAllOptionalTypes(); if (conformsToKnownProtocol( CS.DC, type, KnownProtocolKind::ExpressibleByArrayLiteral)) return false; return conformsToKnownProtocol( CS.DC, type, KnownProtocolKind::ExpressibleByDictionaryLiteral); }; if (isDictionaryContextualType(contextualType)) { auto &DE = CS.getASTContext().Diags; auto numElements = expr->getNumElements(); if (numElements == 0) { DE.diagnose(expr->getStartLoc(), diag::should_use_empty_dictionary_literal) .fixItInsert(expr->getEndLoc(), ":"); return nullptr; } bool isIniting = CS.getContextualTypePurpose(expr) == CTP_Initialization; DE.diagnose(expr->getStartLoc(), diag::should_use_dictionary_literal, contextualType->lookThroughAllOptionalTypes(), isIniting); auto diagnostic = DE.diagnose(expr->getStartLoc(), diag::meant_dictionary_lit); // If there is an even number of elements in the array, let's produce // a fix-it which suggests to replace "," with ":" to form a dictionary // literal. if ((numElements & 1) == 0) { const auto commaLocs = expr->getCommaLocs(); if (commaLocs.size() == numElements - 1) { for (unsigned i = 0, e = numElements / 2; i != e; ++i) diagnostic.fixItReplace(commaLocs[i * 2], ":"); } } return nullptr; } auto arrayTy = CS.createTypeVariable(locator, TVO_PrefersSubtypeBinding | TVO_CanBindToNoEscape); // The array must be an array literal type. CS.addConstraint(ConstraintKind::LiteralConformsTo, arrayTy, arrayProto->getDeclaredInterfaceType(), locator); // Its subexpression should be convertible to a tuple (T.Element...). Type arrayElementTy = DependentMemberType::get(arrayTy, elementAssocTy); // Introduce conversions from each element to the element type of the // array. joinElementTypes(arrayElementTy); // The array element type defaults to 'Any'. CS.addConstraint(ConstraintKind::Defaultable, arrayElementTy, CS.getASTContext().TheAnyType, locator); return arrayTy; } static bool isMergeableValueKind(Expr *expr) { return isa(expr) || isa(expr) || isa(expr); } Type visitDictionaryExpr(DictionaryExpr *expr) { ASTContext &C = CS.getASTContext(); // A dictionary expression can be of a type T that conforms to the // ExpressibleByDictionaryLiteral protocol. // FIXME: This isn't actually used for anything at the moment. ProtocolDecl *dictionaryProto = TypeChecker::getProtocol( C, expr->getLoc(), KnownProtocolKind::ExpressibleByDictionaryLiteral); if (!dictionaryProto) { return Type(); } // FIXME: Protect against broken standard library. auto keyAssocTy = dictionaryProto->getAssociatedType(C.Id_Key); auto valueAssocTy = dictionaryProto->getAssociatedType(C.Id_Value); auto locator = CS.getConstraintLocator(expr); auto contextualType = CS.getContextualType(expr); Type contextualDictionaryType = nullptr; Type contextualDictionaryKeyType = nullptr; Type contextualDictionaryValueType = nullptr; // If a contextual type exists for this expression, apply it directly. Optional> dictionaryKeyValue; if (contextualType && (dictionaryKeyValue = ConstraintSystem::isDictionaryType(contextualType))) { // Is the contextual type a dictionary type? contextualDictionaryType = contextualType; std::tie(contextualDictionaryKeyType, contextualDictionaryValueType) = *dictionaryKeyValue; // Form an explicit tuple type from the contextual type's key and value types. TupleTypeElt tupleElts[2] = { TupleTypeElt(contextualDictionaryKeyType), TupleTypeElt(contextualDictionaryValueType) }; Type contextualDictionaryElementType = TupleType::get(tupleElts, C); CS.addConstraint(ConstraintKind::LiteralConformsTo, contextualType, dictionaryProto->getDeclaredInterfaceType(), locator); unsigned index = 0; for (auto element : expr->getElements()) { CS.addConstraint(ConstraintKind::Conversion, CS.getType(element), contextualDictionaryElementType, CS.getConstraintLocator( expr, LocatorPathElt::TupleElement(index++))); } return contextualDictionaryType; } auto dictionaryTy = CS.createTypeVariable(locator, TVO_PrefersSubtypeBinding | TVO_CanBindToNoEscape); // The dictionary must be a dictionary literal type. CS.addConstraint(ConstraintKind::LiteralConformsTo, dictionaryTy, dictionaryProto->getDeclaredInterfaceType(), locator); // Its subexpression should be convertible to a tuple ((T.Key,T.Value)...). ConstraintLocatorBuilder locatorBuilder(locator); auto dictionaryKeyTy = DependentMemberType::get(dictionaryTy, keyAssocTy); auto dictionaryValueTy = DependentMemberType::get(dictionaryTy, valueAssocTy); TupleTypeElt tupleElts[2] = { TupleTypeElt(dictionaryKeyTy), TupleTypeElt(dictionaryValueTy) }; Type elementTy = TupleType::get(tupleElts, C); // Keep track of which elements have been "merged". This way, we won't create // needless conversion constraints for elements whose equivalence classes have // been merged. llvm::DenseSet mergedElements; // If no contextual type is present, Merge equivalence classes of key // and value types as necessary. if (!CS.getContextualType(expr)) { for (auto element1 : expr->getElements()) { for (auto element2 : expr->getElements()) { if (element1 == element2) continue; auto tty1 = CS.getType(element1)->getAs(); auto tty2 = CS.getType(element2)->getAs(); if (tty1 && tty2) { auto mergedKey = false; auto mergedValue = false; auto keyTyvar1 = tty1->getElementTypes()[0]-> getAs(); auto keyTyvar2 = tty2->getElementTypes()[0]-> getAs(); auto keyExpr1 = cast(element1)->getElements()[0]; auto keyExpr2 = cast(element2)->getElements()[0]; if (keyExpr1->getKind() == keyExpr2->getKind() && isMergeableValueKind(keyExpr1)) { mergedKey = mergeRepresentativeEquivalenceClasses(CS, keyTyvar1, keyTyvar2); } auto valueTyvar1 = tty1->getElementTypes()[1]-> getAs(); auto valueTyvar2 = tty2->getElementTypes()[1]-> getAs(); auto elemExpr1 = cast(element1)->getElements()[1]; auto elemExpr2 = cast(element2)->getElements()[1]; if (elemExpr1->getKind() == elemExpr2->getKind() && isMergeableValueKind(elemExpr1)) { mergedValue = mergeRepresentativeEquivalenceClasses(CS, valueTyvar1, valueTyvar2); } if (mergedKey && mergedValue) mergedElements.insert(element2); } } } } // Introduce conversions from each element to the element type of the // dictionary. (If the equivalence class of an element has already been // merged with a previous one, skip it.) unsigned index = 0; for (auto element : expr->getElements()) { if (!mergedElements.count(element)) CS.addConstraint(ConstraintKind::Conversion, CS.getType(element), elementTy, CS.getConstraintLocator( expr, LocatorPathElt::TupleElement(index++))); } // The dictionary key type defaults to 'AnyHashable'. auto &ctx = CS.getASTContext(); if (dictionaryKeyTy->isTypeVariableOrMember() && ctx.getAnyHashableDecl()) { auto anyHashable = ctx.getAnyHashableDecl(); CS.addConstraint(ConstraintKind::Defaultable, dictionaryKeyTy, anyHashable->getDeclaredInterfaceType(), locator); } // The dictionary value type defaults to 'Any'. if (dictionaryValueTy->isTypeVariableOrMember()) { CS.addConstraint(ConstraintKind::Defaultable, dictionaryValueTy, ctx.TheAnyType, locator); } return dictionaryTy; } Type visitDynamicSubscriptExpr(DynamicSubscriptExpr *expr) { return addSubscriptConstraints(expr, CS.getType(expr->getBase()), expr->getIndex(), /*decl*/ nullptr, expr->getArgumentLabels(), expr->getUnlabeledTrailingClosureIndex()); } Type visitTupleElementExpr(TupleElementExpr *expr) { ASTContext &context = CS.getASTContext(); DeclNameRef name( context.getIdentifier(llvm::utostr(expr->getFieldNumber()))); return addMemberRefConstraints(expr, expr->getBase(), name, FunctionRefKind::Unapplied, /*outerAlternatives=*/{}); } FunctionType *inferClosureType(ClosureExpr *closure) { SmallVector closureParams; if (auto *paramList = closure->getParameters()) { for (unsigned i = 0, n = paramList->size(); i != n; ++i) { const auto *param = paramList->get(i); auto *paramLoc = CS.getConstraintLocator(closure, LocatorPathElt::TupleElement(i)); // If one of the parameters represents a destructured tuple // e.g. `{ (x: Int, (y: Int, z: Int)) in ... }` let's fail // inference here and not attempt to solve the system because: // // a. Destructuring has already been diagnosed by the parser; // b. Body of the closure would have error expressions for // each incorrect parameter reference and solver wouldn't // be able to produce any viable solutions. if (param->isDestructured()) return nullptr; Type externalType; if (param->getTypeRepr()) { auto declaredTy = CS.getVarType(param); externalType = CS.openUnboundGenericTypes(declaredTy, paramLoc); } else { // Let's allow parameters which haven't been explicitly typed // to become holes by default, this helps in situations like // `foo { a in }` where `foo` doesn't exist. externalType = CS.createTypeVariable( paramLoc, TVO_CanBindToInOut | TVO_CanBindToNoEscape | TVO_CanBindToHole); } closureParams.push_back(param->toFunctionParam(externalType)); } } auto extInfo = CS.closureEffects(closure); // Closure expressions always have function type. In cases where a // parameter or return type is omitted, a fresh type variable is used to // stand in for that parameter or return type, allowing it to be inferred // from context. Type resultTy = [&] { if (closure->hasExplicitResultType()) { if (auto declaredTy = closure->getExplicitResultType()) { return declaredTy; } const auto resolvedTy = resolveTypeReferenceInExpression( closure->getExplicitResultTypeRepr(), TypeResolverContext::InExpression, CS.getConstraintLocator(closure, ConstraintLocator::ClosureResult)); if (resolvedTy) return resolvedTy; } if (auto contextualType = CS.getContextualType(closure)) { if (auto fnType = contextualType->getAs()) return fnType->getResult(); } // If no return type was specified, create a fresh type // variable for it and mark it as possible hole. // // If this is a multi-statement closure, let's mark result // as potential hole right away. return Type(CS.createTypeVariable( CS.getConstraintLocator(closure, ConstraintLocator::ClosureResult), shouldTypeCheckInEnclosingExpression(closure) ? 0 : TVO_CanBindToHole)); }(); return FunctionType::get(closureParams, resultTy, extInfo); } /// Produces a type for the given pattern, filling in any missing /// type information with fresh type variables. /// /// \param pattern The pattern. /// /// \param locator The locator to use for generated constraints and /// type variables. /// /// \param externalPatternType The type imposed by the enclosing pattern, /// if any. This will be non-null in cases where there is, e.g., a /// pattern such as "is SubClass". /// /// \param bindPatternVarsOneWay When true, generate fresh type variables /// for the types of each variable declared within the pattern, along /// with a one-way constraint binding that to the type to which the /// variable will be ascribed or inferred. Type getTypeForPattern( Pattern *pattern, ConstraintLocatorBuilder locator, Type externalPatternType, bool bindPatternVarsOneWay, PatternBindingDecl *patternBinding = nullptr, unsigned patternBindingIndex = 0) { // If there's no pattern, then we have an unknown subpattern. Create a // type variable. if (!pattern) { return CS.createTypeVariable(CS.getConstraintLocator(locator), TVO_CanBindToNoEscape); } // Local function that must be called for each "return" throughout this // function, to set the type of the pattern. auto setType = [&](Type type) { CS.setType(pattern, type); return type; }; switch (pattern->getKind()) { case PatternKind::Paren: { auto *paren = cast(pattern); // Parentheses don't affect the canonical type, but record them as // type sugar. if (externalPatternType && isa(externalPatternType.getPointer())) { externalPatternType = cast(externalPatternType.getPointer()) ->getUnderlyingType(); } auto underlyingType = getTypeForPattern(paren->getSubPattern(), locator, externalPatternType, bindPatternVarsOneWay); if (!underlyingType) return Type(); return setType(ParenType::get(CS.getASTContext(), underlyingType)); } case PatternKind::Binding: { auto *subPattern = cast(pattern)->getSubPattern(); auto type = getTypeForPattern(subPattern, locator, externalPatternType, bindPatternVarsOneWay); if (!type) return Type(); // Var doesn't affect the type. return setType(type); } case PatternKind::Any: { return setType( externalPatternType ? externalPatternType : CS.createTypeVariable(CS.getConstraintLocator(locator), TVO_CanBindToNoEscape)); } case PatternKind::Named: { auto var = cast(pattern)->getDecl(); Type varType; // Determine whether optionality will be required. auto ROK = ReferenceOwnership::Strong; if (auto *OA = var->getAttrs().getAttribute()) ROK = OA->get(); auto optionality = optionalityOf(ROK); // If we have a type from an initializer expression, and that // expression does not produce an InOut type, use it. This // will avoid exponential typecheck behavior in the case of // tuples, nested arrays, and dictionary literals. // // FIXME: This should be handled in the solver, not here. // // Otherwise, create a new type variable. if (var->getParentPatternBinding() && !var->hasAttachedPropertyWrapper() && optionality != ReferenceOwnershipOptionality::Required) { if (auto boundExpr = locator.trySimplifyToExpr()) { if (!boundExpr->isSemanticallyInOutExpr()) { varType = CS.getType(boundExpr)->getRValueType(); } } } if (!varType) varType = CS.createTypeVariable(CS.getConstraintLocator(locator), TVO_CanBindToNoEscape); // When we are supposed to bind pattern variables, create a fresh // type variable and a one-way constraint to assign it to either the // deduced type or the externally-imposed type. Type oneWayVarType; if (bindPatternVarsOneWay) { oneWayVarType = CS.createTypeVariable( CS.getConstraintLocator(locator), TVO_CanBindToNoEscape); CS.addConstraint( ConstraintKind::OneWayEqual, oneWayVarType, externalPatternType ? externalPatternType : varType, locator); } // If there is an externally-imposed type. switch (optionality) { case ReferenceOwnershipOptionality::Required: varType = TypeChecker::getOptionalType(var->getLoc(), varType); assert(!varType->hasError()); if (oneWayVarType) { oneWayVarType = TypeChecker::getOptionalType(var->getLoc(), oneWayVarType); } break; case ReferenceOwnershipOptionality::Allowed: case ReferenceOwnershipOptionality::Disallowed: break; } // If we have a type to ascribe to the variable, do so now. if (oneWayVarType) CS.setType(var, oneWayVarType); return setType(varType); } case PatternKind::Typed: { // FIXME: Need a better locator for a pattern as a base. // Compute the type ascribed to the pattern. auto contextualPattern = patternBinding ? ContextualPattern::forPatternBindingDecl( patternBinding, patternBindingIndex) : ContextualPattern::forRawPattern(pattern, CurDC); Type type = TypeChecker::typeCheckPattern(contextualPattern); if (!type) return Type(); // Look through reference storage types. type = type->getReferenceStorageReferent(); Type openedType = CS.openUnboundGenericTypes(type, locator); assert(openedType); auto *subPattern = cast(pattern)->getSubPattern(); // Determine the subpattern type. It will be convertible to the // ascribed type. Type subPatternType = getTypeForPattern( subPattern, locator.withPathElement(LocatorPathElt::PatternMatch(subPattern)), openedType, bindPatternVarsOneWay); if (!subPatternType) return Type(); CS.addConstraint( ConstraintKind::Conversion, subPatternType, openedType, locator.withPathElement(LocatorPathElt::PatternMatch(pattern))); return setType(openedType); } case PatternKind::Tuple: { auto tuplePat = cast(pattern); // If there's an externally-imposed type, decompose it into element // types so long as we have the right number of such types. SmallVector externalEltTypes; if (externalPatternType) { AnyFunctionType::decomposeInput(externalPatternType, externalEltTypes); // If we have the wrong number of elements, we may not be able to // provide more specific types. if (tuplePat->getNumElements() != externalEltTypes.size()) { externalEltTypes.clear(); // Implicit tupling. if (tuplePat->getNumElements() == 1) { externalEltTypes.push_back( AnyFunctionType::Param(externalPatternType)); } } } SmallVector tupleTypeElts; tupleTypeElts.reserve(tuplePat->getNumElements()); for (unsigned i = 0, e = tuplePat->getNumElements(); i != e; ++i) { auto &tupleElt = tuplePat->getElement(i); Type externalEltType; if (!externalEltTypes.empty()) externalEltType = externalEltTypes[i].getPlainType(); auto *eltPattern = tupleElt.getPattern(); Type eltTy = getTypeForPattern( eltPattern, locator.withPathElement(LocatorPathElt::PatternMatch(eltPattern)), externalEltType, bindPatternVarsOneWay); if (!eltTy) return Type(); tupleTypeElts.push_back(TupleTypeElt(eltTy, tupleElt.getLabel())); } return setType(TupleType::get(tupleTypeElts, CS.getASTContext())); } case PatternKind::OptionalSome: { // Remove an optional from the object type. if (externalPatternType) { Type objVar = CS.createTypeVariable( CS.getConstraintLocator( locator.withPathElement(ConstraintLocator::OptionalPayload)), TVO_CanBindToNoEscape); CS.addConstraint( ConstraintKind::OptionalObject, externalPatternType, objVar, locator.withPathElement(LocatorPathElt::PatternMatch(pattern))); externalPatternType = objVar; } auto *subPattern = cast(pattern)->getSubPattern(); // The subpattern must have optional type. Type subPatternType = getTypeForPattern( subPattern, locator.withPathElement(LocatorPathElt::PatternMatch(subPattern)), externalPatternType, bindPatternVarsOneWay); if (!subPatternType) return Type(); return setType(OptionalType::get(subPatternType)); } case PatternKind::Is: { auto isPattern = cast(pattern); const Type castType = resolveTypeReferenceInExpression( isPattern->getCastTypeRepr(), TypeResolverContext::InExpression, locator.withPathElement(LocatorPathElt::PatternMatch(pattern))); if (!castType) return Type(); auto *subPattern = isPattern->getSubPattern(); Type subPatternType = getTypeForPattern( subPattern, locator.withPathElement(LocatorPathElt::PatternMatch(subPattern)), castType, bindPatternVarsOneWay); if (!subPatternType) return Type(); // Make sure we can cast from the subpattern type to the type we're // checking; if it's impossible, fail. CS.addConstraint( ConstraintKind::CheckedCast, subPatternType, castType, locator.withPathElement(LocatorPathElt::PatternMatch(pattern))); // Allow `is` pattern to infer type from context which is then going // to be propaged down to its sub-pattern via conversion. This enables // correct handling of patterns like `_ as Foo` where `_` would // get a type of `Foo` but `is` pattern enclosing it could still be // inferred from enclosing context. auto isType = CS.createTypeVariable(CS.getConstraintLocator(pattern), TVO_CanBindToNoEscape); CS.addConstraint( ConstraintKind::Conversion, subPatternType, isType, locator.withPathElement(LocatorPathElt::PatternMatch(pattern))); return setType(isType); } case PatternKind::Bool: return setType(CS.getASTContext().getBoolDecl()->getDeclaredInterfaceType()); case PatternKind::EnumElement: { auto enumPattern = cast(pattern); // Create a type variable to represent the pattern. Type patternType = CS.createTypeVariable(CS.getConstraintLocator(locator), TVO_CanBindToNoEscape); // Form the member constraint for a reference to a member of this // type. Type baseType; Type memberType = CS.createTypeVariable( CS.getConstraintLocator(locator), TVO_CanBindToLValue | TVO_CanBindToNoEscape); FunctionRefKind functionRefKind = FunctionRefKind::Compound; if (enumPattern->getParentType() || enumPattern->getParentTypeRepr()) { // Resolve the parent type. const auto parentType = [&] { auto *const patternMatchLoc = CS.getConstraintLocator( locator, {LocatorPathElt::PatternMatch(pattern), ConstraintLocator::ParentType}); // FIXME: Sometimes the parent type is realized eagerly in // ResolvePattern::visitUnresolvedDotExpr, so we have to open it // ex post facto. Remove this once we learn how to resolve patterns // while generating constraints to keep the opening of generic types // contained within the type resolver. if (const auto preresolvedTy = enumPattern->getParentType()) { const auto openedTy = CS.openUnboundGenericTypes(preresolvedTy, patternMatchLoc); assert(openedTy); return openedTy; } return resolveTypeReferenceInExpression( enumPattern->getParentTypeRepr(), TypeResolverContext::InExpression, patternMatchLoc); }(); if (!parentType) return Type(); // Perform member lookup into the parent's metatype. Type parentMetaType = MetatypeType::get(parentType); CS.addValueMemberConstraint( parentMetaType, enumPattern->getName(), memberType, CurDC, functionRefKind, {}, CS.getConstraintLocator(locator, {LocatorPathElt::PatternMatch(pattern), ConstraintLocator::Member})); // Parent type needs to be convertible to the pattern type; this // accounts for cases where the pattern type is existential. CS.addConstraint( ConstraintKind::Conversion, parentType, patternType, locator.withPathElement(LocatorPathElt::PatternMatch(pattern))); baseType = parentType; } else { // Use the pattern type for member lookup. CS.addUnresolvedValueMemberConstraint( MetatypeType::get(patternType), enumPattern->getName(), memberType, CurDC, functionRefKind, locator.withPathElement(LocatorPathElt::PatternMatch(pattern))); baseType = patternType; } if (auto subPattern = enumPattern->getSubPattern()) { // When there is a subpattern, the member will have function type, // and we're matching the type of that subpattern to the parameter // types. Type subPatternType = getTypeForPattern( subPattern, locator, Type(), bindPatternVarsOneWay); if (!subPatternType) return Type(); SmallVector params; AnyFunctionType::decomposeInput(subPatternType, params); // Remove parameter labels; they aren't used when matching cases, // but outright conflicts will be checked during coercion. for (auto ¶m : params) { param = param.getWithoutLabel(); } Type outputType = CS.createTypeVariable( CS.getConstraintLocator(locator), TVO_CanBindToNoEscape); Type functionType = FunctionType::get(params, outputType); CS.addConstraint( ConstraintKind::Equal, functionType, memberType, locator.withPathElement(LocatorPathElt::PatternMatch(pattern))); CS.addConstraint( ConstraintKind::Conversion, outputType, baseType, locator.withPathElement(LocatorPathElt::PatternMatch(pattern))); } return setType(patternType); } // Refutable patterns occur when checking the PatternBindingDecls in an // if/let or while/let condition. They always require an initial value, // so they always allow unspecified types. case PatternKind::Expr: // TODO: we could try harder here, e.g. for enum elements to provide the // enum type. return setType( CS.createTypeVariable( CS.getConstraintLocator(locator), TVO_CanBindToNoEscape)); } llvm_unreachable("Unhandled pattern kind"); } Type visitCaptureListExpr(CaptureListExpr *expr) { // The type of the capture list is just the type of its closure. return CS.getType(expr->getClosureBody()); } Type visitClosureExpr(ClosureExpr *closure) { auto *locator = CS.getConstraintLocator(closure); auto closureType = CS.createTypeVariable(locator, TVO_CanBindToNoEscape); // Collect any variable references whose types involve type variables, // because there will be a dependency on those type variables once we have // generated constraints for the closure body. This includes references // to other closure params such as in `{ x in { x }}` where the inner // closure is dependent on the outer closure's param type, as well as // cases like `for i in x where bar({ i })` where there's a dependency on // the type variable for the pattern `i`. struct CollectVarRefs : public ASTWalker { ConstraintSystem &cs; llvm::SmallVector varRefs; bool hasErrorExprs = false; CollectVarRefs(ConstraintSystem &cs) : cs(cs) { } bool shouldWalkCaptureInitializerExpressions() override { return true; } std::pair walkToExprPre(Expr *expr) override { // If there are any error expressions in this closure // it wouldn't be possible to infer its type. if (isa(expr)) { hasErrorExprs = true; return {false, nullptr}; } // Retrieve type variables from references to var decls. if (auto *declRef = dyn_cast(expr)) { if (auto *varDecl = dyn_cast(declRef->getDecl())) { if (auto varType = cs.getTypeIfAvailable(varDecl)) { varType->getTypeVariables(varRefs); } } } // FIXME: We can see UnresolvedDeclRefExprs here because we have // not yet run preCheckExpression() on the entire closure body // yet. // // We could consider pre-checking more eagerly. if (auto *declRef = dyn_cast(expr)) { auto name = declRef->getName(); auto loc = declRef->getLoc(); if (name.isSimpleName() && loc.isValid()) { auto *varDecl = dyn_cast_or_null( ASTScope::lookupSingleLocalDecl(cs.DC->getParentSourceFile(), name.getFullName(), loc)); if (varDecl) if (auto varType = cs.getTypeIfAvailable(varDecl)) varType->getTypeVariables(varRefs); } } return { true, expr }; } } collectVarRefs(CS); closure->walk(collectVarRefs); // If walker discovered error expressions, let's fail constraint // genreation only if closure is going to participate // in the type-check. This allows us to delay validation of // multi-statement closures until body is opened. if (shouldTypeCheckInEnclosingExpression(closure) && collectVarRefs.hasErrorExprs) { return Type(); } auto inferredType = inferClosureType(closure); if (!inferredType || inferredType->hasError()) return Type(); CS.addUnsolvedConstraint( Constraint::create(CS, ConstraintKind::DefaultClosureType, closureType, inferredType, locator, collectVarRefs.varRefs)); CS.setClosureType(closure, inferredType); return closureType; } Type visitAutoClosureExpr(AutoClosureExpr *expr) { // AutoClosureExpr is introduced by CSApply. llvm_unreachable("Already type-checked"); } Type visitInOutExpr(InOutExpr *expr) { // The address-of operator produces an explicit inout T from an lvalue T. // We model this with the constraint // // S < lvalue T // // where T is a fresh type variable. auto lvalue = CS.createTypeVariable(CS.getConstraintLocator(expr), TVO_CanBindToNoEscape); auto bound = LValueType::get(lvalue); auto result = InOutType::get(lvalue); CS.addConstraint(ConstraintKind::Conversion, CS.getType(expr->getSubExpr()), bound, CS.getConstraintLocator(expr)); return result; } Type visitVarargExpansionExpr(VarargExpansionExpr *expr) { // Create a fresh type variable. auto element = CS.createTypeVariable(CS.getConstraintLocator(expr), TVO_CanBindToNoEscape); // Try to build the appropriate type for a variadic argument list of // the fresh element type. If that failed, just bail out. auto array = TypeChecker::getArraySliceType(expr->getLoc(), element); if (array->hasError()) return element; // Require the operand to be convertible to the array type. CS.addConstraint(ConstraintKind::Conversion, CS.getType(expr->getSubExpr()), array, CS.getConstraintLocator(expr)); return array; } Type visitDynamicTypeExpr(DynamicTypeExpr *expr) { auto tv = CS.createTypeVariable(CS.getConstraintLocator(expr), TVO_CanBindToNoEscape); CS.addConstraint(ConstraintKind::DynamicTypeOf, tv, CS.getType(expr->getBase()), CS.getConstraintLocator(expr, ConstraintLocator::RValueAdjustment)); return tv; } Type visitOpaqueValueExpr(OpaqueValueExpr *expr) { assert(expr->isPlaceholder() && "Already type checked"); return expr->getType(); } Type visitPropertyWrapperValuePlaceholderExpr( PropertyWrapperValuePlaceholderExpr *expr) { return expr->getType(); } Type visitDefaultArgumentExpr(DefaultArgumentExpr *expr) { return expr->getType(); } Type visitApplyExpr(ApplyExpr *expr) { auto fnExpr = expr->getFn(); SmallVector scratch; associateArgumentLabels( CS.getConstraintLocator(expr), {expr->getArgumentLabels(scratch), expr->getUnlabeledTrailingClosureIndex()}, /*labelsArePermanent=*/isa(expr)); if (auto *UDE = dyn_cast(fnExpr)) { auto typeOperation = getTypeOperation(UDE, CS.getASTContext()); if (typeOperation != TypeOperation::None) return resultOfTypeOperation(typeOperation, expr->getArg()); } // The result type is a fresh type variable. Type resultType = CS.createTypeVariable( CS.getConstraintLocator(expr, ConstraintLocator::FunctionResult), TVO_CanBindToNoEscape); // A direct call to a ClosureExpr makes it noescape. FunctionType::ExtInfo extInfo; if (isa(fnExpr->getSemanticsProvidingExpr())) extInfo = extInfo.withNoEscape(); // FIXME: Redesign the AST so that an ApplyExpr directly stores a list of // arguments together with their inout-ness, instead of a single // ParenExpr or TupleExpr. SmallVector params; AnyFunctionType::decomposeInput(CS.getType(expr->getArg()), params); CS.addConstraint(ConstraintKind::ApplicableFunction, FunctionType::get(params, resultType, extInfo), CS.getType(expr->getFn()), CS.getConstraintLocator(expr, ConstraintLocator::ApplyFunction)); // If we ended up resolving the result type variable to a concrete type, // set it as the favored type for this expression. Type fixedType = CS.getFixedTypeRecursive(resultType, /*wantRvalue=*/true); if (!fixedType->isTypeVariableOrMember()) { CS.setFavoredType(expr, fixedType.getPointer()); resultType = fixedType; } return resultType; } Type getSuperType(VarDecl *selfDecl, SourceLoc diagLoc, Diag<> diag_not_in_class, Diag<> diag_no_base_class) { DeclContext *typeContext = selfDecl->getDeclContext()->getParent(); assert(typeContext && "constructor without parent context?!"); auto &de = CS.getASTContext().Diags; ClassDecl *classDecl = typeContext->getSelfClassDecl(); if (!classDecl) { de.diagnose(diagLoc, diag_not_in_class); return Type(); } if (!classDecl->hasSuperclass()) { de.diagnose(diagLoc, diag_no_base_class); return Type(); } auto selfTy = CS.DC->mapTypeIntoContext( typeContext->getDeclaredInterfaceType()); auto superclassTy = selfTy->getSuperclass(); if (!superclassTy) return Type(); if (selfDecl->getInterfaceType()->is()) superclassTy = MetatypeType::get(superclassTy); return superclassTy; } Type visitRebindSelfInConstructorExpr(RebindSelfInConstructorExpr *expr) { // The result is void. return TupleType::getEmpty(CS.getASTContext()); } Type visitIfExpr(IfExpr *expr) { // Condition must convert to Bool. auto boolDecl = CS.getASTContext().getBoolDecl(); if (!boolDecl) return Type(); CS.addConstraint( ConstraintKind::Conversion, CS.getType(expr->getCondExpr()), boolDecl->getDeclaredInterfaceType(), CS.getConstraintLocator(expr, ConstraintLocator::Condition)); // The branches must be convertible to a common type. return CS.addJoinConstraint( CS.getConstraintLocator(expr), {{CS.getType(expr->getThenExpr()), CS.getConstraintLocator(expr, LocatorPathElt::TernaryBranch(true))}, {CS.getType(expr->getElseExpr()), CS.getConstraintLocator(expr, LocatorPathElt::TernaryBranch(false))}}); } virtual Type visitImplicitConversionExpr(ImplicitConversionExpr *expr) { llvm_unreachable("Already type-checked"); } Type createTypeVariableAndDisjunctionForIUOCoercion(Type toType, ConstraintLocator *locator) { auto typeVar = CS.createTypeVariable(locator, TVO_CanBindToNoEscape); CS.buildDisjunctionForImplicitlyUnwrappedOptional(typeVar, toType, locator); return typeVar; } Type visitForcedCheckedCastExpr(ForcedCheckedCastExpr *expr) { auto fromExpr = expr->getSubExpr(); if (!fromExpr) // Either wasn't constructed correctly or wasn't folded. return nullptr; auto *const repr = expr->getCastTypeRepr(); // Validate the resulting type. const auto toType = resolveTypeReferenceInExpression( repr, TypeResolverContext::ExplicitCastExpr, CS.getConstraintLocator(expr)); if (!toType) return nullptr; // Cache the type we're casting to. if (repr) CS.setType(repr, toType); auto fromType = CS.getType(fromExpr); auto locator = CS.getConstraintLocator(expr); // The source type can be checked-cast to the destination type. CS.addConstraint(ConstraintKind::CheckedCast, fromType, toType, locator); // If the result type was declared IUO, add a disjunction for // bindings for the result of the coercion. if (repr && repr->getKind() == TypeReprKind::ImplicitlyUnwrappedOptional) return createTypeVariableAndDisjunctionForIUOCoercion(toType, locator); return toType; } Type visitCoerceExpr(CoerceExpr *expr) { // Validate the resulting type. auto *const repr = expr->getCastTypeRepr(); const auto toType = resolveTypeReferenceInExpression( repr, TypeResolverContext::ExplicitCastExpr, CS.getConstraintLocator(expr)); if (!toType) return nullptr; // Cache the type we're casting to. if (repr) CS.setType(repr, toType); auto fromType = CS.getType(expr->getSubExpr()); auto locator = CS.getConstraintLocator(expr); // Add a conversion constraint for the direct conversion between // types. CS.addExplicitConversionConstraint(fromType, toType, RememberChoice, locator); // If the result type was declared IUO, add a disjunction for // bindings for the result of the coercion. if (repr && repr->getKind() == TypeReprKind::ImplicitlyUnwrappedOptional) return createTypeVariableAndDisjunctionForIUOCoercion(toType, locator); return toType; } Type visitConditionalCheckedCastExpr(ConditionalCheckedCastExpr *expr) { auto fromExpr = expr->getSubExpr(); if (!fromExpr) // Either wasn't constructed correctly or wasn't folded. return nullptr; // Validate the resulting type. auto *const repr = expr->getCastTypeRepr(); const auto toType = resolveTypeReferenceInExpression( repr, TypeResolverContext::ExplicitCastExpr, CS.getConstraintLocator(expr)); if (!toType) return nullptr; // Cache the type we're casting to. if (repr) CS.setType(repr, toType); auto fromType = CS.getType(fromExpr); auto locator = CS.getConstraintLocator(expr); CS.addConstraint(ConstraintKind::CheckedCast, fromType, toType, locator); // If the result type was declared IUO, add a disjunction for // bindings for the result of the coercion. if (repr && repr->getKind() == TypeReprKind::ImplicitlyUnwrappedOptional) return createTypeVariableAndDisjunctionForIUOCoercion( OptionalType::get(toType), locator); return OptionalType::get(toType); } Type visitIsExpr(IsExpr *expr) { // Validate the type. // FIXME: Locator for the cast type? auto &ctx = CS.getASTContext(); const auto toType = resolveTypeReferenceInExpression( expr->getCastTypeRepr(), TypeResolverContext::ExplicitCastExpr, CS.getConstraintLocator(expr)); if (!toType) return nullptr; // Cache the type we're checking. CS.setType(expr->getCastTypeRepr(), toType); // Add a checked cast constraint. auto fromType = CS.getType(expr->getSubExpr()); CS.addConstraint(ConstraintKind::CheckedCast, fromType, toType, CS.getConstraintLocator(expr)); // The result is Bool. auto boolDecl = ctx.getBoolDecl(); if (!boolDecl) { ctx.Diags.diagnose(SourceLoc(), diag::broken_bool); return Type(); } return boolDecl->getDeclaredInterfaceType(); } Type visitDiscardAssignmentExpr(DiscardAssignmentExpr *expr) { /// Diagnose a '_' that isn't on the immediate LHS of an assignment. if (!CorrectDiscardAssignmentExprs.count(expr)) { auto &DE = CS.getASTContext().Diags; DE.diagnose(expr->getLoc(), diag::discard_expr_outside_of_assignment); return Type(); } auto locator = CS.getConstraintLocator(expr); auto typeVar = CS.createTypeVariable(locator, TVO_CanBindToNoEscape); return LValueType::get(typeVar); } static Type genAssignDestType(Expr *expr, ConstraintSystem &CS) { if (auto *TE = dyn_cast(expr)) { SmallVector destTupleTypes; for (unsigned i = 0; i != TE->getNumElements(); ++i) { Type subType = genAssignDestType(TE->getElement(i), CS); destTupleTypes.push_back(TupleTypeElt(subType, TE->getElementName(i))); } return TupleType::get(destTupleTypes, CS.getASTContext()); } else { auto *locator = CS.getConstraintLocator(expr); auto isOrCanBeLValueType = [](Type type) { if (auto *typeVar = type->getAs()) { return typeVar->getImpl().canBindToLValue(); } return type->is(); }; auto exprType = CS.getType(expr); if (!isOrCanBeLValueType(exprType)) { // Pretend that destination is an l-value type. exprType = LValueType::get(exprType); (void)CS.recordFix(TreatRValueAsLValue::create(CS, locator)); } auto *destTy = CS.createTypeVariable(locator, TVO_CanBindToNoEscape); CS.addConstraint(ConstraintKind::Bind, LValueType::get(destTy), exprType, locator); return destTy; } } /// Scout out the specified destination of an AssignExpr to recursively /// identify DiscardAssignmentExpr in legal places. We can only allow them /// in simple pattern-like expressions, so we reject anything complex here. void markAcceptableDiscardExprs(Expr *E) { if (!E) return; if (auto *PE = dyn_cast(E)) return markAcceptableDiscardExprs(PE->getSubExpr()); if (auto *TE = dyn_cast(E)) { for (auto &elt : TE->getElements()) markAcceptableDiscardExprs(elt); return; } if (auto *DAE = dyn_cast(E)) CorrectDiscardAssignmentExprs.insert(DAE); // Otherwise, we can't support this. } Type visitAssignExpr(AssignExpr *expr) { // Handle invalid code. if (!expr->getDest() || !expr->getSrc()) return Type(); Type destTy = genAssignDestType(expr->getDest(), CS); CS.addConstraint(ConstraintKind::Conversion, CS.getType(expr->getSrc()), destTy, CS.getConstraintLocator(expr)); return TupleType::getEmpty(CS.getASTContext()); } Type visitUnresolvedPatternExpr(UnresolvedPatternExpr *expr) { // If there are UnresolvedPatterns floating around after pattern type // checking, they are definitely invalid. However, we will // diagnose that condition elsewhere; to avoid unnecessary noise errors, // just plop an open type variable here. auto locator = CS.getConstraintLocator(expr); auto typeVar = CS.createTypeVariable(locator, TVO_CanBindToLValue | TVO_CanBindToNoEscape); return typeVar; } /// Get the type T? /// /// This is not the ideal source location, but it's only used for /// diagnosing ill-formed standard libraries, so it really isn't /// worth QoI efforts. Type getOptionalType(SourceLoc optLoc, Type valueTy) { auto optTy = TypeChecker::getOptionalType(optLoc, valueTy); if (optTy->hasError() || TypeChecker::requireOptionalIntrinsics(CS.getASTContext(), optLoc)) return Type(); return optTy; } Type visitBindOptionalExpr(BindOptionalExpr *expr) { // The operand must be coercible to T?, and we will have type T. auto locator = CS.getConstraintLocator(expr); auto objectTy = CS.createTypeVariable(locator, TVO_PrefersSubtypeBinding | TVO_CanBindToLValue | TVO_CanBindToNoEscape); // The result is the object type of the optional subexpression. CS.addConstraint(ConstraintKind::OptionalObject, CS.getType(expr->getSubExpr()), objectTy, locator); return objectTy; } Type visitOptionalEvaluationExpr(OptionalEvaluationExpr *expr) { // The operand must be coercible to T? for some type T. We'd // like this to be the smallest possible nesting level of // optional types, e.g. T? over T??; otherwise we don't really // have a preference. auto valueTy = CS.createTypeVariable(CS.getConstraintLocator(expr), TVO_PrefersSubtypeBinding | TVO_CanBindToNoEscape); Type optTy = getOptionalType(expr->getSubExpr()->getLoc(), valueTy); if (!optTy) return Type(); CS.addConstraint(ConstraintKind::Conversion, CS.getType(expr->getSubExpr()), optTy, CS.getConstraintLocator(expr)); return optTy; } Type visitForceValueExpr(ForceValueExpr *expr) { // Force-unwrap an optional of type T? to produce a T. auto locator = CS.getConstraintLocator(expr); auto objectTy = CS.createTypeVariable(locator, TVO_PrefersSubtypeBinding | TVO_CanBindToLValue | TVO_CanBindToNoEscape); auto *valueExpr = expr->getSubExpr(); // It's invalid to force unwrap `nil` literal e.g. `_ = nil!` or // `_ = (try nil)!` and similar constructs. if (auto *nilLiteral = dyn_cast( valueExpr->getSemanticsProvidingExpr())) { CS.recordFix(SpecifyContextualTypeForNil::create( CS, CS.getConstraintLocator(nilLiteral))); } // The result is the object type of the optional subexpression. CS.addConstraint(ConstraintKind::OptionalObject, CS.getType(valueExpr), objectTy, locator); return objectTy; } Type visitOpenExistentialExpr(OpenExistentialExpr *expr) { llvm_unreachable("Already type-checked"); } Type visitMakeTemporarilyEscapableExpr(MakeTemporarilyEscapableExpr *expr) { llvm_unreachable("Already type-checked"); } Type visitKeyPathApplicationExpr(KeyPathApplicationExpr *expr) { // This should only appear in already-type-checked solutions, but we may // need to re-check for failure diagnosis. auto locator = CS.getConstraintLocator(expr); auto projectedTy = CS.createTypeVariable(locator, TVO_CanBindToLValue | TVO_CanBindToNoEscape); CS.addKeyPathApplicationConstraint(CS.getType(expr->getKeyPath()), CS.getType(expr->getBase()), projectedTy, locator); return projectedTy; } Type visitEnumIsCaseExpr(EnumIsCaseExpr *expr) { return CS.getASTContext().getBoolDecl()->getDeclaredInterfaceType(); } Type visitLazyInitializerExpr(LazyInitializerExpr *expr) { llvm_unreachable("Already type-checked"); } Type visitEditorPlaceholderExpr(EditorPlaceholderExpr *E) { if (auto *placeholderRepr = E->getPlaceholderTypeRepr()) { // Just resolve the referenced type. return resolveTypeReferenceInExpression( placeholderRepr, TypeResolverContext::InExpression, CS.getConstraintLocator(E)); } auto locator = CS.getConstraintLocator(E); // A placeholder may have any type, but default to Void type if // otherwise unconstrained. auto &placeholderTy = editorPlaceholderVariables[currentEditorPlaceholderVariable]; if (!placeholderTy) { placeholderTy = CS.createTypeVariable(locator, TVO_CanBindToNoEscape); CS.addConstraint(ConstraintKind::Defaultable, placeholderTy, TupleType::getEmpty(CS.getASTContext()), locator); } // Move to the next placeholder variable. // FIXME: Cycling type variables like this is unsound. currentEditorPlaceholderVariable = (currentEditorPlaceholderVariable + 1) % numEditorPlaceholderVariables; return placeholderTy; } Type visitObjCSelectorExpr(ObjCSelectorExpr *E) { // #selector only makes sense when we have the Objective-C // runtime. auto &ctx = CS.getASTContext(); if (!ctx.LangOpts.EnableObjCInterop) { ctx.Diags.diagnose(E->getLoc(), diag::expr_selector_no_objc_runtime); return nullptr; } // Make sure we can reference ObjectiveC.Selector. // FIXME: Fix-It to add the import? auto type = CS.getASTContext().getSelectorType(); if (!type) { ctx.Diags.diagnose(E->getLoc(), diag::expr_selector_module_missing); return nullptr; } return type; } Type visitKeyPathExpr(KeyPathExpr *E) { if (E->isObjC()) return CS.getType(E->getObjCStringLiteralExpr()); auto kpDecl = CS.getASTContext().getKeyPathDecl(); if (!kpDecl) { auto &de = CS.getASTContext().Diags; de.diagnose(E->getLoc(), diag::expr_keypath_no_keypath_type); return ErrorType::get(CS.getASTContext()); } // For native key paths, traverse the key path components to set up // appropriate type relationships at each level. auto rootLocator = CS.getConstraintLocator(E, ConstraintLocator::KeyPathRoot); auto locator = CS.getConstraintLocator(E); Type root = CS.createTypeVariable(rootLocator, TVO_CanBindToNoEscape | TVO_CanBindToHole); // If a root type was explicitly given, then resolve it now. if (auto rootRepr = E->getRootType()) { const auto rootObjectTy = resolveTypeReferenceInExpression( rootRepr, TypeResolverContext::InExpression, locator); if (!rootObjectTy || rootObjectTy->hasError()) return Type(); // Allow \Derived.property to be inferred as \Base.property to // simulate a sort of covariant conversion from // KeyPath to KeyPath. CS.addConstraint(ConstraintKind::Subtype, rootObjectTy, root, locator); } bool didOptionalChain = false; // We start optimistically from an lvalue base. Type base = LValueType::get(root); SmallVector componentTypeVars; for (unsigned i : indices(E->getComponents())) { auto &component = E->getComponents()[i]; auto memberLocator = CS.getConstraintLocator( locator, LocatorPathElt::KeyPathComponent(i)); auto resultLocator = CS.getConstraintLocator( memberLocator, ConstraintLocator::KeyPathComponentResult); switch (auto kind = component.getKind()) { case KeyPathExpr::Component::Kind::Invalid: break; case KeyPathExpr::Component::Kind::UnresolvedProperty: // This should only appear in resolved ASTs, but we may need to // re-type-check the constraints during failure diagnosis. case KeyPathExpr::Component::Kind::Property: { auto memberTy = CS.createTypeVariable(resultLocator, TVO_CanBindToLValue | TVO_CanBindToNoEscape); componentTypeVars.push_back(memberTy); auto lookupName = kind == KeyPathExpr::Component::Kind::UnresolvedProperty ? DeclNameRef(component.getUnresolvedDeclName()) // FIXME: type change needed : component.getDeclRef().getDecl()->createNameRef(); auto refKind = lookupName.isSimpleName() ? FunctionRefKind::Unapplied : FunctionRefKind::Compound; CS.addValueMemberConstraint(base, lookupName, memberTy, CurDC, refKind, /*outerAlternatives=*/{}, memberLocator); base = memberTy; break; } case KeyPathExpr::Component::Kind::UnresolvedSubscript: // Subscript should only appear in resolved ASTs, but we may need to // re-type-check the constraints during failure diagnosis. case KeyPathExpr::Component::Kind::Subscript: { auto index = component.getIndexExpr(); auto unlabeledTrailingClosureIndex = index->getUnlabeledTrailingClosureIndexOfPackedArgument(); base = addSubscriptConstraints(E, base, index, /*decl*/ nullptr, component.getSubscriptLabels(), unlabeledTrailingClosureIndex, memberLocator, &componentTypeVars); break; } case KeyPathExpr::Component::Kind::TupleElement: { // Note: If implemented, the logic in `getCalleeLocator` will need // updating to return the correct callee locator for this. llvm_unreachable("not implemented"); break; } case KeyPathExpr::Component::Kind::OptionalChain: { didOptionalChain = true; // We can't assign an optional back through an optional chain // today. Force the base to an rvalue. auto rvalueTy = CS.createTypeVariable(resultLocator, TVO_CanBindToNoEscape); componentTypeVars.push_back(rvalueTy); CS.addConstraint(ConstraintKind::Equal, base, rvalueTy, resultLocator); base = rvalueTy; LLVM_FALLTHROUGH; } case KeyPathExpr::Component::Kind::OptionalForce: { auto optionalObjTy = CS.createTypeVariable(resultLocator, TVO_CanBindToLValue | TVO_CanBindToNoEscape); componentTypeVars.push_back(optionalObjTy); CS.addConstraint(ConstraintKind::OptionalObject, base, optionalObjTy, resultLocator); base = optionalObjTy; break; } case KeyPathExpr::Component::Kind::OptionalWrap: { // This should only appear in resolved ASTs, but we may need to // re-type-check the constraints during failure diagnosis. base = OptionalType::get(base); break; } case KeyPathExpr::Component::Kind::Identity: continue; case KeyPathExpr::Component::Kind::DictionaryKey: llvm_unreachable("DictionaryKey only valid in #keyPath"); break; } // By now, `base` is the result type of this component. Set it in the // constraint system so we can find it later. CS.setType(E, i, base); } // If there was an optional chaining component, the end result must be // optional. if (didOptionalChain) { auto objTy = CS.createTypeVariable(locator, TVO_CanBindToNoEscape); componentTypeVars.push_back(objTy); auto optTy = OptionalType::get(objTy); CS.addConstraint(ConstraintKind::Conversion, base, optTy, locator); base = optTy; } auto baseLocator = CS.getConstraintLocator(E, ConstraintLocator::KeyPathValue); auto rvalueBase = CS.createTypeVariable(baseLocator, TVO_CanBindToNoEscape); CS.addConstraint(ConstraintKind::Equal, base, rvalueBase, locator); // The result is a KeyPath from the root to the end component. // The type of key path depends on the overloads chosen for the key // path components. auto typeLoc = CS.getConstraintLocator(locator, ConstraintLocator::KeyPathType); Type kpTy = CS.createTypeVariable(typeLoc, TVO_CanBindToNoEscape | TVO_CanBindToHole); CS.addKeyPathConstraint(kpTy, root, rvalueBase, componentTypeVars, locator); return kpTy; } Type visitKeyPathDotExpr(KeyPathDotExpr *E) { llvm_unreachable("found KeyPathDotExpr in CSGen"); } Type visitOneWayExpr(OneWayExpr *expr) { auto locator = CS.getConstraintLocator(expr); auto resultTypeVar = CS.createTypeVariable(locator, 0); CS.addConstraint(ConstraintKind::OneWayEqual, resultTypeVar, CS.getType(expr->getSubExpr()), locator); return resultTypeVar; } Type visitTapExpr(TapExpr *expr) { DeclContext *varDC = expr->getVar()->getDeclContext(); assert(varDC == CS.DC || (varDC && isa(varDC)) && "TapExpr var should be in the same DeclContext we're checking it in!"); auto locator = CS.getConstraintLocator(expr); auto tv = CS.createTypeVariable(locator, TVO_CanBindToNoEscape); if (auto subExpr = expr->getSubExpr()) { auto subExprType = CS.getType(subExpr); CS.addConstraint(ConstraintKind::Bind, subExprType, tv, locator); } return tv; } static bool isTriggerFallbackDiagnosticBuiltin(UnresolvedDotExpr *UDE, ASTContext &Context) { auto *DRE = dyn_cast(UDE->getBase()); if (!DRE) return false; if (DRE->getDecl() != Context.TheBuiltinModule) return false; auto member = UDE->getName().getBaseName().userFacingName(); return member.equals("trigger_fallback_diagnostic"); } enum class TypeOperation { None, Join, JoinInout, JoinMeta, JoinNonexistent, OneWay, }; static TypeOperation getTypeOperation(UnresolvedDotExpr *UDE, ASTContext &Context) { auto *DRE = dyn_cast(UDE->getBase()); if (!DRE) return TypeOperation::None; if (DRE->getDecl() != Context.TheBuiltinModule) return TypeOperation::None; return llvm::StringSwitch( UDE->getName().getBaseIdentifier().str()) .Case("one_way", TypeOperation::OneWay) .Case("type_join", TypeOperation::Join) .Case("type_join_inout", TypeOperation::JoinInout) .Case("type_join_meta", TypeOperation::JoinMeta) .Case("type_join_nonexistent", TypeOperation::JoinNonexistent) .Default(TypeOperation::None); } Type resultOfTypeOperation(TypeOperation op, Expr *Arg) { auto *tuple = cast(Arg); auto *lhs = tuple->getElement(0); auto *rhs = tuple->getElement(1); switch (op) { case TypeOperation::None: case TypeOperation::OneWay: llvm_unreachable( "We should have a valid type operation at this point!"); case TypeOperation::Join: { auto lhsMeta = CS.getType(lhs)->getAs(); auto rhsMeta = CS.getType(rhs)->getAs(); if (!lhsMeta || !rhsMeta) llvm_unreachable("Unexpected argument types for Builtin.type_join!"); auto &ctx = lhsMeta->getASTContext(); auto join = Type::join(lhsMeta->getInstanceType(), rhsMeta->getInstanceType()); if (!join) return ErrorType::get(ctx); return MetatypeType::get(*join, ctx)->getCanonicalType(); } case TypeOperation::JoinInout: { auto lhsInOut = CS.getType(lhs)->getAs(); auto rhsMeta = CS.getType(rhs)->getAs(); if (!lhsInOut || !rhsMeta) llvm_unreachable("Unexpected argument types for Builtin.type_join!"); auto &ctx = lhsInOut->getASTContext(); auto join = Type::join(lhsInOut, rhsMeta->getInstanceType()); if (!join) return ErrorType::get(ctx); return MetatypeType::get(*join, ctx)->getCanonicalType(); } case TypeOperation::JoinMeta: { auto lhsMeta = CS.getType(lhs)->getAs(); auto rhsMeta = CS.getType(rhs)->getAs(); if (!lhsMeta || !rhsMeta) llvm_unreachable("Unexpected argument types for Builtin.type_join!"); auto &ctx = lhsMeta->getASTContext(); auto join = Type::join(lhsMeta, rhsMeta); if (!join) return ErrorType::get(ctx); return *join; } case TypeOperation::JoinNonexistent: { auto lhsMeta = CS.getType(lhs)->getAs(); auto rhsMeta = CS.getType(rhs)->getAs(); if (!lhsMeta || !rhsMeta) llvm_unreachable("Unexpected argument types for Builtin.type_join_nonexistent!"); auto &ctx = lhsMeta->getASTContext(); auto join = Type::join(lhsMeta->getInstanceType(), rhsMeta->getInstanceType()); // Verify that we could not compute a join. if (join) llvm_unreachable("Unexpected result from join - it should not have been computable!"); // The return value is unimportant. return MetatypeType::get(ctx.TheAnyType)->getCanonicalType(); } } llvm_unreachable("unhandled operation"); } void associateArgumentLabels(ConstraintLocator *locator, ConstraintSystem::ArgumentInfo info, bool labelsArePermanent = true) { assert(locator && locator->getAnchor()); // Record the labels. if (!labelsArePermanent) info.Labels = CS.allocateCopy(info.Labels); CS.ArgumentInfos[CS.getArgumentInfoLocator(locator)] = info; } }; class ConstraintWalker : public ASTWalker { ConstraintGenerator &CG; public: ConstraintWalker(ConstraintGenerator &CG) : CG(CG) { } std::pair walkToExprPre(Expr *expr) override { if (CG.getConstraintSystem().shouldReusePrecheckedType()) { if (expr->getType()) { assert(!expr->getType()->hasTypeVariable()); assert(!expr->getType()->hasHole()); CG.getConstraintSystem().cacheType(expr); return { false, expr }; } } // Note that the subexpression of a #selector expression is // unevaluated. if (auto sel = dyn_cast(expr)) { CG.getConstraintSystem().UnevaluatedRootExprs.insert(sel->getSubExpr()); } // Check an objc key-path expression, which fills in its semantic // expression as a string literal. if (auto keyPath = dyn_cast(expr)) { if (keyPath->isObjC()) { auto &cs = CG.getConstraintSystem(); (void)TypeChecker::checkObjCKeyPathExpr(cs.DC, keyPath); } } // Generate constraints for each of the entries in the capture list. if (auto captureList = dyn_cast(expr)) { TypeChecker::diagnoseDuplicateCaptureVars(captureList); auto &CS = CG.getConstraintSystem(); for (const auto &capture : captureList->getCaptureList()) { SolutionApplicationTarget target(capture.Init); if (CS.generateConstraints(target, FreeTypeVariableBinding::Disallow)) return {false, nullptr}; } } // Both multi- and single-statement closures now behave the same way // when it comes to constraint generation. if (auto closure = dyn_cast(expr)) { auto &CS = CG.getConstraintSystem(); auto closureType = CG.visitClosureExpr(closure); if (!closureType) return {false, nullptr}; CS.setType(expr, closureType); return {false, expr}; } // Don't visit CoerceExpr with an empty sub expression. They may occur // if the body of a closure was not visited while pre-checking because // of an error in the closure's signature. if (auto coerceExpr = dyn_cast(expr)) { if (!coerceExpr->getSubExpr()) { return { false, expr }; } } // Don't visit IfExpr with empty sub expressions. They may occur // if the body of a closure was not visited while pre-checking because // of an error in the closure's signature. if (auto ifExpr = dyn_cast(expr)) { if (!ifExpr->getThenExpr() || !ifExpr->getElseExpr()) return { false, expr }; } if (auto *assignment = dyn_cast(expr)) CG.markAcceptableDiscardExprs(assignment->getDest()); return { true, expr }; } /// Once we've visited the children of the given expression, /// generate constraints from the expression. Expr *walkToExprPost(Expr *expr) override { auto &CS = CG.getConstraintSystem(); // Translate special type-checker Builtin calls into simpler expressions. if (auto *apply = dyn_cast(expr)) { auto fnExpr = apply->getFn(); if (auto *UDE = dyn_cast(fnExpr)) { auto typeOperation = ConstraintGenerator::getTypeOperation(UDE, CS.getASTContext()); if (typeOperation == ConstraintGenerator::TypeOperation::OneWay) { // For a one-way constraint, create the OneWayExpr node. auto *arg = cast(apply->getArg())->getSubExpr(); expr = new (CS.getASTContext()) OneWayExpr(arg); } else if (typeOperation != ConstraintGenerator::TypeOperation::None) { // Handle the Builtin.type_join* family of calls by replacing // them with dot_self_expr of type_expr with the type being the // result of the join. auto joinMetaTy = CG.resultOfTypeOperation(typeOperation, apply->getArg()); auto joinTy = joinMetaTy->castTo(); auto *TE = TypeExpr::createImplicit(joinTy->getInstanceType(), CS.getASTContext()); CS.cacheType(TE); auto *DSE = new (CS.getASTContext()) DotSelfExpr(TE, SourceLoc(), SourceLoc(), CS.getType(TE)); DSE->setImplicit(); CS.cacheType(DSE); return DSE; } } } if (auto type = CG.visit(expr)) { auto simplifiedType = CS.simplifyType(type); CS.setType(expr, simplifiedType); return expr; } return nullptr; } /// Ignore statements. std::pair walkToStmtPre(Stmt *stmt) override { return { false, stmt }; } /// Ignore declarations. bool walkToDeclPre(Decl *decl) override { return false; } }; } // end anonymous namespace static Expr *generateConstraintsFor(ConstraintSystem &cs, Expr *expr, DeclContext *DC) { // Walk the expression, generating constraints. ConstraintGenerator cg(cs, DC); ConstraintWalker cw(cg); Expr *result = expr->walk(cw); if (result) cs.optimizeConstraints(result); return result; } /// Generate constraints to produce the wrapped value type given the property /// that has an attached property wrapper. /// /// \param initializerType The type of the adjusted initializer, which /// initializes the underlying storage variable. /// \param wrappedVar The property that has a property wrapper. /// \returns the type of the property. static bool generateWrappedPropertyTypeConstraints( ConstraintSystem &cs, Type initializerType, VarDecl *wrappedVar, Type propertyType) { auto dc = wrappedVar->getInnermostDeclContext(); Type wrapperType = LValueType::get(initializerType); Type wrappedValueType; auto wrapperAttributes = wrappedVar->getAttachedPropertyWrappers(); for (unsigned i : indices(wrapperAttributes)) { // FIXME: We should somehow pass an OpenUnboundGenericTypeFn to // AttachedPropertyWrapperTypeRequest::evaluate to open up unbound // generics on the fly. Type rawWrapperType = wrappedVar->getAttachedPropertyWrapperType(i); auto wrapperInfo = wrappedVar->getAttachedPropertyWrapperTypeInfo(i); if (rawWrapperType->hasError() || !wrapperInfo) return true; // The former wrappedValue type must be equal to the current wrapper type if (wrappedValueType) { auto *typeRepr = wrapperAttributes[i]->getTypeRepr(); auto *locator = cs.getConstraintLocator(typeRepr, LocatorPathElt::ContextualType()); wrapperType = cs.openUnboundGenericTypes(rawWrapperType, locator); cs.addConstraint(ConstraintKind::Equal, wrapperType, wrappedValueType, locator); cs.setContextualType(typeRepr, TypeLoc::withoutLoc(wrappedValueType), CTP_ComposedPropertyWrapper); } wrappedValueType = wrapperType->getTypeOfMember( dc->getParentModule(), wrapperInfo.valueVar); } // The property type must be equal to the wrapped value type cs.addConstraint(ConstraintKind::Equal, propertyType, wrappedValueType, cs.getConstraintLocator(wrappedVar, LocatorPathElt::ContextualType())); cs.setContextualType(wrappedVar, TypeLoc::withoutLoc(wrappedValueType), CTP_WrappedProperty); return false; } /// Generate additional constraints for the pattern of an initialization. static bool generateInitPatternConstraints( ConstraintSystem &cs, SolutionApplicationTarget target, Expr *initializer) { auto pattern = target.getInitializationPattern(); auto locator = cs.getConstraintLocator(initializer, LocatorPathElt::ContextualType()); Type patternType = cs.generateConstraints( pattern, locator, target.shouldBindPatternVarsOneWay(), target.getInitializationPatternBindingDecl(), target.getInitializationPatternBindingIndex()); if (!patternType) return true; if (auto wrappedVar = target.getInitializationWrappedVar()) return generateWrappedPropertyTypeConstraints( cs, cs.getType(target.getAsExpr()), wrappedVar, patternType); if (!patternType->is()) { // Add a conversion constraint between the types. cs.addConstraint(ConstraintKind::Conversion, cs.getType(target.getAsExpr()), patternType, locator, /*isFavored*/true); } return false; } /// Generate constraints for a for-each statement. static Optional generateForEachStmtConstraints( ConstraintSystem &cs, SolutionApplicationTarget target, Expr *sequence) { auto forEachStmtInfo = target.getForEachStmtInfo(); ForEachStmt *stmt = forEachStmtInfo.stmt; auto locator = cs.getConstraintLocator(sequence); auto contextualLocator = cs.getConstraintLocator(sequence, LocatorPathElt::ContextualType()); // The expression type must conform to the Sequence protocol. auto sequenceProto = TypeChecker::getProtocol( cs.getASTContext(), stmt->getForLoc(), KnownProtocolKind::Sequence); if (!sequenceProto) { return None; } Type sequenceType = cs.createTypeVariable(locator, TVO_CanBindToNoEscape); cs.addConstraint(ConstraintKind::Conversion, cs.getType(sequence), sequenceType, locator); cs.addConstraint(ConstraintKind::ConformsTo, sequenceType, sequenceProto->getDeclaredInterfaceType(), contextualLocator); // Check the element pattern. ASTContext &ctx = cs.getASTContext(); auto dc = target.getDeclContext(); Pattern *pattern = TypeChecker::resolvePattern(stmt->getPattern(), dc, /*isStmtCondition*/false); if (!pattern) return None; auto contextualPattern = ContextualPattern::forRawPattern(pattern, dc); Type patternType = TypeChecker::typeCheckPattern(contextualPattern); if (patternType->hasError()) { return None; } // Collect constraints from the element pattern. auto elementLocator = cs.getConstraintLocator( contextualLocator, ConstraintLocator::SequenceElementType); Type initType = cs.generateConstraints( pattern, contextualLocator, target.shouldBindPatternVarsOneWay(), nullptr, 0); if (!initType) return None; // Add a conversion constraint between the element type of the sequence // and the type of the element pattern. auto elementAssocType = sequenceProto->getAssociatedType(cs.getASTContext().Id_Element); Type elementType = DependentMemberType::get(sequenceType, elementAssocType); cs.addConstraint(ConstraintKind::Conversion, elementType, initType, elementLocator); // Determine the iterator type. auto iteratorAssocType = sequenceProto->getAssociatedType(cs.getASTContext().Id_Iterator); Type iteratorType = DependentMemberType::get(sequenceType, iteratorAssocType); // The iterator type must conform to IteratorProtocol. ProtocolDecl *iteratorProto = TypeChecker::getProtocol( cs.getASTContext(), stmt->getForLoc(), KnownProtocolKind::IteratorProtocol); if (!iteratorProto) return None; // Reference the makeIterator witness. FuncDecl *makeIterator = ctx.getSequenceMakeIterator(); Type makeIteratorType = cs.createTypeVariable(locator, TVO_CanBindToNoEscape); cs.addValueWitnessConstraint( LValueType::get(sequenceType), makeIterator, makeIteratorType, dc, FunctionRefKind::Compound, contextualLocator); // Generate constraints for the "where" expression, if there is one. if (forEachStmtInfo.whereExpr) { auto *boolDecl = dc->getASTContext().getBoolDecl(); if (!boolDecl) return None; Type boolType = boolDecl->getDeclaredInterfaceType(); if (!boolType) return None; SolutionApplicationTarget whereTarget( forEachStmtInfo.whereExpr, dc, CTP_Condition, boolType, /*isDiscarded=*/false); if (cs.generateConstraints(whereTarget, FreeTypeVariableBinding::Disallow)) return None; cs.setContextualType(forEachStmtInfo.whereExpr, TypeLoc::withoutLoc(boolType), CTP_Condition); forEachStmtInfo.whereExpr = whereTarget.getAsExpr(); } // Populate all of the information for a for-each loop. forEachStmtInfo.elementType = elementType; forEachStmtInfo.iteratorType = iteratorType; forEachStmtInfo.initType = initType; forEachStmtInfo.sequenceType = sequenceType; target.setPattern(pattern); target.getForEachStmtInfo() = forEachStmtInfo; return target; } bool ConstraintSystem::generateConstraints( SolutionApplicationTarget &target, FreeTypeVariableBinding allowFreeTypeVariables) { if (Expr *expr = target.getAsExpr()) { // If the target requires an optional of some type, form a new appropriate // type variable and update the target's type with an optional of that // type variable. if (target.isOptionalSomePatternInit()) { assert(!target.getExprContextualType() && "some pattern cannot have contextual type pre-configured"); auto *convertTypeLocator = getConstraintLocator(expr, LocatorPathElt::ContextualType()); Type var = createTypeVariable(convertTypeLocator, TVO_CanBindToNoEscape); target.setExprConversionType(TypeChecker::getOptionalType(expr->getLoc(), var)); } expr = buildTypeErasedExpr(expr, target.getDeclContext(), target.getExprContextualType(), target.getExprContextualTypePurpose()); // Generate constraints for the main system. expr = generateConstraints(expr, target.getDeclContext()); if (!expr) return true; target.setExpr(expr); // If there is a type that we're expected to convert to, add the conversion // constraint. if (Type convertType = target.getExprConversionType()) { // Determine whether we know more about the contextual type. ContextualTypePurpose ctp = target.getExprContextualTypePurpose(); bool isOpaqueReturnType = target.infersOpaqueReturnType(); // Substitute type variables in for unresolved types. if (allowFreeTypeVariables == FreeTypeVariableBinding::UnresolvedType) { auto *convertTypeLocator = getConstraintLocator(expr, LocatorPathElt::ContextualType()); convertType = convertType.transform([&](Type type) -> Type { if (type->is()) { return createTypeVariable( convertTypeLocator, TVO_CanBindToNoEscape); } return type; }); } addContextualConversionConstraint(expr, convertType, ctp, isOpaqueReturnType); } // For an initialization target, generate constraints for the pattern. if (target.getExprContextualTypePurpose() == CTP_Initialization && generateInitPatternConstraints(*this, target, expr)) { return true; } // For a for-each statement, generate constraints for the pattern, where // clause, and sequence traversal. if (target.getExprContextualTypePurpose() == CTP_ForEachStmt) { auto resultTarget = generateForEachStmtConstraints(*this, target, expr); if (!resultTarget) return true; target = *resultTarget; } if (isDebugMode()) { auto &log = llvm::errs(); log << "---Initial constraints for the given expression---\n"; print(log, expr); log << "\n"; print(log); } return false; } switch (target.kind) { case SolutionApplicationTarget::Kind::expression: llvm_unreachable("Handled above"); case SolutionApplicationTarget::Kind::caseLabelItem: case SolutionApplicationTarget::Kind::function: case SolutionApplicationTarget::Kind::stmtCondition: llvm_unreachable("Handled separately"); case SolutionApplicationTarget::Kind::patternBinding: { auto patternBinding = target.getAsPatternBinding(); auto dc = target.getDeclContext(); bool hadError = false; /// Generate constraints for each pattern binding entry for (unsigned index : range(patternBinding->getNumPatternEntries())) { // Type check the pattern. auto pattern = patternBinding->getPattern(index); auto contextualPattern = ContextualPattern::forRawPattern(pattern, dc); Type patternType = TypeChecker::typeCheckPattern(contextualPattern); auto init = patternBinding->getInit(index); if (!init) { llvm_unreachable("Unsupported pattern binding entry"); } // Generate constraints for the initialization. auto target = SolutionApplicationTarget::forInitialization( init, dc, patternType, pattern, /*bindPatternVarsOneWay=*/true); if (generateConstraints(target, FreeTypeVariableBinding::Disallow)) { hadError = true; continue; } // Keep track of this binding entry. setSolutionApplicationTarget({patternBinding, index}, target); } return hadError; } case SolutionApplicationTarget::Kind::uninitializedWrappedVar: { auto *wrappedVar = target.getAsUninitializedWrappedVar(); auto *outermostWrapper = wrappedVar->getAttachedPropertyWrappers().front(); auto *typeRepr = outermostWrapper->getTypeRepr(); auto backingType = openUnboundGenericTypes(outermostWrapper->getType(), getConstraintLocator(typeRepr)); setType(typeRepr, backingType); auto propertyType = getVarType(wrappedVar); if (propertyType->hasError()) return true; return generateWrappedPropertyTypeConstraints( *this, backingType, wrappedVar, propertyType); } } } Expr *ConstraintSystem::generateConstraints( Expr *expr, DeclContext *dc, bool isInputExpression) { if (isInputExpression) InputExprs.insert(expr); return generateConstraintsFor(*this, expr, dc); } Type ConstraintSystem::generateConstraints( Pattern *pattern, ConstraintLocatorBuilder locator, bool bindPatternVarsOneWay, PatternBindingDecl *patternBinding, unsigned patternIndex) { ConstraintGenerator cg(*this, nullptr); return cg.getTypeForPattern(pattern, locator, Type(), bindPatternVarsOneWay, patternBinding, patternIndex); } bool ConstraintSystem::generateConstraints(StmtCondition condition, DeclContext *dc) { // FIXME: This should be folded into constraint generation for conditions. auto boolDecl = getASTContext().getBoolDecl(); if (!boolDecl) { return true; } Type boolTy = boolDecl->getDeclaredInterfaceType(); for (const auto &condElement : condition) { switch (condElement.getKind()) { case StmtConditionElement::CK_Availability: // Nothing to do here. continue; case StmtConditionElement::CK_Boolean: { Expr *condExpr = condElement.getBoolean(); setContextualType(condExpr, TypeLoc::withoutLoc(boolTy), CTP_Condition); condExpr = generateConstraints(condExpr, dc); if (!condExpr) { return true; } addConstraint(ConstraintKind::Conversion, getType(condExpr), boolTy, getConstraintLocator(condExpr, LocatorPathElt::ContextualType())); continue; } case StmtConditionElement::CK_PatternBinding: { auto *pattern = TypeChecker::resolvePattern( condElement.getPattern(), dc, /*isStmtCondition*/true); if (!pattern) return true; auto target = SolutionApplicationTarget::forInitialization( condElement.getInitializer(), dc, Type(), pattern, /*bindPatternVarsOneWay=*/true); if (generateConstraints(target, FreeTypeVariableBinding::Disallow)) return true; setSolutionApplicationTarget(&condElement, target); continue; } } } return false; } bool ConstraintSystem::generateConstraints( CaseStmt *caseStmt, DeclContext *dc, Type subjectType, ConstraintLocator *locator) { // Pre-bind all of the pattern variables within the case. bindSwitchCasePatternVars(dc, caseStmt); for (auto &caseLabelItem : caseStmt->getMutableCaseLabelItems()) { // Resolve the pattern. auto *pattern = caseLabelItem.getPattern(); if (!caseLabelItem.isPatternResolved()) { pattern = TypeChecker::resolvePattern( pattern, dc, /*isStmtCondition=*/false); if (!pattern) return true; } // Generate constraints for the pattern, including one-way bindings for // any variables that show up in this pattern, because those variables // can be referenced in the guard expressions and the body. Type patternType = generateConstraints( pattern, locator, /* bindPatternVarsOneWay=*/true, /*patternBinding=*/nullptr, /*patternBindingIndex=*/0); // Convert the subject type to the pattern, which establishes the // bindings. addConstraint( ConstraintKind::Conversion, subjectType, patternType, locator); // Generate constraints for the guard expression, if there is one. Expr *guardExpr = caseLabelItem.getGuardExpr(); if (guardExpr) { guardExpr = generateConstraints(guardExpr, dc); if (!guardExpr) return true; } // Save this info. setCaseLabelItemInfo(&caseLabelItem, {pattern, guardExpr}); // For any pattern variable that has a parent variable (i.e., another // pattern variable with the same name in the same case), require that // the types be equivalent. pattern->forEachNode([&](Pattern *pattern) { auto namedPattern = dyn_cast(pattern); if (!namedPattern) return; auto var = namedPattern->getDecl(); if (auto parentVar = var->getParentVarDecl()) { addConstraint( ConstraintKind::Equal, getType(parentVar), getType(var), getConstraintLocator( locator, LocatorPathElt::PatternMatch(namedPattern))); } }); } // Bind the types of the case body variables. for (auto caseBodyVar : caseStmt->getCaseBodyVariablesOrEmptyArray()) { auto parentVar = caseBodyVar->getParentVarDecl(); assert(parentVar && "Case body variables always have parents"); setType(caseBodyVar, getType(parentVar)); } return false; } void ConstraintSystem::optimizeConstraints(Expr *e) { if (getASTContext().TypeCheckerOpts.DisableConstraintSolverPerformanceHacks) return; SmallVector linkedExprs; // Collect any linked expressions. LinkedExprCollector collector(linkedExprs, *this); e->walk(collector); // Favor types, as appropriate. for (auto linkedExpr : linkedExprs) { computeFavoredTypeForExpr(linkedExpr, *this); } // Optimize the constraints. ConstraintOptimizer optimizer(*this); e->walk(optimizer); } bool swift::areGenericRequirementsSatisfied( const DeclContext *DC, GenericSignature sig, SubstitutionMap Substitutions, bool isExtension) { ConstraintSystemOptions Options; ConstraintSystem CS(const_cast(DC), Options); auto Loc = CS.getConstraintLocator({}); // For every requirement, add a constraint. for (auto Req : sig->getRequirements()) { if (auto resolved = Req.subst( QuerySubstitutionMap{Substitutions}, LookUpConformanceInModule(DC->getParentModule()))) { CS.addConstraint(*resolved, Loc); } else if (isExtension) { return false; } // Unresolved requirements are requirements of the function itself. This // does not prevent it from being applied. E.g. func foo(x: T). } // Having a solution implies the requirements have been fulfilled. return CS.solveSingle().hasValue(); } struct ResolvedMemberResult::Implementation { llvm::SmallVector AllDecls; unsigned ViableStartIdx; Optional BestIdx; }; ResolvedMemberResult::ResolvedMemberResult(): Impl(new Implementation()) {}; ResolvedMemberResult::~ResolvedMemberResult() { delete Impl; }; ResolvedMemberResult::operator bool() const { return !Impl->AllDecls.empty(); } bool ResolvedMemberResult:: hasBestOverload() const { return Impl->BestIdx.hasValue(); } ValueDecl* ResolvedMemberResult:: getBestOverload() const { return Impl->AllDecls[Impl->BestIdx.getValue()]; } ArrayRef ResolvedMemberResult:: getMemberDecls(InterestedMemberKind Kind) { auto Result = llvm::makeArrayRef(Impl->AllDecls); switch (Kind) { case InterestedMemberKind::Viable: return Result.slice(Impl->ViableStartIdx); case InterestedMemberKind::Unviable: return Result.slice(0, Impl->ViableStartIdx); case InterestedMemberKind::All: return Result; } llvm_unreachable("unhandled kind"); } ResolvedMemberResult swift::resolveValueMember(DeclContext &DC, Type BaseTy, DeclName Name) { ResolvedMemberResult Result; ConstraintSystem CS(&DC, None); // Look up all members of BaseTy with the given Name. MemberLookupResult LookupResult = CS.performMemberLookup( ConstraintKind::ValueMember, DeclNameRef(Name), BaseTy, FunctionRefKind::SingleApply, CS.getConstraintLocator({}), false); // Keep track of all the unviable members. for (auto Can : LookupResult.UnviableCandidates) Result.Impl->AllDecls.push_back(Can.getDecl()); // Keep track of the start of viable choices. Result.Impl->ViableStartIdx = Result.Impl->AllDecls.size(); // If no viable members, we are done. if (LookupResult.ViableCandidates.empty()) return Result; // If there's only one viable member, that is the best one. if (LookupResult.ViableCandidates.size() == 1) { Result.Impl->BestIdx = Result.Impl->AllDecls.size(); Result.Impl->AllDecls.push_back(LookupResult.ViableCandidates[0].getDecl()); return Result; } // Try to figure out the best overload. ConstraintLocator *Locator = CS.getConstraintLocator({}); TypeVariableType *TV = CS.createTypeVariable(Locator, TVO_CanBindToLValue | TVO_CanBindToNoEscape); CS.addOverloadSet(TV, LookupResult.ViableCandidates, &DC, Locator); Optional OpSolution = CS.solveSingle(); ValueDecl *Selected = nullptr; if (OpSolution.hasValue()) { Selected = OpSolution.getValue().overloadChoices[Locator].choice.getDecl(); } for (OverloadChoice& Choice : LookupResult.ViableCandidates) { ValueDecl *VD = Choice.getDecl(); // If this VD is the best overload, keep track of its index. if (VD == Selected) Result.Impl->BestIdx = Result.Impl->AllDecls.size(); Result.Impl->AllDecls.push_back(VD); } return Result; } OriginalArgumentList swift::getOriginalArgumentList(Expr *expr) { OriginalArgumentList result; auto add = [&](Expr *arg, Identifier label, SourceLoc labelLoc) { if (isa(arg)) { return; } if (auto *varargExpr = dyn_cast(arg)) { if (auto *arrayExpr = dyn_cast(varargExpr->getSubExpr())) { for (auto *elt : arrayExpr->getElements()) { result.args.push_back(elt); result.labels.push_back(label); result.labelLocs.push_back(labelLoc); label = Identifier(); labelLoc = SourceLoc(); } return; } } result.args.push_back(arg); result.labels.push_back(label); result.labelLocs.push_back(labelLoc); }; if (auto *parenExpr = dyn_cast(expr)) { result.lParenLoc = parenExpr->getLParenLoc(); result.rParenLoc = parenExpr->getRParenLoc(); result.hasTrailingClosure = parenExpr->hasTrailingClosure(); add(parenExpr->getSubExpr(), Identifier(), SourceLoc()); } else if (auto *tupleExpr = dyn_cast(expr)) { result.lParenLoc = tupleExpr->getLParenLoc(); result.rParenLoc = tupleExpr->getRParenLoc(); result.hasTrailingClosure = tupleExpr->hasTrailingClosure(); auto args = tupleExpr->getElements(); auto labels = tupleExpr->getElementNames(); auto labelLocs = tupleExpr->getElementNameLocs(); for (unsigned i = 0, e = args.size(); i != e; ++i) { // Implicit TupleExprs don't always store label locations. add(args[i], labels[i], labelLocs.empty() ? SourceLoc() : labelLocs[i]); } } else { add(expr, Identifier(), SourceLoc()); } return result; }