//===--- CSGen.cpp - Constraint Generator ---------------------------------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// // // This file implements constraint generation for the type checker. // //===----------------------------------------------------------------------===// #include "ConstraintSystem.h" #include "swift/AST/ASTVisitor.h" #include "swift/AST/ASTWalker.h" #include "swift/AST/Attr.h" #include "swift/AST/Expr.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/APInt.h" using namespace swift; using namespace swift::constraints; /// \brief Retrieve the name bound by the given (immediate) pattern. static Identifier findPatternName(Pattern *pattern) { switch (pattern->getKind()) { case PatternKind::Paren: case PatternKind::Any: case PatternKind::Tuple: return Identifier(); case PatternKind::Named: return cast(pattern)->getBoundName(); case PatternKind::Typed: return findPatternName(cast(pattern)->getSubPattern()); // TODO #define PATTERN(Id, Parent) #define REFUTABLE_PATTERN(Id, Parent) case PatternKind::Id: #include "swift/AST/PatternNodes.def" llvm_unreachable("not implemented"); } llvm_unreachable("Unhandled pattern kind"); } /// \brief Skip any implicit conversions applied to this expression. static Expr *skipImplicitConversions(Expr *expr) { while (auto ice = dyn_cast(expr)) expr = ice->getSubExpr(); return expr; } /// \brief Find the declaration directly referenced by this expression. static ValueDecl *findReferencedDecl(Expr *expr, SourceLoc &loc) { do { expr = expr->getSemanticsProvidingExpr(); if (auto ice = dyn_cast(expr)) { expr = ice->getSubExpr(); continue; } if (auto dre = dyn_cast(expr)) { loc = dre->getLoc(); return dre->getDecl(); } return nullptr; } while (true); } namespace { class ConstraintGenerator : public ExprVisitor { ConstraintSystem &CS; /// \brief 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, Identifier name) { // 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 = base->getType(); auto tv = CS.createTypeVariable( CS.getConstraintLocator(expr, ConstraintLocator::Member), TVO_CanBindToLValue); // FIXME: Constraint below should be a ::Member constraint? CS.addValueMemberConstraint(baseTy, name, tv, CS.getConstraintLocator(expr, ConstraintLocator::MemberRefBase)); return tv; } /// \brief 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) { // If we're referring to an invalid declaration, fail. CS.getTypeChecker().validateDecl(decl, true); if (decl->isInvalid()) return nullptr; auto tv = CS.createTypeVariable( CS.getConstraintLocator(expr, ConstraintLocator::Member), TVO_CanBindToLValue); OverloadChoice choice(base->getType(), decl, /*isSpecialized=*/false); auto locator = CS.getConstraintLocator(expr, ConstraintLocator::Member); CS.addBindOverloadConstraint(tv, choice, locator); return tv; } /// \brief Add constraints for a subscript operation. Type addSubscriptConstraints(Expr *expr, Expr *base, Expr *index) { ASTContext &Context = CS.getASTContext(); // Locators used in this expression. auto indexLocator = CS.getConstraintLocator(expr, ConstraintLocator::SubscriptIndex); auto resultLocator = CS.getConstraintLocator(expr, ConstraintLocator::SubscriptResult); // The base type must have a subscript declaration with type // I -> [inout] O, where I and O are fresh type variables. The index // expression must be convertible to I and the subscript expression // itself has type [inout] O, where O may or may not be settable. auto inputTv = CS.createTypeVariable(indexLocator, /*options=*/0); auto outputTv = CS.createTypeVariable(resultLocator, TVO_CanBindToLValue); // Add the member constraint for a subscript declaration. // FIXME: lame name! auto baseTy = base->getType(); auto fnTy = FunctionType::get(inputTv, outputTv); CS.addValueMemberConstraint(baseTy, Context.getIdentifier("subscript"), fnTy, CS.getConstraintLocator(expr, ConstraintLocator::SubscriptMember)); // Add the constraint that the index expression's type be convertible // to the input type of the subscript operator. CS.addConstraint(ConstraintKind::Conversion, index->getType(), inputTv, indexLocator); return outputTv; } public: ConstraintGenerator(ConstraintSystem &CS) : CS(CS) { } ConstraintSystem &getConstraintSystem() const { return CS; } Type visitErrorExpr(ErrorExpr *E) { // FIXME: Can we do anything with error expressions at this point? return nullptr; } Type visitLiteralExpr(LiteralExpr *expr) { auto protocol = CS.getTypeChecker().getLiteralProtocol(expr); if (!protocol) { return nullptr; } auto tv = CS.createTypeVariable(CS.getConstraintLocator(expr, { }), TVO_PrefersSubtypeBinding); CS.addConstraint(ConstraintKind::ConformsTo, tv, protocol->getDeclaredType()); return tv; } Type visitInterpolatedStringLiteralExpr(InterpolatedStringLiteralExpr *expr) { // Dig out the StringInterpolationConvertible protocol. auto &tc = CS.getTypeChecker(); auto interpolationProto = tc.getProtocol(expr->getLoc(), KnownProtocolKind::StringInterpolationConvertible); if (!interpolationProto) { tc.diagnose(expr->getStartLoc(), diag::interpolation_missing_proto); return nullptr; } // The type of the expression must conform to the // StringInterpolationConvertible protocol. auto tv = CS.createTypeVariable(CS.getConstraintLocator(expr, { }), TVO_PrefersSubtypeBinding); CS.addConstraint(ConstraintKind::ConformsTo, tv, interpolationProto->getDeclaredType()); // Each of the segments needs to be either convertible to the underlying // string type or there must be a string constructor from the segment. unsigned index = 0; for (auto segment : expr->getSegments()) { auto locator = CS.getConstraintLocator( expr, LocatorPathElt::getInterpolationArgument(index++)); Constraint *constraints[2] = { Constraint::create(CS, ConstraintKind::Conversion, segment->getType(), tv, Identifier(), locator), Constraint::create(CS, ConstraintKind::Construction, segment->getType(), tv, Identifier(), locator) }; CS.addConstraint(Constraint::createDisjunction(CS, constraints, locator)); } return tv; } Type visitDeclRefExpr(DeclRefExpr *E) { // If we're referring to an invalid declaration, don't type-check. // // FIXME: If the decl is in error, we get no information from this. // We may, alternatively, want to use a type variable in that case, // and possibly infer the type of the variable that way. CS.getTypeChecker().validateDecl(E->getDecl(), true); if (E->getDecl()->isInvalid()) return nullptr; auto locator = CS.getConstraintLocator(E, { }); // If this is an anonymous closure argument, take it's type and turn it // into an implicit lvalue type. This accounts for the fact that the // closure argument type itself might be inferred to an lvalue type. if (auto var = dyn_cast(E->getDecl())) { if (var->isAnonClosureParam()) { auto tv = CS.createTypeVariable(locator, /*options=*/0); CS.addConstraint(ConstraintKind::Equal, tv, E->getDecl()->getType()); return LValueType::get(tv, LValueType::Qual::DefaultForVar); } } // 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); CS.resolveOverload(locator, tv, OverloadChoice(Type(), E->getDecl(), E->isSpecialized())); return tv; } Type visitOtherConstructorDeclRefExpr(OtherConstructorDeclRefExpr *E) { return E->getType(); } Type visitSuperRefExpr(SuperRefExpr *E) { if (!E->getType()) { // Resolve the super type of 'self'. Type superTy = getSuperType(E->getSelf(), E->getLoc(), diag::super_not_in_class_method, diag::super_with_no_base_class); if (!superTy) return nullptr; superTy = LValueType::get(superTy, LValueType::Qual::DefaultForVar); return adjustLValueForReference(superTy, E->getSelf()->getAttrs().isAssignment()); } return E->getType(); } Type visitUnresolvedConstructorExpr(UnresolvedConstructorExpr *expr) { ASTContext &C = CS.getASTContext(); // Open a member constraint for constructors on the subexpr type. auto baseTy = expr->getSubExpr()->getType()->getRValueType(); auto argsTy = CS.createTypeVariable(CS.getConstraintLocator(expr, { }), TVO_CanBindToLValue|TVO_PrefersSubtypeBinding); auto methodTy = FunctionType::get(argsTy, baseTy); CS.addValueMemberConstraint(baseTy, C.getIdentifier("init"), methodTy, CS.getConstraintLocator(expr, ConstraintLocator::ConstructorMember)); // The result of the expression is the partial application of the // constructor to 'self'. return methodTy; } 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); ArrayRef decls = expr->getDecls(); SmallVector choices; for (unsigned i = 0, n = decls.size(); i != n; ++i) { // If the result is invalid, skip it. // FIXME: Note this as invalid, in case we don't find a solution, // so we don't let errors cascade further. CS.getTypeChecker().validateDecl(decls[i], true); if (decls[i]->isInvalid()) continue; choices.push_back(OverloadChoice(Type(), decls[i], expr->isSpecialized())); } // If there are no valid overloads, give up. if (choices.empty()) return nullptr; // Record this overload set. CS.addOverloadSet(tv, choices, locator); return tv; } Type visitOverloadedMemberRefExpr(OverloadedMemberRefExpr *expr) { // For a reference to an overloaded declaration, we create a type variable // that will be bound to different types depending on which overload // is selected. auto tv = CS.createTypeVariable(CS.getConstraintLocator(expr, { }), TVO_CanBindToLValue); ArrayRef decls = expr->getDecls(); SmallVector choices; auto baseTy = expr->getBase()->getType(); 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. CS.getTypeChecker().validateDecl(decls[i], true); if (decls[i]->isInvalid()) continue; choices.push_back(OverloadChoice(baseTy, decls[i], /*isSpecialized=*/false)); } // If there are no valid overloads, give up. if (choices.empty()) return nullptr; // Record this overload set. auto locator = CS.getConstraintLocator(expr, ConstraintLocator::Member); CS.addOverloadSet(tv, choices, 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); } Type visitMemberRefExpr(MemberRefExpr *expr) { return addMemberRefConstraints(expr, expr->getBase(), expr->getMember().getDecl()); } Type visitExistentialMemberRefExpr(ExistentialMemberRefExpr *expr) { return addMemberRefConstraints(expr, expr->getBase(), expr->getDecl()); } Type visitArchetypeMemberRefExpr(ArchetypeMemberRefExpr *expr) { return addMemberRefConstraints(expr, expr->getBase(), expr->getDecl()); } Type visitDynamicMemberRefExpr(DynamicMemberRefExpr *expr) { return addMemberRefConstraints(expr, expr->getBase(), expr->getMember().getDecl()); } Type visitUnresolvedMemberExpr(UnresolvedMemberExpr *expr) { auto baseLocator = CS.getConstraintLocator( expr, ConstraintLocator::MemberRefBase); auto memberLocator = CS.getConstraintLocator(expr, ConstraintLocator::UnresolvedMember); auto baseTy = CS.createTypeVariable(baseLocator, /*options=*/0); auto memberTy = CS.createTypeVariable(memberLocator, TVO_CanBindToLValue); // An unresolved member expression '.member' is modeled as a value member // constraint // // T0.metatype[.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 &ctx = CS.getASTContext(); auto baseMetaTy = MetatypeType::get(baseTy, ctx); CS.addValueMemberConstraint(baseMetaTy, expr->getName(), memberTy, memberLocator); // If there is an argument, apply it. if (auto arg = expr->getArgument()) { // The result type of the function must be the base type. auto outputTy = CS.createTypeVariable( CS.getConstraintLocator(expr, ConstraintLocator::FunctionResult), /*options=*/0); CS.addConstraint(ConstraintKind::Equal, outputTy, baseTy, CS.getConstraintLocator(expr, ConstraintLocator::RvalueAdjustment)); // The function/enum case must be callable with the given argument. auto funcTy = FunctionType::get(arg->getType(), outputTy); CS.addConstraint(ConstraintKind::ApplicableFunction, funcTy, memberTy, CS.getConstraintLocator(expr, ConstraintLocator::ApplyFunction)); return baseTy; } // Otherwise, the member needs to have the same type as the base. CS.addConstraint(ConstraintKind::Equal, baseTy, memberTy, CS.getConstraintLocator(expr, ConstraintLocator::RvalueAdjustment)); return memberTy; } Type visitUnresolvedDotExpr(UnresolvedDotExpr *expr) { return addMemberRefConstraints(expr, expr->getBase(), expr->getName()); } Type visitUnresolvedSpecializeExpr(UnresolvedSpecializeExpr *expr) { auto baseTy = expr->getSubExpr()->getType(); // We currently only support explicit specialization of generic types. // FIXME: We could support explicit function specialization. auto &tc = CS.getTypeChecker(); if (baseTy->is()) { tc.diagnose(expr->getSubExpr()->getLoc(), diag::cannot_explicitly_specialize_generic_function); tc.diagnose(expr->getLAngleLoc(), diag::while_parsing_as_left_angle_bracket); return Type(); } if (MetatypeType *meta = baseTy->getAs()) { if (BoundGenericType *bgt = meta->getInstanceType()->getAs()) { ArrayRef typeVars = bgt->getGenericArgs(); ArrayRef specializations = expr->getUnresolvedParams(); // If we have too many generic arguments, complain. if (specializations.size() > typeVars.size()) { tc.diagnose(expr->getSubExpr()->getLoc(), diag::type_parameter_count_mismatch, bgt->getDecl()->getName(), typeVars.size(), specializations.size(), false) .highlight(SourceRange(expr->getLAngleLoc(), expr->getRAngleLoc())); tc.diagnose(bgt->getDecl(), diag::generic_type_declared_here, bgt->getDecl()->getName()); return Type(); } // Bind the specified generic arguments to the type variables in the // open type. for (size_t i = 0, size = specializations.size(); i < size; ++i) { CS.addConstraint(ConstraintKind::Equal, typeVars[i], specializations[i].getType()); } return baseTy; } else { tc.diagnose(expr->getSubExpr()->getLoc(), diag::not_a_generic_type, meta->getInstanceType()); tc.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. tc.diagnose(expr->getSubExpr()->getLoc(), diag::not_a_generic_definition); tc.diagnose(expr->getLAngleLoc(), diag::while_parsing_as_left_angle_bracket); return Type(); } Type visitSequenceExpr(SequenceExpr *expr) { llvm_unreachable("Didn't even parse?"); } Type visitParenExpr(ParenExpr *expr) { expr->setType(expr->getSubExpr()->getType()); return expr->getType(); } Type visitTupleExpr(TupleExpr *expr) { // The type of a tuple expression is simply a tuple of the types of // its subexpressions. SmallVector elements; elements.reserve(expr->getNumElements()); for (unsigned i = 0, n = expr->getNumElements(); i != n; ++i) { elements.push_back(TupleTypeElt(expr->getElement(i)->getType(), expr->getElementName(i))); } return TupleType::get(elements, CS.getASTContext()); } Type visitSubscriptExpr(SubscriptExpr *expr) { return addSubscriptConstraints(expr, expr->getBase(), expr->getIndex()); } Type visitArrayExpr(ArrayExpr *expr) { ASTContext &C = CS.getASTContext(); // An array expression can be of a type T that conforms to the // ArrayLiteralConvertible protocol. auto &tc = CS.getTypeChecker(); ProtocolDecl *arrayProto = tc.getProtocol(expr->getLoc(), KnownProtocolKind::ArrayLiteralConvertible); if (!arrayProto) { return Type(); } auto locator = CS.getConstraintLocator(expr, { }); auto arrayTy = CS.createTypeVariable(locator, TVO_PrefersSubtypeBinding); // The array must be an array literal type. CS.addConstraint(ConstraintKind::ConformsTo, arrayTy, arrayProto->getDeclaredType(), locator); // Its subexpression should be convertible to a tuple (T.Element...). // FIXME: We should really go through the conformance above to extract // the element type, rather than just looking for the element type. // FIXME: Member constraint is still weird here. auto arrayElementTy = CS.createTypeVariable( CS.getConstraintLocator(expr, ConstraintLocator::Member), /*options=*/0); CS.addTypeMemberConstraint(arrayTy, C.getIdentifier("Element"), arrayElementTy); // Introduce conversions from each element to the element type of the // array. unsigned index = 0; for (auto element : expr->getElements()) { CS.addConstraint(ConstraintKind::Conversion, element->getType(), arrayElementTy, CS.getConstraintLocator( expr, LocatorPathElt::getTupleElement(index++))); } return arrayTy; } Type visitDictionaryExpr(DictionaryExpr *expr) { ASTContext &C = CS.getASTContext(); // A dictionary expression can be of a type T that conforms to the // DictionaryLiteralConvertible protocol. // FIXME: This isn't actually used for anything at the moment. auto &tc = CS.getTypeChecker(); ProtocolDecl *dictionaryProto = tc.getProtocol(expr->getLoc(), KnownProtocolKind::DictionaryLiteralConvertible); if (!dictionaryProto) { return Type(); } auto locator = CS.getConstraintLocator(expr, { }); auto dictionaryTy = CS.createTypeVariable(locator, TVO_PrefersSubtypeBinding); // The array must be a dictionary literal type. CS.addConstraint(ConstraintKind::ConformsTo, dictionaryTy, dictionaryProto->getDeclaredType(), locator); // Its subexpression should be convertible to a tuple // ((T.Key,T.Value)...). // // FIXME: We should be getting Key/Value through the witnesses, not // directly from the type. // FIXME: Member locator here is weird. auto memberLocator = CS.getConstraintLocator(expr, ConstraintLocator::Member); auto dictionaryKeyTy = CS.createTypeVariable(memberLocator, /*options=*/0); CS.addTypeMemberConstraint(dictionaryTy, C.getIdentifier("Key"), dictionaryKeyTy); auto dictionaryValueTy = CS.createTypeVariable(memberLocator, /*options=*/0); CS.addTypeMemberConstraint(dictionaryTy, C.getIdentifier("Value"), dictionaryValueTy); TupleTypeElt tupleElts[2] = { TupleTypeElt(dictionaryKeyTy), TupleTypeElt(dictionaryValueTy) }; Type elementTy = TupleType::get(tupleElts, C); // Introduce conversions from each element to the element type of the // dictionary. unsigned index = 0; for (auto element : expr->getElements()) { CS.addConstraint(ConstraintKind::Conversion, element->getType(), elementTy, CS.getConstraintLocator( expr, LocatorPathElt::getTupleElement(index++))); } return dictionaryTy; } Type visitExistentialSubscriptExpr(ExistentialSubscriptExpr *expr) { return addSubscriptConstraints(expr, expr->getBase(), expr->getIndex()); } Type visitArchetypeSubscriptExpr(ArchetypeSubscriptExpr *expr) { return addSubscriptConstraints(expr, expr->getBase(), expr->getIndex()); } Type visitDynamicSubscriptExpr(DynamicSubscriptExpr *expr) { return addSubscriptConstraints(expr, expr->getBase(), expr->getIndex()); } Type visitTupleElementExpr(TupleElementExpr *expr) { ASTContext &context = CS.getASTContext(); Identifier name = context.getIdentifier(llvm::utostr(expr->getFieldNumber())); return addMemberRefConstraints(expr, expr->getBase(), name); } /// \brief Produces a type for the given pattern, filling in any missing /// type information with fresh type variables. /// /// \param pattern The pattern. Type getTypeForPattern(Pattern *pattern, bool forFunctionParam, ConstraintLocatorBuilder locator) { switch (pattern->getKind()) { case PatternKind::Paren: // Parentheses don't affect the type. return getTypeForPattern(cast(pattern)->getSubPattern(), forFunctionParam, locator); case PatternKind::Any: // For a pattern of unknown type, create a new type variable. return CS.createTypeVariable(CS.getConstraintLocator(locator), forFunctionParam? TVO_CanBindToLValue : 0); case PatternKind::Named: { auto var = cast(pattern)->getDecl(); // For a named pattern without a type, create a new type variable // and use it as the type of the variable. Type ty = CS.createTypeVariable(CS.getConstraintLocator(locator), forFunctionParam? TVO_CanBindToLValue : 0); // For [weak] variables, use Optional. if (!forFunctionParam && var->getAttrs().isWeak()) { ty = CS.getTypeChecker().getOptionalType(var->getLoc(), ty); if (!ty) return Type(); } // We want to set the variable's type here when type-checking // a function's parameter clauses because we're going to // type-check the entire function body within the context of // the constraint system. In contrast, when type-checking a // variable binding, we really don't want to set the // variable's type because it can easily escape the constraint // system and become a dangling type reference. if (forFunctionParam) var->setType(ty); return ty; } case PatternKind::Typed: // For a typed pattern, simply return the opened type of the pattern. // FIXME: Error recovery if the type is an error type? return CS.openType(cast(pattern)->getType()); case PatternKind::Tuple: { auto tuplePat = cast(pattern); SmallVector tupleTypeElts; tupleTypeElts.reserve(tuplePat->getNumFields()); for (unsigned i = 0, e = tuplePat->getFields().size(); i != e; ++i) { auto tupleElt = tuplePat->getFields()[i]; bool isVararg = tuplePat->hasVararg() && i == e-1; Type eltTy = getTypeForPattern(tupleElt.getPattern(), forFunctionParam, locator.withPathElement( LocatorPathElt::getTupleElement(i))); // Only cons up a tuple element name in a function signature. Identifier name; if (forFunctionParam) name = findPatternName(tupleElt.getPattern()); Type varArgBaseTy; tupleTypeElts.push_back(TupleTypeElt(eltTy, name, tupleElt.getDefaultArgKind(), isVararg)); } return TupleType::get(tupleTypeElts, CS.getASTContext()); } // TODO #define PATTERN(Id, Parent) #define REFUTABLE_PATTERN(Id, Parent) case PatternKind::Id: #include "swift/AST/PatternNodes.def" llvm_unreachable("not implemented"); } llvm_unreachable("Unhandled pattern kind"); } Type visitClosureExpr(ClosureExpr *expr) { // 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 funcTy; if (expr->hasExplicitResultType()) { funcTy = expr->getExplicitResultTypeLoc().getType(); } else { // If no return type was specified, create a fresh type // variable for it. funcTy = CS.createTypeVariable( CS.getConstraintLocator(expr, ConstraintLocator::ClosureResult), /*options=*/0); } // Walk through the patterns in the func expression, backwards, // computing the type of each pattern (which may involve fresh type // variables where parameter types where no provided) and building the // eventual function type. auto paramTy = getTypeForPattern( expr->getParams(), /*forFunctionParam*/ true, CS.getConstraintLocator( expr, LocatorPathElt::getTupleElement(0))); funcTy = FunctionType::get(paramTy, funcTy); return funcTy; } Type visitAutoClosureExpr(AutoClosureExpr *expr) { llvm_unreachable("Already type-checked"); } Type visitModuleExpr(ModuleExpr *expr) { // Module expressions always have a fixed type. return expr->getType(); } Type visitAddressOfExpr(AddressOfExpr *expr) { // The address-of operator produces an explicit lvalue // [inout(settable)] T from a (potentially implicit) settable lvalue S. // We model this with the constraint // // S < [inout(implicit, settable)] T // // where T is a fresh type variable. auto tv = CS.createTypeVariable(CS.getConstraintLocator(expr, { }), /*options=*/0); auto bound = LValueType::get(tv, LValueType::Qual::DefaultForType| LValueType::Qual::Implicit); auto result = LValueType::get(tv, LValueType::Qual::DefaultForType); CS.addConstraint(ConstraintKind::Subtype, expr->getSubExpr()->getType(), bound, CS.getConstraintLocator(expr, ConstraintLocator::AddressOf)); return result; } Type visitNewArrayExpr(NewArrayExpr *expr) { // Validate the element type. auto &tc = CS.getTypeChecker(); if (tc.validateType(expr->getElementTypeLoc(), CS.DC, /*allowUnboundGenerics=*/true)) return nullptr; // Open up the element type. auto elementTy = CS.openType(expr->getElementTypeLoc().getType()); auto resultTy = elementTy; for (unsigned i = expr->getBounds().size(); i != 1; --i) { // FIXME: To support multidimensional arrays, we'll need to look at // the expressions in here. auto &bound = expr->getBounds()[i-1]; resultTy = tc.getArraySliceType(bound.Brackets.Start, resultTy); } // The outer bound must be an ArrayBound. auto &outerBound = expr->getBounds()[0]; auto arrayBoundProto = tc.getProtocol(expr->getLoc(), KnownProtocolKind::ArrayBound); if (!arrayBoundProto) return nullptr; CS.addConstraint(ConstraintKind::ConformsTo, outerBound.Value->getType(), arrayBoundProto->getDeclaredType(), CS.getConstraintLocator(outerBound.Value, { })); // If we have an explicit constructor, make sure we can call it. // Either we have an explicit constructor closure or else ElementType must // be default constructible. if (expr->hasConstructionFunction()) { // FIXME: Assume the index type is DefaultIntegerLiteralType for now. auto intProto = tc.getProtocol( expr->getConstructionFunction()->getLoc(), KnownProtocolKind::IntegerLiteralConvertible); Type intTy = tc.getDefaultType(intProto, CS.DC); assert(intTy && "No default integer type?"); Expr *constructionFn = expr->getConstructionFunction(); Type constructionTy = FunctionType::get(intTy, elementTy); CS.addConstraint(ConstraintKind::Conversion, constructionFn->getType(), constructionTy, CS.getConstraintLocator( expr, ConstraintLocator::NewArrayConstructor)); } else { // Otherwise, ElementType must be default constructible. Type defaultCtorTy = FunctionType::get(TupleType::getEmpty(tc.Context), elementTy); CS.addValueMemberConstraint(elementTy, tc.Context.getIdentifier("init"), defaultCtorTy, CS.getConstraintLocator(expr, ConstraintLocator::NewArrayElement)); } return tc.getArraySliceType(outerBound.Brackets.Start, resultTy); } Type visitMetatypeExpr(MetatypeExpr *expr) { if (auto base = expr->getBase()) { auto tv = CS.createTypeVariable(CS.getConstraintLocator(expr, { }), /*options=*/0); CS.addConstraint(ConstraintKind::Equal, tv, base->getType(), CS.getConstraintLocator(expr, ConstraintLocator::RvalueAdjustment)); return MetatypeType::get(tv, CS.getASTContext()); } if (auto baseTyR = expr->getBaseTypeRepr()) { auto type = CS.TC.resolveType(baseTyR, /*SIL*/ false, CS.DC); if (type) return MetatypeType::get(type, CS.getASTContext()); return Type(); } // This is an artificial MetatypeExpr, so it's fully type-checked. return expr->getType(); } Type visitOpaqueValueExpr(OpaqueValueExpr *expr) { return expr->getType(); } Type visitDefaultValueExpr(DefaultValueExpr *expr) { expr->setType(expr->getSubExpr()->getType()); return expr->getType(); } Type visitApplyExpr(ApplyExpr *expr) { // The function subexpression has some rvalue type T1 -> T2 for fresh // variables T1 and T2. auto outputTy = CS.createTypeVariable( CS.getConstraintLocator(expr, ConstraintLocator::FunctionResult), /*options=*/0); auto funcTy = FunctionType::get(expr->getArg()->getType(), outputTy); CS.addConstraint(ConstraintKind::ApplicableFunction, funcTy, expr->getFn()->getType(), CS.getConstraintLocator(expr, ConstraintLocator::ApplyFunction)); return outputTy; } Type getSuperType(ValueDecl *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 &tc = CS.getTypeChecker(); ClassDecl *classDecl = typeContext->getDeclaredTypeInContext() ->getClassOrBoundGenericClass(); if (!classDecl) { tc.diagnose(diagLoc, diag_not_in_class); return Type(); } if (!classDecl->hasSuperclass()) { tc.diagnose(diagLoc, diag_no_base_class); return Type(); } Type superclassTy = typeContext->getDeclaredTypeInContext() ->getSuperclass(&tc); if (selfDecl->getType()->is()) superclassTy = MetatypeType::get(superclassTy, CS.getASTContext()); return superclassTy; } Type visitRebindSelfInConstructorExpr(RebindSelfInConstructorExpr *expr) { // The subexpression must be a supertype of 'self' type. CS.addConstraint(ConstraintKind::Subtype, expr->getSelf()->getType(), expr->getSubExpr()->getType()); // The result is void. return TupleType::getEmpty(CS.getASTContext()); } Type visitIfExpr(IfExpr *expr) { // The conditional expression must conform to LogicValue. Expr *condExpr = expr->getCondExpr(); auto logicValue = CS.getTypeChecker().getProtocol(expr->getQuestionLoc(), KnownProtocolKind::LogicValue); if (!logicValue) return Type(); CS.addConstraint(ConstraintKind::ConformsTo, condExpr->getType(), logicValue->getDeclaredType(), CS.getConstraintLocator(expr, { })); // The branches must be convertible to a common type. auto resultTy = CS.createTypeVariable(CS.getConstraintLocator(expr, { }), TVO_PrefersSubtypeBinding); CS.addConstraint(ConstraintKind::Conversion, expr->getThenExpr()->getType(), resultTy, CS.getConstraintLocator(expr, ConstraintLocator::IfThen)); CS.addConstraint(ConstraintKind::Conversion, expr->getElseExpr()->getType(), resultTy, CS.getConstraintLocator(expr, ConstraintLocator::IfElse)); return resultTy; } Type visitImplicitConversionExpr(ImplicitConversionExpr *expr) { llvm_unreachable("Already type-checked"); } Type visitConditionalCheckedCastExpr(ConditionalCheckedCastExpr *expr) { auto &tc = CS.getTypeChecker(); // Validate the resulting type. if (tc.validateType(expr->getCastTypeLoc(), CS.DC, /*allowUnboundGenerics=*/true)) return nullptr; // Open the type we're casting to. auto toType = CS.openType(expr->getCastTypeLoc().getType()); expr->getCastTypeLoc().setType(toType, /*validated=*/true); // Create a type variable to describe the result. auto locator = CS.getConstraintLocator(expr, { }); auto typeVar = CS.createTypeVariable(locator, /*options=*/0); // Form the constraints for the implicit conversion case. auto fromType = expr->getSubExpr()->getType(); Constraint *convConstraints[2] = { Constraint::create(CS, ConstraintKind::Conversion, fromType, toType, Identifier(), locator), Constraint::create(CS, ConstraintKind::Equal, typeVar, toType, Identifier(), locator) }; auto convConstraint = Constraint::createConjunction(CS, convConstraints, locator); // Form the constraints for the checked cast case. auto optToType = tc.getOptionalType(expr->getLoc(), toType); Constraint *checkConstraints[2] = { Constraint::create(CS, ConstraintKind::CheckedCast, fromType, toType, Identifier(), locator), Constraint::create(CS, ConstraintKind::Equal, typeVar, optToType, Identifier(), locator) }; auto checkConstraint = Constraint::createConjunction(CS, checkConstraints, locator); // Form the disjunction of the two kinds of constraints. Constraint *constraints[2] = { convConstraint, checkConstraint }; CS.addConstraint(Constraint::createDisjunction(CS, constraints, locator)); return typeVar; } Type visitIsaExpr(IsaExpr *expr) { // Validate the type. auto &tc = CS.getTypeChecker(); if (tc.validateType(expr->getCastTypeLoc(), CS.DC, /*allowUnboundGenerics=*/true)) return nullptr; // Open up the type we're checking. auto toType = CS.openType(expr->getCastTypeLoc().getType()); expr->getCastTypeLoc().setType(toType, /*validated=*/true); // Add a checked cast constraint. auto fromType = expr->getSubExpr()->getType(); CS.addConstraint(ConstraintKind::CheckedCast, fromType, toType, CS.getConstraintLocator(expr, { })); // The result is Bool. return CS.getTypeChecker().lookupBoolType(CS.DC); } Type visitCoerceExpr(CoerceExpr *expr) { return expr->getCastTypeLoc().getType(); } Type visitDiscardAssignmentExpr(DiscardAssignmentExpr *expr) { // '_' is only allowed in assignments, so give it an AssignDest locator. return CS.createTypeVariable( CS.getConstraintLocator(expr, ConstraintLocator::AssignDest), TVO_CanBindToLValue); } Type visitAssignExpr(AssignExpr *expr) { // Compute the type to which the source must be converted to allow // assignment to the destination. auto destTy = CS.computeAssignDestType(expr->getDest(), expr->getLoc()); if (!destTy) return Type(); // The source must be convertible to the destination. auto assignLocator = CS.getConstraintLocator(expr->getSrc(), ConstraintLocator::AssignSource); CS.addConstraint(ConstraintKind::Conversion, expr->getSrc()->getType(), destTy, assignLocator); expr->setType(TupleType::getEmpty(CS.getASTContext())); return expr->getType(); } Type visitUnresolvedPatternExpr(UnresolvedPatternExpr *expr) { // If there are UnresolvedPatterns floating around after name binding, // they are pattern productions in invalid positions. CS.TC.diagnose(expr->getLoc(), diag::pattern_in_expr, expr->getSubPattern()->getKind()); return Type(); } /// 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 = CS.getTypeChecker().getOptionalType(optLoc, valueTy); if (!optTy || CS.getTypeChecker().requireOptionalIntrinsics(optLoc)) return Type(); return optTy; } Type visitBindOptionalExpr(BindOptionalExpr *expr) { // The operand must be coercible to T?, and we will have type T. auto valueTy = CS.createTypeVariable(CS.getConstraintLocator(expr, { }), /*options*/ 0); Type optTy = getOptionalType(expr->getQuestionLoc(), valueTy); if (!optTy) return Type(); CS.addConstraint(ConstraintKind::Conversion, expr->getSubExpr()->getType(), optTy, CS.getConstraintLocator(expr, {})); return valueTy; } 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); Type optTy = getOptionalType(expr->getSubExpr()->getLoc(), valueTy); if (!optTy) return Type(); CS.addConstraint(ConstraintKind::Conversion, expr->getSubExpr()->getType(), optTy, CS.getConstraintLocator(expr, {})); return optTy; } Type visitForceValueExpr(ForceValueExpr *expr) { // The value can be forced in two different ways: // - Either the value is coercible to T? and the result is T, which // retrieves the value stored in the optional // - The value is of rvalue type DynamicLookup, and the result is // some class type T. auto valueTy = CS.createTypeVariable(CS.getConstraintLocator(expr, { }), TVO_PrefersSubtypeBinding); Type optTy = getOptionalType(expr->getSubExpr()->getLoc(), valueTy); if (!optTy) return Type(); auto locator = CS.getConstraintLocator(expr, {}); Constraint *downcastConstraints[2] = { Constraint::create(CS, ConstraintKind::DynamicLookupValue, expr->getSubExpr()->getType(), Type(), Identifier(), locator), Constraint::create(CS, ConstraintKind::Class, valueTy, Type(), Identifier(), locator) }; Constraint *constraints[2] = { // The subexpression is convertible to T? Constraint::create(CS, ConstraintKind::Conversion, expr->getSubExpr()->getType(), optTy, Identifier(), locator), // The subexpression is a DynamicLookup value and the resulting value // is of class type. Constraint::createConjunction(CS, downcastConstraints, locator) }; CS.addConstraint(Constraint::createDisjunction(CS, constraints, locator)); // The result is of type T. return valueTy; } }; /// \brief AST walker that "sanitizes" an expression for the /// constraint-based type checker. /// /// This is only necessary because Sema fills in too much type information /// before the type-checker runs, causing redundant work. class SanitizeExpr : public ASTWalker { TypeChecker &TC; public: SanitizeExpr(TypeChecker &tc) : TC(tc) { } std::pair walkToExprPre(Expr *expr) override { // Don't recurse into default-value expressions. return { !isa(expr), expr }; } Expr *walkToExprPost(Expr *expr) override { if (auto implicit = dyn_cast(expr)) { // Skip implicit conversions completely. return implicit->getSubExpr(); } if (auto dotCall = dyn_cast(expr)) { // A DotSyntaxCallExpr is a member reference that has already been // type-checked down to a call; turn it back into an overloaded // member reference expression. SourceLoc memberLoc; if (auto member = findReferencedDecl(dotCall->getFn(), memberLoc)) { auto base = skipImplicitConversions(dotCall->getArg()); auto members = TC.Context.AllocateCopy(ArrayRef(&member, 1)); return new (TC.Context) OverloadedMemberRefExpr(base, dotCall->getDotLoc(), members, memberLoc, expr->isImplicit()); } } if (auto dotIgnored = dyn_cast(expr)) { // A DotSyntaxBaseIgnoredExpr is a static member reference that has // already been type-checked down to a call where the argument doesn't // actually matter; turn it back into an overloaded member reference // expression. SourceLoc memberLoc; if (auto member = findReferencedDecl(dotIgnored->getRHS(), memberLoc)) { auto base = skipImplicitConversions(dotIgnored->getLHS()); auto members = TC.Context.AllocateCopy(ArrayRef(&member, 1)); return new (TC.Context) OverloadedMemberRefExpr(base, dotIgnored->getDotLoc(), members, memberLoc, expr->isImplicit()); } } return expr; } }; class ConstraintWalker : public ASTWalker { ConstraintGenerator &CG; public: ConstraintWalker(ConstraintGenerator &CG) : CG(CG) { } std::pair walkToExprPre(Expr *expr) override { // For closures containing only a single expression, the body participates // in type checking. if (auto closure = dyn_cast(expr)) { if (closure->hasSingleExpressionBody()) { // Visit the closure itself, which produces a function type. auto funcTy = CG.visit(expr)->castTo(); expr->setType(funcTy); } return { true, expr }; } // We don't visit default value expressions; they've already been // type-checked. if (isa(expr)) { return { false, expr }; } return { true, expr }; } /// \brief Once we've visited the children of the given expression, /// generate constraints from the expression. Expr *walkToExprPost(Expr *expr) override { if (auto closure = dyn_cast(expr)) { if (closure->hasSingleExpressionBody()) { // Visit the body. It's type needs to be convertible to the function's // return type. auto resultTy = closure->getResultType(); auto bodyTy = closure->getSingleExpressionBody()->getType(); CG.getConstraintSystem() .addConstraint(ConstraintKind::Conversion, bodyTy, resultTy, CG.getConstraintSystem() .getConstraintLocator( expr, ConstraintLocator::ClosureResult)); return expr; } } if (auto type = CG.visit(expr)) { expr->setType(CG.getConstraintSystem().simplifyType(type)); return expr; } return nullptr; } /// \brief Ignore statements. std::pair walkToStmtPre(Stmt *stmt) override { return { false, stmt }; } /// \brief Ignore declarations. bool walkToDeclPre(Decl *decl) override { return false; } }; } // end anonymous namespace Expr *ConstraintSystem::generateConstraints(Expr *expr) { // Remove implicit conversions from the expression. expr = expr->walk(SanitizeExpr(getTypeChecker())); // Walk the expression, generating constraints. ConstraintGenerator cg(*this); ConstraintWalker cw(cg); return expr->walk(cw); } Expr *ConstraintSystem::generateConstraintsShallow(Expr *expr) { // Sanitize the expression. expr = SanitizeExpr(getTypeChecker()).walkToExprPost(expr); // Visit the top-level expression generating constraints. ConstraintGenerator cg(*this); auto type = cg.visit(expr); if (!type) return nullptr; expr->setType(type); return expr; } Type ConstraintSystem::generateConstraints(Pattern *pattern, ConstraintLocatorBuilder locator) { ConstraintGenerator cg(*this); return cg.getTypeForPattern(pattern, /*forFunctionParam*/ false, locator); }