Skip to content

Commit 61702fb

Browse files
committed
Implement Vector literals
1 parent f867d0b commit 61702fb

File tree

15 files changed

+377
-19
lines changed

15 files changed

+377
-19
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8175,6 +8175,13 @@ ERROR(availability_value_generic_type_only_version_newer, none,
81758175
ERROR(invalid_value_for_type_same_type,none,
81768176
"cannot constrain type parameter %0 to be integer %1", (Type, Type))
81778177

8178+
//===----------------------------------------------------------------------===//
8179+
// MARK: Vector
8180+
//===----------------------------------------------------------------------===//
8181+
8182+
ERROR(vector_literal_incorrect_count,none,
8183+
"expected %0 elements in vector literal, but got %1", (Type, Type))
8184+
81788185
//===----------------------------------------------------------------------===//
81798186
// MARK: @abi Attribute
81808187
//===----------------------------------------------------------------------===//

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

include/swift/Sema/CSFix.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -483,6 +483,10 @@ enum class FixKind : uint8_t {
483483
/// sending result, but is passed a function typed parameter without a sending
484484
/// result.
485485
AllowSendingMismatch,
486+
487+
/// Ignore when a 'Vector' literal has mismatched number of elements to the
488+
/// type it's attempting to bind to.
489+
AllowVectorLiteralCountMismatch,
486490
};
487491

488492
class ConstraintFix {
@@ -3837,6 +3841,30 @@ class IgnoreKeyPathSubscriptIndexMismatch final : public ConstraintFix {
38373841
}
38383842
};
38393843

3844+
class AllowVectorLiteralCountMismatch final : public ConstraintFix {
3845+
Type lhsCount, rhsCount;
3846+
3847+
AllowVectorLiteralCountMismatch(ConstraintSystem &cs, Type lhsCount,
3848+
Type rhsCount, ConstraintLocator *locator)
3849+
: ConstraintFix(cs, FixKind::AllowVectorLiteralCountMismatch, locator),
3850+
lhsCount(lhsCount), rhsCount(rhsCount) {}
3851+
3852+
public:
3853+
std::string getName() const override {
3854+
return "allow vector literal count mismatch";
3855+
}
3856+
3857+
bool diagnose(const Solution &solution, bool asNote = false) const override;
3858+
3859+
static AllowVectorLiteralCountMismatch *
3860+
create(ConstraintSystem &cs, Type lhsCount, Type rhsCount,
3861+
ConstraintLocator *locator);
3862+
3863+
static bool classof(const ConstraintFix *fix) {
3864+
return fix->getKind() == FixKind::AllowVectorLiteralCountMismatch;
3865+
}
3866+
};
3867+
38403868
} // end namespace constraints
38413869
} // end namespace swift
38423870

lib/AST/Type.cpp

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

809809
Type TypeBase::isArrayType() {
810810
if (auto boundStruct = getAs<BoundGenericStructType>()) {
811-
if (boundStruct->getDecl() == getASTContext().getArrayDecl())
811+
if (isArray())
812812
return boundStruct->getGenericArgs()[0];
813+
814+
if (isVector())
815+
return boundStruct->getGenericArgs()[1];
813816
}
814817
return Type();
815818
}

lib/SILGen/SILGenExpr.cpp

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

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

