Check a complete array-new expression within a single constraint system.

Fixes <rdar://problem/15653973>.


Swift SVN r11262
This commit is contained in:
Doug Gregor
2013-12-13 19:16:19 +00:00
parent 6faf833365
commit 1d12c5352c
6 changed files with 85 additions and 75 deletions

View File

@@ -787,30 +787,55 @@ namespace {
}
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;
auto &tc = CS.getTypeChecker();
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];
if (!bound.Value) {
resultTy = tc.getArraySliceType(bound.Brackets.Start, resultTy);
continue;
}
// FIXME: When we get a constant expression evaluator, we'll have
// to use it here.
auto literal = cast<IntegerLiteralExpr>(
bound.Value->getSemanticsProvidingExpr());
resultTy = ArrayType::get(resultTy, literal->getValue().getZExtValue(),
tc.Context);
resultTy = tc.getArraySliceType(bound.Brackets.Start, resultTy);
}
auto &outerBound = expr->getBounds()[0];
// 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()) {
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,
tc.Context);
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,
tc.Context);
@@ -1143,12 +1168,8 @@ namespace {
SanitizeExpr(TypeChecker &tc) : TC(tc) { }
std::pair<bool, Expr *> walkToExprPre(Expr *expr) override {
// Don't recur into array-new or default-value expressions.
return {
!isa<NewArrayExpr>(expr)
&& !isa<DefaultValueExpr>(expr),
expr
};
// Don't recurse into default-value expressions.
return { !isa<DefaultValueExpr>(expr), expr };
}
Expr *walkToExprPost(Expr *expr) override {
@@ -1211,16 +1232,6 @@ namespace {
return { true, expr };
}
// For new array expressions, we visit the node but not any of its
// children.
// FIXME: If new array expressions gain an initializer, we'll need to
// visit that first.
if (auto newArray = dyn_cast<NewArrayExpr>(expr)) {
auto type = CG.visitNewArrayExpr(newArray);
expr->setType(type);
return { false, expr };
}
// We don't visit default value expressions; they've already been
// type-checked.
if (isa<DefaultValueExpr>(expr)) {