| //===--- 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 <utility> |
| |
| 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<TypeBase*, 16> collectedTypes; |
| llvm::SmallVector<BinaryExpr *, 4> 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<Expr*> &LinkedExprs; |
| ConstraintSystem &CS; |
| |
| public: |
| LinkedExprCollector(llvm::SmallVectorImpl<Expr *> &linkedExprs, |
| ConstraintSystem &cs) |
| : LinkedExprs(linkedExprs), CS(cs) {} |
| |
| std::pair<bool, Expr *> walkToExprPre(Expr *expr) override { |
| |
| if (CS.shouldReusePrecheckedType() && |
| !CS.getType(expr)->hasTypeVariable()) { |
| return { false, expr }; |
| } |
| |
| if (isa<ClosureExpr>(expr)) |
| return {false, expr}; |
| |
| // Store top-level binary exprs for further analysis. |
| if (isa<BinaryExpr>(expr) || |
| |
| // Literal exprs are contextually typed, so store them off as well. |
| isa<LiteralExpr>(expr) || |
| |
| // We'd like to look at the elements of arrays and dictionaries. |
| isa<ArrayExpr>(expr) || |
| isa<DictionaryExpr>(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<AssignExpr>(expr)) { |
| LinkedExprs.push_back(expr); |
| return {false, expr}; |
| } |
| |
| return { true, expr }; |
| } |
| |
| Expr *walkToExprPost(Expr *expr) override { |
| return expr; |
| } |
| |
| /// Ignore statements. |
| std::pair<bool, Stmt *> walkToStmtPre(Stmt *stmt) override { |
| return { false, stmt }; |
| } |
| |
| /// Ignore declarations. |
| bool walkToDeclPre(Decl *decl) override { return false; } |
| |
| /// Ignore patterns. |
| std::pair<bool, Pattern*> 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<bool, Expr *> walkToExprPre(Expr *expr) override { |
| |
| if (CS.shouldReusePrecheckedType() && |
| !CS.getType(expr)->hasTypeVariable()) { |
| return { false, expr }; |
| } |
| |
| if (isa<LiteralExpr>(expr)) { |
| LTI.hasLiteral = true; |
| return { false, expr }; |
| } |
| |
| if (isa<CollectionExpr>(expr)) { |
| return { true, expr }; |
| } |
| |
| if (auto UDE = dyn_cast<UnresolvedDotExpr>(expr)) { |
| |
| if (CS.hasType(UDE)) |
| LTI.collectedTypes.insert(CS.getType(UDE).getPointer()); |
| |
| // Don't recurse into the base expression. |
| return { false, expr }; |
| } |
| |
| |
| if (isa<ClosureExpr>(expr)) { |
| return {false, expr}; |
| } |
| |
| if (auto FVE = dyn_cast<ForceValueExpr>(expr)) { |
| LTI.collectedTypes.insert(CS.getType(FVE).getPointer()); |
| return { false, expr }; |
| } |
| |
| if (auto DRE = dyn_cast<DeclRefExpr>(expr)) { |
| if (auto varDecl = dyn_cast<VarDecl>(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<ApplyExpr>(expr) && |
| !(isa<BinaryExpr>(expr) || isa<PrefixUnaryExpr>(expr) || |
| isa<PostfixUnaryExpr>(expr))) { |
| return { false, expr }; |
| } |
| |
| if (isa<BinaryExpr>(expr)) { |
| LTI.binaryExprs.push_back(dyn_cast<BinaryExpr>(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<IfExpr>(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<TupleExpr>(expr) && !isa<ApplyExpr>(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<CoerceExpr>(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<SubscriptExpr>(expr) || isa<DynamicLookupExpr>(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<UnresolvedMemberExpr>(expr)) { |
| return {false, expr }; |
| } |
| |
| return { true, expr }; |
| } |
| |
| /// Ignore statements. |
| std::pair<bool, Stmt *> walkToStmtPre(Stmt *stmt) override { |
| return { false, stmt }; |
| } |
| |
| /// Ignore declarations. |
| bool walkToDeclPre(Decl *decl) override { return false; } |
| |
| /// Ignore patterns. |
| std::pair<bool, Pattern*> 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<TypeVariableType>(); |
| auto fnTy2 = CS.getType(binExp2)->getAs<TypeVariableType>(); |
| |
| if (!(fnTy1 && fnTy2)) |
| return; |
| |
| auto ODR1 = dyn_cast<OverloadedDeclRefExpr>(binExp1->getFn()); |
| auto ODR2 = dyn_cast<OverloadedDeclRefExpr>(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<TypeVariableType>(); |
| auto odTy2 = CS.getType(ODR2)->getAs<TypeVariableType>(); |
| |
| 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<ProtocolDecl *, 2> literalProtos; |
| if (auto argTypeVar = argTy->getAs<TypeVariableType>()) { |
| 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<bool(ValueDecl *, Type)> isFavored, |
| std::function<bool(ValueDecl *)> |
| mustConsider = nullptr) { |
| // Find the type variable associated with the function, if any. |
| auto tyvarType = CS.getType(expr->getFn())->getAs<TypeVariableType>(); |
| 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<Constraint *, 4> 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<DisfavoredOverloadAttr>() && |
| 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<AnyFunctionType>()->getResult(); |
| if (!resultType->hasTypeParameter()) |
| CS.setFavoredType(expr, resultType.getPointer()); |
| } |
| } |
| |
| size_t getOperandCount(Type t) { |
| size_t nOperands = 0; |
| |
| if (auto parenTy = dyn_cast<ParenType>(t.getPointer())) { |
| if (parenTy->getDesugaredType()) |
| nOperands = 1; |
| } else if (auto tupleTy = t->getAs<TupleType>()) { |
| 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<size_t, size_t> getParamCount(ValueDecl *VD) { |
| auto fTy = VD->getInterfaceType()->castTo<AnyFunctionType>(); |
| |
| size_t nOperands = fTy->getParams().size(); |
| size_t nNoDefault = 0; |
| |
| if (auto AFD = dyn_cast<AbstractFunctionDecl>(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<AnyFunctionType>(); |
| 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<OverloadedDeclRefExpr>(fnExpr)) { |
| bool haveMultipleApplicableOverloads = false; |
| |
| for (auto VD : ODR->getDecls()) { |
| if (VD->getInterfaceType()->is<AnyFunctionType>()) { |
| 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 { |
| // We want to consider all options for calls that might contain the code |
| // completion location, as missing arguments after the completion |
| // location are valid (since it might be that they just haven't been |
| // written yet). |
| if (CS.isForCodeCompletion()) |
| return false; |
| |
| if (!type->is<AnyFunctionType>()) |
| 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<AnyFunctionType>(); |
| 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<ProtocolDecl>(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<TupleType>(); |
| auto argTupleExpr = dyn_cast<TupleExpr>(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<AnyFunctionType>(); |
| 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<bool, Expr *> walkToExprPre(Expr *expr) override { |
| |
| if (CS.shouldReusePrecheckedType() && |
| !CS.getType(expr)->hasTypeVariable()) { |
| return { false, expr }; |
| } |
| |
| if (auto applyExpr = dyn_cast<ApplyExpr>(expr)) { |
| if (isa<PrefixUnaryExpr>(applyExpr) || |
| isa<PostfixUnaryExpr>(applyExpr)) { |
| favorMatchingUnaryOperators(applyExpr, CS); |
| } else if (isa<BinaryExpr>(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<ParenExpr>(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<ClosureExpr>(expr)) |
| return {false, expr}; |
| |
| return { true, expr }; |
| } |
| |
| Expr *walkToExprPost(Expr *expr) override { |
| return expr; |
| } |
| |
| /// Ignore statements. |
| std::pair<bool, Stmt *> walkToStmtPre(Stmt *stmt) override { |
| return { false, stmt }; |
| } |
| |
| /// Ignore declarations. |
| bool walkToDeclPre(Decl *decl) override { return false; } |
| }; |
| } // end anonymous namespace |
| |
| namespace { |
| |
| class ConstraintGenerator : public ExprVisitor<ConstraintGenerator, Type> { |
| 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<DiscardAssignmentExpr*, 2> CorrectDiscardAssignmentExprs; |
| |
| /// A map from each UnresolvedMemberExpr to the respective (implicit) base |
| /// found during our walk. |
| llvm::MapVector<UnresolvedMemberExpr *, Type> 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<NilLiteralExpr>(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<ValueDecl *> 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<OverloadChoice, 4> 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<Identifier> argLabels, |
| Optional<unsigned> unlabeledTrailingClosure, |
| ConstraintLocator *locator = nullptr, |
| SmallVectorImpl<TypeVariableType *> *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<SubscriptExpr>(anchor)) { |
| |
| auto isLValueBase = false; |
| auto baseObjTy = baseTy; |
| if (baseObjTy->is<LValueType>()) { |
| isLValueBase = true; |
| baseObjTy = baseObjTy->getWithoutSpecifierType(); |
| } |
| |
| if (CS.isArrayType(baseObjTy.getPointer())) { |
| |
| if (auto arraySliceTy = |
| dyn_cast<ArraySliceType>(baseObjTy.getPointer())) { |
| baseObjTy = arraySliceTy->getDesugaredType(); |
| } |
| |
| auto indexExpr = index; |
| |
| if (auto parenExpr = dyn_cast<ParenExpr>(indexExpr)) { |
| indexExpr = parenExpr->getSubExpr(); |
| } |
| |
| if (isa<IntegerLiteralExpr>(indexExpr)) { |
| |
| outputTy = baseObjTy->getAs<BoundGenericType>()->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<TypeVariableType>()); |
| } |
| |
| // 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<InOutType>()) { |
| 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<AnyFunctionType::Param, 8> 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. |
| // result 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. |
| if (CS.containsCodeCompletionLoc(E)) |
| 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<TypeVariableType>()) |
| 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<BuiltinFloatType>()) { |
| 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<ConstructorDecl>( |
| 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<AnyFunctionType::Param, 8> 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<VarDecl>(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()) { |
| auto *hole = CS.createTypeVariable(locator, TVO_CanBindToHole); |
| (void)CS.recordFix(AllowRefToInvalidDecl::create(CS, locator)); |
| if (!CS.hasType(E)) |
| CS.setType(E, hole); |
| return hole; |
| } |
| |
| 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<ParamDecl>(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 declaration is invalid, let's turn it into a potential hole |
| // and keep generating constraints. |
| if (!knownType && E->getDecl()->isInvalid()) { |
| auto *hole = CS.createTypeVariable(locator, TVO_CanBindToHole); |
| (void)CS.recordFix(AllowRefToInvalidDecl::create(CS, locator)); |
| CS.setType(E, hole); |
| return hole; |
| } |
| |
| // 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 result 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<ValueDecl*> decls = expr->getDecls(); |
| SmallVector<OverloadChoice, 4> 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, 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<AnyFunctionType>()) { |
| 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<AnyMetatypeType>()) { |
| if (BoundGenericType *bgt |
| = meta->getInstanceType()->getAs<BoundGenericType>()) { |
| ArrayRef<Type> 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<TupleTypeElt, 4> 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<VarargExpansionExpr>(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<Type> elementType) { |
| const auto elements = expr->getElements(); |
| unsigned index = 0; |
| |
| using Iterator = decltype(elements)::iterator; |
| CS.addJoinConstraint<Iterator>(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<Type> 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(); |
| |
| // Empty and single element array literals with dictionary contextual |
| // types are fixed during solving, so continue as normal in those |
| // cases. |
| if (numElements > 1) { |
| 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<StringLiteralExpr>(expr) || isa<IntegerLiteralExpr>(expr) || |
| isa<FloatLiteralExpr>(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<std::pair<Type, Type>> 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<Expr *> 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<TupleType>(); |
| auto tty2 = CS.getType(element2)->getAs<TupleType>(); |
| |
| if (tty1 && tty2) { |
| auto mergedKey = false; |
| auto mergedValue = false; |
| |
| auto keyTyvar1 = tty1->getElementTypes()[0]-> |
| getAs<TypeVariableType>(); |
| auto keyTyvar2 = tty2->getElementTypes()[0]-> |
| getAs<TypeVariableType>(); |
| |
| auto keyExpr1 = cast<TupleExpr>(element1)->getElements()[0]; |
| auto keyExpr2 = cast<TupleExpr>(element2)->getElements()[0]; |
| |
| if (keyExpr1->getKind() == keyExpr2->getKind() && |
| isMergeableValueKind(keyExpr1)) { |
| mergedKey = mergeRepresentativeEquivalenceClasses(CS, |
| keyTyvar1, keyTyvar2); |
| } |
| |
| auto valueTyvar1 = tty1->getElementTypes()[1]-> |
| getAs<TypeVariableType>(); |
| auto valueTyvar2 = tty2->getElementTypes()[1]-> |
| getAs<TypeVariableType>(); |
| |
| auto elemExpr1 = cast<TupleExpr>(element1)->getElements()[1]; |
| auto elemExpr2 = cast<TupleExpr>(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<AnyFunctionType::Param, 4> 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<FunctionType>()) |
| 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<ParenPattern>(pattern); |
| |
| // Parentheses don't affect the canonical type, but record them as |
| // type sugar. |
| if (externalPatternType && |
| isa<ParenType>(externalPatternType.getPointer())) { |
| externalPatternType = cast<ParenType>(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<BindingPattern>(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<NamedPattern>(pattern)->getDecl(); |
| |
| Type varType; |
| |
| // Determine whether optionality will be required. |
| auto ROK = ReferenceOwnership::Strong; |
| if (auto *OA = var->getAttrs().getAttribute<ReferenceOwnershipAttr>()) |
| 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<TypedPattern>(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<TuplePattern>(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<AnyFunctionType::Param, 4> 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<TupleTypeElt, 4> 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<OptionalSomePattern>(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<IsPattern>(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<EnumElementPattern>(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<AnyFunctionType::Param, 4> 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<TypeVariableType *, 4> varRefs; |
| bool hasErrorExprs = false; |
| |
| CollectVarRefs(ConstraintSystem &cs) : cs(cs) { } |
| |
| bool shouldWalkCaptureInitializerExpressions() override { return true; } |
| |
| std::pair<bool, Expr *> walkToExprPre(Expr *expr) override { |
| // If there are any error expressions in this closure |
| // it wouldn't be possible to infer its type. |
| if (isa<ErrorExpr>(expr)) { |
| hasErrorExprs = true; |
| return {false, nullptr}; |
| } |
| |
| // Retrieve type variables from references to var decls. |
| if (auto *declRef = dyn_cast<DeclRefExpr>(expr)) { |
| if (auto *varDecl = dyn_cast<VarDecl>(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<UnresolvedDeclRefExpr>(expr)) { |
| auto name = declRef->getName(); |
| auto loc = declRef->getLoc(); |
| if (name.isSimpleName() && loc.isValid()) { |
| auto *varDecl = dyn_cast_or_null<VarDecl>( |
| 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::DynamicType)); |
| 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<Identifier, 4> scratch; |
| associateArgumentLabels( |
| CS.getConstraintLocator(expr), |
| {expr->getArgumentLabels(scratch), |
| expr->getUnlabeledTrailingClosureIndex()}, |
| /*labelsArePermanent=*/isa<CallExpr>(expr)); |
| |
| if (auto *UDE = dyn_cast<UnresolvedDotExpr>(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<ClosureExpr>(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<AnyFunctionType::Param, 8> 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<MetatypeType>()) |
| 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<TupleExpr>(expr)) { |
| SmallVector<TupleTypeElt, 4> 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<TypeVariableType>()) { |
| return typeVar->getImpl().canBindToLValue(); |
| } |
| return type->is<LValueType>(); |
| }; |
| |
| 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<ParenExpr>(E)) |
| return markAcceptableDiscardExprs(PE->getSubExpr()); |
| if (auto *TE = dyn_cast<TupleExpr>(E)) { |
| for (auto &elt : TE->getElements()) |
| markAcceptableDiscardExprs(elt); |
| return; |
| } |
| if (auto *DAE = dyn_cast<DiscardAssignmentExpr>(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<NilLiteralExpr>( |
| 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<Derived, T> to KeyPath<Base, T>. |
| CS.addConstraint(ConstraintKind::Subtype, rootObjectTy, root, locator); |
| } |
| |
| bool didOptionalChain = false; |
| // We start optimistically from an lvalue base. |
| Type base = LValueType::get(root); |
| |
| SmallVector<TypeVariableType *, 2> 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<AbstractClosureExpr>(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<DeclRefExpr>(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<DeclRefExpr>(UDE->getBase()); |
| if (!DRE) |
| return TypeOperation::None; |
| |
| if (DRE->getDecl() != Context.TheBuiltinModule) |
| return TypeOperation::None; |
| |
| return llvm::StringSwitch<TypeOperation>( |
| 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<TupleExpr>(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<MetatypeType>(); |
| auto rhsMeta = CS.getType(rhs)->getAs<MetatypeType>(); |
| 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<InOutType>(); |
| auto rhsMeta = CS.getType(rhs)->getAs<MetatypeType>(); |
| 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<MetatypeType>(); |
| auto rhsMeta = CS.getType(rhs)->getAs<MetatypeType>(); |
| 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<MetatypeType>(); |
| auto rhsMeta = CS.getType(rhs)->getAs<MetatypeType>(); |
| 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<bool, Expr *> 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<ObjCSelectorExpr>(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<KeyPathExpr>(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<CaptureListExpr>(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<ClosureExpr>(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<CoerceExpr>(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<IfExpr>(expr)) { |
| if (!ifExpr->getThenExpr() || !ifExpr->getElseExpr()) |
| return { false, expr }; |
| } |
| |
| if (auto *assignment = dyn_cast<AssignExpr>(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<ApplyExpr>(expr)) { |
| auto fnExpr = apply->getFn(); |
| if (auto *UDE = dyn_cast<UnresolvedDotExpr>(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<ParenExpr>(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<MetatypeType>(); |
| |
| 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<bool, Stmt *> 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<OpaqueTypeArchetypeType>()) { |
| // 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<SolutionApplicationTarget> |
| 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<UnresolvedType>()) { |
| 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<NamedPattern>(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<Expr *, 16> 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<DeclContext *>(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<T: Sequence>(x: T). |
| } |
| |
| // Having a solution implies the requirements have been fulfilled. |
| return CS.solveSingle().hasValue(); |
| } |
| |
| struct ResolvedMemberResult::Implementation { |
| llvm::SmallVector<ValueDecl*, 4> AllDecls; |
| unsigned ViableStartIdx; |
| Optional<unsigned> 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<ValueDecl*> 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<Solution> 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<DefaultArgumentExpr>(arg)) { |
| return; |
| } |
| |
| if (auto *varargExpr = dyn_cast<VarargExpansionExpr>(arg)) { |
| if (auto *arrayExpr = dyn_cast<ArrayExpr>(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<ParenExpr>(expr)) { |
| result.lParenLoc = parenExpr->getLParenLoc(); |
| result.rParenLoc = parenExpr->getRParenLoc(); |
| result.hasTrailingClosure = parenExpr->hasTrailingClosure(); |
| add(parenExpr->getSubExpr(), Identifier(), SourceLoc()); |
| } else if (auto *tupleExpr = dyn_cast<TupleExpr>(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; |
| } |