lib/Sema/CSApply.cpp

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3792,23 +3792,29 @@ namespace {
37923792
/// "Finish" an array expression by filling in the semantic expression.
37933793
ArrayExpr *finishArrayExpr(ArrayExpr *expr) {
37943794
Type arrayTy = cs.getType(expr);
3795+
Type elementType;
37953796

3796-
ProtocolDecl *arrayProto = TypeChecker::getProtocol(
3797-
ctx, expr->getLoc(), KnownProtocolKind::ExpressibleByArrayLiteral);
3798-
assert(arrayProto && "type-checked array literal w/o protocol?!");
3797+
if (arrayTy->isVector()) {
3798+
// <let Count: Int, Element>
3799+
elementType = arrayTy->castTo<BoundGenericStructType>()->getGenericArgs()[1];
3800+
} else {
3801+
ProtocolDecl *arrayProto = TypeChecker::getProtocol(
3802+
ctx, expr->getLoc(), KnownProtocolKind::ExpressibleByArrayLiteral);
3803+
assert(arrayProto && "type-checked array literal w/o protocol?!");
37993804

3800-
auto conformance = checkConformance(arrayTy, arrayProto);
3801-
assert(conformance && "Type does not conform to protocol?");
3805+
auto conformance = checkConformance(arrayTy, arrayProto);
3806+
assert(conformance && "Type does not conform to protocol?");
38023807

3803-
DeclName name(ctx, DeclBaseName::createConstructor(),
3804-
{ctx.Id_arrayLiteral});
3805-
ConcreteDeclRef witness =
3806-
conformance.getWitnessByName(arrayTy->getRValueType(), name);
3807-
if (!witness || !isa<AbstractFunctionDecl>(witness.getDecl()))
3808-
return nullptr;
3809-
expr->setInitializer(witness);
3808+
DeclName name(ctx, DeclBaseName::createConstructor(),
3809+
{ctx.Id_arrayLiteral});
3810+
ConcreteDeclRef witness =
3811+
conformance.getWitnessByName(arrayTy->getRValueType(), name);
3812+
if (!witness || !isa<AbstractFunctionDecl>(witness.getDecl()))
3813+
return nullptr;
3814+
expr->setInitializer(witness);
38103815

3811-
auto elementType = expr->getElementType();
3816+
elementType = expr->getElementType();
3817+
}
38123818

38133819
for (unsigned i = 0, n = expr->getNumElements(); i != n; ++i) {
38143820
expr->setElement(
@@ -6792,7 +6798,7 @@ Expr *ExprRewriter::buildCollectionUpcastExpr(
67926798
bridged, locator, 0);
67936799

67946800
// For single-parameter collections, form the upcast.
6795-
if (toType->isArrayType() || ConstraintSystem::isSetType(toType)) {
6801+
if (toType->isArray() || ConstraintSystem::isSetType(toType)) {
67966802
return cs.cacheType(
67976803
new (ctx) CollectionUpcastConversionExpr(expr, toType, {}, conv));
67986804
}
@@ -6817,7 +6823,7 @@ Expr *ExprRewriter::buildObjCBridgeExpr(Expr *expr, Type toType,
68176823

68186824
// Bridged collection casts always succeed, so we treat them as
68196825
// collection "upcasts".
6820-
if ((fromType->isArrayType() && toType->isArrayType())
6826+
if ((fromType->isArray() && toType->isArray())
68216827
|| (ConstraintSystem::isDictionaryType(fromType)
68226828
&& ConstraintSystem::isDictionaryType(toType))
68236829
|| (ConstraintSystem::isSetType(fromType)

lib/Sema/CSDiagnostics.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9571,3 +9571,8 @@ bool InvalidTypeAsKeyPathSubscriptIndex::diagnoseAsError() {
95719571
emitDiagnostic(diag::cannot_convert_type_to_keypath_subscript_index, ArgType);
95729572
return true;
95739573
}
9574+
9575+
bool IncorrectVectorLiteralCount::diagnoseAsError() {
9576+
emitDiagnostic(diag::vector_literal_incorrect_count, lhsCount, rhsCount);
9577+
return true;
9578+
}

lib/Sema/CSDiagnostics.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3234,6 +3234,24 @@ class InvalidTypeAsKeyPathSubscriptIndex final : public FailureDiagnostic {
32343234
bool diagnoseAsError() override;
32353235
};
32363236

3237+
/// Diagnose when a vector literal has an incorrect number of elements for the
3238+
/// contextual vector type it's initializing.
3239+
///
3240+
/// \code
3241+
/// let x: Vector<4, Int> = [1, 2] // expected '4' elements but got '2'
3242+
/// \endcode
3243+
class IncorrectVectorLiteralCount final : public FailureDiagnostic {
3244+
Type lhsCount, rhsCount;
3245+
3246+
public:
3247+
IncorrectVectorLiteralCount(const Solution &solution, Type lhsCount,
3248+
Type rhsCount, ConstraintLocator *locator)
3249+
: FailureDiagnostic(solution, locator), lhsCount(resolveType(lhsCount)),
3250+
rhsCount(resolveType(rhsCount)) {}
3251+
3252+
bool diagnoseAsError() override;
3253+
};
3254+
32373255
} // end namespace constraints
32383256
} // end namespace swift
32393257

lib/Sema/CSFix.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2722,3 +2722,17 @@ IgnoreKeyPathSubscriptIndexMismatch::create(ConstraintSystem &cs, Type argType,
27222722
return new (cs.getAllocator())
27232723
IgnoreKeyPathSubscriptIndexMismatch(cs, argType, locator);
27242724
}
2725+
2726+
AllowVectorLiteralCountMismatch *
2727+
AllowVectorLiteralCountMismatch::create(ConstraintSystem &cs, Type lhsCount,
2728+
Type rhsCount,
2729+
ConstraintLocator *locator) {
2730+
return new (cs.getAllocator())
2731+
AllowVectorLiteralCountMismatch(cs, lhsCount, rhsCount, locator);
2732+
}
2733+
2734+
bool AllowVectorLiteralCountMismatch::diagnose(const Solution &solution,
2735+
bool asNote) const {
2736+
IncorrectVectorLiteralCount failure(solution, lhsCount, rhsCount, getLocator());
2737+
return failure.diagnose(asNote);
2738+
}

lib/Sema/CSGen.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,7 @@ namespace {
333333
baseObjTy = baseObjTy->getWithoutSpecifierType();
334334
}
335335

336-
if (baseObjTy->isArrayType()) {
336+
if (auto elementTy = baseObjTy->isArrayType()) {
337337

338338
if (auto arraySliceTy =
339339
dyn_cast<ArraySliceType>(baseObjTy.getPointer())) {
@@ -343,7 +343,7 @@ namespace {
343343
if (argList->isUnlabeledUnary() &&
344344
isa<IntegerLiteralExpr>(argList->getExpr(0))) {
345345

346-
outputTy = baseObjTy->getAs<BoundGenericType>()->getGenericArgs()[0];
346+
outputTy = elementTy;
347347

348348
if (isLValueBase)
349349
outputTy = LValueType::get(outputTy);

0 commit comments

Comments
 (0)