mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
1284 lines
50 KiB
C++
1284 lines
50 KiB
C++
//===--- 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<NamedPattern>(pattern)->getBoundName();
|
|
|
|
case PatternKind::Typed:
|
|
return findPatternName(cast<TypedPattern>(pattern)->getSubPattern());
|
|
|
|
case PatternKind::Var:
|
|
return findPatternName(cast<VarPattern>(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<ImplicitConversionExpr>(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<ImplicitConversionExpr>(expr)) {
|
|
expr = ice->getSubExpr();
|
|
continue;
|
|
}
|
|
|
|
if (auto dre = dyn_cast<DeclRefExpr>(expr)) {
|
|
loc = dre->getLoc();
|
|
return dre->getDecl();
|
|
}
|
|
|
|
return nullptr;
|
|
} while (true);
|
|
}
|
|
|
|
namespace {
|
|
class ConstraintGenerator : public ExprVisitor<ConstraintGenerator, Type> {
|
|
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 memberLocator =
|
|
CS.getConstraintLocator(expr, ConstraintLocator::Member);
|
|
auto tv = CS.createTypeVariable(memberLocator, 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 an lvalue.
|
|
auto inputTv = CS.createTypeVariable(indexLocator, /*options=*/0);
|
|
auto outputTv = CS.createTypeVariable(resultLocator,
|
|
TVO_CanBindToLValue);
|
|
|
|
auto subscriptMemberLocator
|
|
= CS.getConstraintLocator(expr, ConstraintLocator::SubscriptMember);
|
|
|
|
// 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, subscriptMemberLocator);
|
|
|
|
// 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, { });
|
|
|
|
// 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'.
|
|
return getSuperType(E->getSelf(), E->getLoc(),
|
|
diag::super_not_in_class_method,
|
|
diag::super_with_no_base_class);
|
|
}
|
|
|
|
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 the subexpression.
|
|
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<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.
|
|
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<ValueDecl*> decls = expr->getDecls();
|
|
SmallVector<OverloadChoice, 4> 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<AnyFunctionType>()) {
|
|
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<MetatypeType>()) {
|
|
if (BoundGenericType *bgt
|
|
= meta->getInstanceType()->getAs<BoundGenericType>()) {
|
|
ArrayRef<Type> typeVars = bgt->getGenericArgs();
|
|
ArrayRef<TypeLoc> 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<TupleTypeElt, 4> 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<ParenPattern>(pattern)->getSubPattern(),
|
|
forFunctionParam, locator);
|
|
case PatternKind::Var:
|
|
// Var doesn't affect the type.
|
|
return getTypeForPattern(cast<VarPattern>(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<NamedPattern>(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<T>.
|
|
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<TypedPattern>(pattern)->getType());
|
|
|
|
case PatternKind::Tuple: {
|
|
auto tuplePat = cast<TuplePattern>(pattern);
|
|
SmallVector<TupleTypeElt, 4> 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 T from an implicit lvalue @inout (implicit) T.
|
|
// We model this with the constraint
|
|
//
|
|
// S < @inout(implicit) T
|
|
//
|
|
// where T is a fresh type variable.
|
|
auto tv = CS.createTypeVariable(CS.getConstraintLocator(expr, { }),
|
|
/*options=*/0);
|
|
auto bound = LValueType::get(tv);
|
|
auto result = InOutType::get(tv);
|
|
|
|
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,
|
|
TC_AllowUnboundGenerics))
|
|
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, CS.DC, TypeResolutionOptions());
|
|
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<MetatypeType>())
|
|
superclassTy = MetatypeType::get(superclassTy, CS.getASTContext());
|
|
return superclassTy;
|
|
}
|
|
|
|
Type visitRebindSelfInConstructorExpr(RebindSelfInConstructorExpr *expr) {
|
|
// 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,
|
|
TC_AllowUnboundGenerics))
|
|
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,
|
|
TC_AllowUnboundGenerics))
|
|
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.
|
|
auto locator = CS.getConstraintLocator(expr,
|
|
ConstraintLocator::AssignDest);
|
|
auto typeVar = CS.createTypeVariable(locator, /*options=*/0);
|
|
return LValueType::get(typeVar);
|
|
}
|
|
|
|
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<bool, Expr *> walkToExprPre(Expr *expr) override {
|
|
// Don't recurse into default-value expressions.
|
|
return { !isa<DefaultValueExpr>(expr), expr };
|
|
}
|
|
|
|
Expr *walkToExprPost(Expr *expr) override {
|
|
if (auto implicit = dyn_cast<ImplicitConversionExpr>(expr)) {
|
|
// Skip implicit conversions completely.
|
|
return implicit->getSubExpr();
|
|
}
|
|
|
|
if (auto dotCall = dyn_cast<DotSyntaxCallExpr>(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<ValueDecl *>(&member, 1));
|
|
return new (TC.Context) OverloadedMemberRefExpr(base,
|
|
dotCall->getDotLoc(), members, memberLoc,
|
|
expr->isImplicit());
|
|
}
|
|
}
|
|
|
|
if (auto dotIgnored = dyn_cast<DotSyntaxBaseIgnoredExpr>(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<ValueDecl *>(&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<bool, Expr *> walkToExprPre(Expr *expr) override {
|
|
// For closures containing only a single expression, the body participates
|
|
// in type checking.
|
|
if (auto closure = dyn_cast<ClosureExpr>(expr)) {
|
|
if (closure->hasSingleExpressionBody()) {
|
|
// Visit the closure itself, which produces a function type.
|
|
auto funcTy = CG.visit(expr)->castTo<FunctionType>();
|
|
expr->setType(funcTy);
|
|
}
|
|
|
|
return { true, expr };
|
|
}
|
|
|
|
// We don't visit default value expressions; they've already been
|
|
// type-checked.
|
|
if (isa<DefaultValueExpr>(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<ClosureExpr>(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<bool, Stmt *> 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);
|
|
}
|