Skip to content

Commit 2d887bc

Browse files
committed
Implement Vector literals
1 parent fbad0da commit 2d887bc

File tree

9 files changed

+151
-15
lines changed

9 files changed

+151
-15
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8094,5 +8094,12 @@ ERROR(availability_value_generic_type_only_version_newer, none,
80948094
ERROR(invalid_value_for_type_same_type,none,
80958095
"cannot constrain type parameter %0 to be integer %1", (Type, Type))
80968096

8097+
//===----------------------------------------------------------------------===//
8098+
// MARK: Vector
8099+
//===----------------------------------------------------------------------===//
8100+
8101+
ERROR(vector_literal_incorrect_count,none,
8102+
"expected %0 elements in vector literal, but got %1", (Type, Type))
8103+
80978104
#define UNDEFINE_DIAGNOSTIC_MACROS
80988105
#include "DefineDiagnosticMacros.h"

include/swift/AST/KnownStdlibTypes.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,4 +97,6 @@ KNOWN_STDLIB_TYPE_DECL(DecodingError, NominalTypeDecl, 0)
9797

9898
KNOWN_STDLIB_TYPE_DECL(Result, NominalTypeDecl, 2)
9999

100+
KNOWN_STDLIB_TYPE_DECL(Vector, NominalTypeDecl, 2)
101+
100102
#undef KNOWN_STDLIB_TYPE_DECL

lib/AST/Type.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -764,8 +764,11 @@ CanType CanType::wrapInOptionalTypeImpl(CanType type) {
764764

765765
Type TypeBase::isArrayType() {
766766
if (auto boundStruct = getAs<BoundGenericStructType>()) {
767-
if (boundStruct->getDecl() == getASTContext().getArrayDecl())
767+
if (isArray())
768768
return boundStruct->getGenericArgs()[0];
769+
770+
if (isVector())
771+
return boundStruct->getGenericArgs()[1];
769772
}
770773
return Type();
771774
}

lib/IRGen/GenReflection.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1163,6 +1163,11 @@ class FixedTypeMetadataBuilder : public ReflectionMetadataBuilder {
11631163
};
11641164

11651165
void IRGenModule::emitBuiltinTypeMetadataRecord(CanType builtinType) {
1166+
// If this builtin is generic, don't emit anything.
1167+
if (builtinType->hasTypeParameter()) {
1168+
return;
1169+
}
1170+
11661171
FixedTypeMetadataBuilder builder(*this, builtinType);
11671172
builder.emit();
11681173
}

lib/SILGen/SILGenExpr.cpp

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4600,7 +4600,76 @@ visitMagicIdentifierLiteralExpr(MagicIdentifierLiteralExpr *E, SGFContext C) {
46004600
llvm_unreachable("Unhandled MagicIdentifierLiteralExpr in switch.");
46014601
}
46024602

4603+
static RValue emitVectorLiteral(SILGenFunction &SGF, CollectionExpr *E,
4604+
SGFContext C) {
4605+
ArgumentScope scope(SGF, E);
4606+
4607+
auto vectorType = E->getType()->castTo<BoundGenericType>();
4608+
auto loweredVectorType = SGF.getLoweredType(vectorType);
4609+
auto elementType = vectorType->getGenericArgs()[1]->getCanonicalType();
4610+
auto loweredElementType = SGF.getLoweredType(elementType);
4611+
auto &eltTL = SGF.getTypeLowering(AbstractionPattern::getOpaque(), elementType);
4612+
4613+
SILValue alloc = SGF.emitTemporaryAllocation(E, loweredVectorType);
4614+
SILValue addr = SGF.B.createUncheckedAddrCast(E, alloc,
4615+
loweredElementType.getAddressType());
4616+
4617+
// Cleanups for any elements that have been initialized so far.
4618+
SmallVector<CleanupHandle, 8> cleanups;
4619+
4620+
for (unsigned index : range(E->getNumElements())) {
4621+
auto destAddr = addr;
4622+
4623+
if (index != 0) {
4624+
SILValue indexValue = SGF.B.createIntegerLiteral(
4625+
E, SILType::getBuiltinWordType(SGF.getASTContext()), index);
4626+
destAddr = SGF.B.createIndexAddr(E, addr, indexValue,
4627+
/*needsStackProtection=*/ false);
4628+
}
4629+
4630+
// Create a dormant cleanup for the value in case we exit before the
4631+
// full vector has been constructed.
4632+
4633+
CleanupHandle destCleanup = CleanupHandle::invalid();
4634+
if (!eltTL.isTrivial()) {
4635+
destCleanup = SGF.enterDestroyCleanup(destAddr);
4636+
SGF.Cleanups.setCleanupState(destCleanup, CleanupState::Dormant);
4637+
cleanups.push_back(destCleanup);
4638+
}
4639+
4640+
TemporaryInitialization init(destAddr, destCleanup);
4641+
4642+
ArgumentSource(E->getElements()[index])
4643+
.forwardInto(SGF, AbstractionPattern::getOpaque(), &init, eltTL);
4644+
}
4645+
4646+
// Kill the per-element cleanups. The vector will take ownership of them.
4647+
for (auto destCleanup : cleanups)
4648+
SGF.Cleanups.setCleanupState(destCleanup, CleanupState::Dead);
4649+
4650+
SILValue vectorVal;
4651+
4652+
// If the vector is naturally address-only, then we can adopt the stack slot
4653+
// as the value directly.
4654+
if (loweredVectorType.isAddressOnly(SGF.F)) {
4655+
vectorVal = SGF.B.createUncheckedAddrCast(E, alloc, loweredVectorType);
4656+
} else {
4657+
// Otherwise, this vector is loadable. Load it.
4658+
vectorVal = SGF.B.createLoad(E, alloc, LoadOwnershipQualifier::Trivial);
4659+
}
4660+
4661+
auto vectorMV = SGF.emitManagedRValueWithCleanup(vectorVal);
4662+
auto vector = RValue(SGF, E, vectorMV);
4663+
4664+
return scope.popPreservingValue(std::move(vector));
4665+
}
4666+
46034667
RValue RValueEmitter::visitCollectionExpr(CollectionExpr *E, SGFContext C) {
4668+
// Handle 'Vector' literals separately.
4669+
if (E->getType()->isVector()) {
4670+
return emitVectorLiteral(SGF, E, C);
4671+
}
4672+
46044673
auto loc = SILLocation(E);
46054674
ArgumentScope scope(SGF, loc);
46064675

lib/Sema/CSApply.cpp

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3801,23 +3801,29 @@ namespace {
38013801
ArrayExpr *finishArrayExpr(ArrayExpr *expr) {
38023802
Type arrayTy = cs.getType(expr);
38033803
auto &ctx = cs.getASTContext();
3804+
Type elementType;
38043805

3805-
ProtocolDecl *arrayProto = TypeChecker::getProtocol(
3806-
ctx, expr->getLoc(), KnownProtocolKind::ExpressibleByArrayLiteral);
3807-
assert(arrayProto && "type-checked array literal w/o protocol?!");
3806+
if (arrayTy->isVector()) {
3807+
// <let Count: Int, Element>
3808+
elementType = arrayTy->castTo<BoundGenericStructType>()->getGenericArgs()[1];
3809+
} else {
3810+
ProtocolDecl *arrayProto = TypeChecker::getProtocol(
3811+
ctx, expr->getLoc(), KnownProtocolKind::ExpressibleByArrayLiteral);
3812+
assert(arrayProto && "type-checked array literal w/o protocol?!");
38083813

3809-
auto conformance = checkConformance(arrayTy, arrayProto);
3810-
assert(conformance && "Type does not conform to protocol?");
3814+
auto conformance = checkConformance(arrayTy, arrayProto);
3815+
assert(conformance && "Type does not conform to protocol?");
38113816

3812-
DeclName name(ctx, DeclBaseName::createConstructor(),
3813-
{ctx.Id_arrayLiteral});
3814-
ConcreteDeclRef witness =
3815-
conformance.getWitnessByName(arrayTy->getRValueType(), name);
3816-
if (!witness || !isa<AbstractFunctionDecl>(witness.getDecl()))
3817-
return nullptr;
3818-
expr->setInitializer(witness);
3817+
DeclName name(ctx, DeclBaseName::createConstructor(),
3818+
{ctx.Id_arrayLiteral});
3819+
ConcreteDeclRef witness =
3820+
conformance.getWitnessByName(arrayTy->getRValueType(), name);
3821+
if (!witness || !isa<AbstractFunctionDecl>(witness.getDecl()))
3822+
return nullptr;
3823+
expr->setInitializer(witness);
38193824

3820-
auto elementType = expr->getElementType();
3825+
elementType = expr->getElementType();
3826+
}
38213827

38223828
for (unsigned i = 0, n = expr->getNumElements(); i != n; ++i) {
38233829
expr->setElement(

lib/Sema/CSGen.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2131,7 +2131,8 @@ namespace {
21312131
};
21322132

21332133
// If a contextual type exists for this expression, apply it directly.
2134-
if (contextualType && contextualType->isArrayType()) {
2134+
if (contextualType &&
2135+
(contextualType->isArrayType() || contextualType->isVector())) {
21352136
// Now that we know we're actually going to use the type, get the
21362137
// version for use in a constraint.
21372138
contextualType = CS.getContextualType(expr, /*forConstraint=*/true);

lib/Sema/CSSimplify.cpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8540,6 +8540,46 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyConformsToConstraint(
85408540
}
85418541
}
85428542
}
8543+
8544+
auto arrayLiteralProto =
8545+
getASTContext().getProtocol(KnownProtocolKind::ExpressibleByArrayLiteral);
8546+
auto anchor = loc->getAnchor();
8547+
auto arrayLiteral = getAsExpr<ArrayExpr>(anchor);
8548+
8549+
// If we're attempting to bind an array literal to a 'Vector' parameter,
8550+
// then check if the counts are equal and solve.
8551+
if (kind == ConstraintKind::LiteralConformsTo &&
8552+
protocol == arrayLiteralProto &&
8553+
type->isVector() &&
8554+
arrayLiteral) {
8555+
auto vectorTy = type->castTo<BoundGenericStructType>();
8556+
8557+
// <let Count: Int, Element>
8558+
// Attempt to bind the number of elements in the literal with the
8559+
// contextual count. This will diagnose if the literal does not enough
8560+
// or too many elements.
8561+
auto contextualCount = vectorTy->getGenericArgs()[0];
8562+
auto literalCount = IntegerType::get(
8563+
std::to_string(arrayLiteral->getNumElements()),
8564+
/* isNegative */ false,
8565+
vectorTy->getASTContext());
8566+
8567+
// If the counts are already equal, '2' == '2', then we're done.
8568+
if (contextualCount->isEqual(literalCount)) {
8569+
return SolutionKind::Solved;
8570+
}
8571+
8572+
// If our contextual count is not known, e.g., Vector<_, Int> = [1, 2],
8573+
// then just eagerly bind the count to what the literal count is.
8574+
if (contextualCount->isTypeVariableOrMember()) {
8575+
addConstraint(ConstraintKind::Bind, contextualCount, literalCount,
8576+
locator);
8577+
return SolutionKind::Solved;
8578+
}
8579+
8580+
// Otherwise this is an error and the counts aren't equal to each other.
8581+
// We'll make a fix to diagnose it as such.
8582+
}
85438583
} break;
85448584

85458585
default:

lib/Sema/TypeCheckType.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -740,6 +740,9 @@ namespace {
740740
if (secondType->is<IntegerType>())
741741
return true;
742742

743+
if (secondType->is<PlaceholderType>())
744+
return true;
745+
743746
return false;
744747
}
745748

0 commit comments

Comments
 (0)