Skip to content

[AST] Rename isArrayType and split the InlineArray portion #81184

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
May 9, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions include/swift/AST/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -987,9 +987,13 @@ class alignas(1 << TypeAlignInBits) TypeBase
/// type) from `DistributedActor`.
bool isDistributedActor();

/// Determine if the type in question is an Array<T> and, if so, provide the
/// Determine if this type is an Array<T> and, if so, provide the element type
/// of the array.
Type getArrayElementType();

/// Determine if this type is an InlineArray<n, T> and, if so, provide the
/// element type of the array.
Type isArrayType();
Type getInlineArrayElementType();

/// Determines the element type of a known
/// [Autoreleasing]Unsafe[Mutable][Raw]Pointer variant, or returns null if the
Expand Down
29 changes: 21 additions & 8 deletions lib/AST/Type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -829,15 +829,28 @@ CanType CanType::wrapInOptionalTypeImpl(CanType type) {
return type->wrapInOptionalType()->getCanonicalType();
}

Type TypeBase::isArrayType() {
if (auto boundStruct = getAs<BoundGenericStructType>()) {
if (isArray())
return boundStruct->getGenericArgs()[0];
Type TypeBase::getArrayElementType() {
if (!isArray())
return Type();

if (isInlineArray())
return boundStruct->getGenericArgs()[1];
}
return Type();
if (!is<BoundGenericStructType>())
return Type();

// Array<T>
auto boundStruct = castTo<BoundGenericStructType>();
return boundStruct->getGenericArgs()[0];
}

Type TypeBase::getInlineArrayElementType() {
if (!isInlineArray())
return Type();

if (!is<BoundGenericStructType>())
return Type();

// InlineArray<n, T>
auto boundStruct = castTo<BoundGenericStructType>();
return boundStruct->getGenericArgs()[1];
}

Type TypeBase::getAnyPointerElementType(PointerTypeKind &PTK) {
Expand Down
2 changes: 1 addition & 1 deletion lib/SILGen/SILGenExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6680,7 +6680,7 @@ static void diagnoseImplicitRawConversion(Type sourceTy, Type pointerTy,
// Array conversion does not always go down the ArrayConverter
// path. Recognize the Array source type here both for ArrayToPointer and
// InoutToPointer cases and diagnose on the element type.
Type eltTy = sourceTy->isArrayType();
Type eltTy = sourceTy->getArrayElementType();
if (!eltTy)
eltTy = sourceTy;

Expand Down
2 changes: 1 addition & 1 deletion lib/Sema/CSApply.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6891,7 +6891,7 @@ bool ExprRewriter::peepholeCollectionUpcast(Expr *expr, Type toType,

// Array literals.
if (auto arrayLiteral = dyn_cast<ArrayExpr>(expr)) {
if (Type elementType = toType->isArrayType()) {
if (auto elementType = toType->getArrayElementType()) {
peepholeArrayUpcast(arrayLiteral, toType, bridged, elementType, locator);
return true;
}
Expand Down
2 changes: 1 addition & 1 deletion lib/Sema/CSBindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1385,7 +1385,7 @@ static bool hasConversions(Type type) {
return true;

if (auto *structTy = type->getAs<BoundGenericStructType>()) {
if (auto eltTy = structTy->isArrayType()) {
if (auto eltTy = structTy->getArrayElementType()) {
return hasConversions(eltTy);
} else if (auto pair = ConstraintSystem::isDictionaryType(structTy)) {
return hasConversions(pair->second);
Expand Down
2 changes: 1 addition & 1 deletion lib/Sema/CSDiagnostics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1979,7 +1979,7 @@ bool RValueTreatedAsLValueFailure::diagnoseAsError() {
auto argType = getType(inoutExpr)->getWithoutSpecifierType();

PointerTypeKind ptr;
if (argType->isArrayType() && paramType->getAnyPointerElementType(ptr)
if (argType->isArray() && paramType->getAnyPointerElementType(ptr)
&& (ptr == PTK_UnsafePointer || ptr == PTK_UnsafeRawPointer)) {
emitDiagnosticAt(inoutExpr->getLoc(),
diag::extra_address_of_unsafepointer, paramType)
Expand Down
4 changes: 2 additions & 2 deletions lib/Sema/CSFix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ TreatArrayLiteralAsDictionary *
TreatArrayLiteralAsDictionary::attempt(ConstraintSystem &cs, Type dictionaryTy,
Type arrayTy,
ConstraintLocator *locator) {
if (!arrayTy->isArrayType())
if (!arrayTy->isArray())
return nullptr;

// Determine the ArrayExpr from the locator.
Expand Down Expand Up @@ -1814,7 +1814,7 @@ ExpandArrayIntoVarargs::attempt(ConstraintSystem &cs, Type argType,
if (!(argLoc && argLoc->getParameterFlags().isVariadic()))
return nullptr;

auto elementType = argType->isArrayType();
auto elementType = argType->getArrayElementType();
if (!elementType)
return nullptr;

Expand Down
23 changes: 19 additions & 4 deletions lib/Sema/CSGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1085,7 +1085,12 @@ namespace {
baseObjTy = baseObjTy->getWithoutSpecifierType();
}

if (auto elementTy = baseObjTy->isArrayType()) {
auto elementTy = baseObjTy->getArrayElementType();

if (!elementTy)
elementTy = baseObjTy->getInlineArrayElementType();

if (elementTy) {

if (auto arraySliceTy =
dyn_cast<ArraySliceType>(baseObjTy.getPointer())) {
Expand Down Expand Up @@ -2151,18 +2156,28 @@ namespace {
};

// If a contextual type exists for this expression, apply it directly.
if (contextualType && contextualType->isArrayType()) {
if (contextualType &&
(contextualType->getArrayElementType() ||
contextualType->getInlineArrayElementType())) {
// Now that we know we're actually going to use the type, get the
// version for use in a constraint.
contextualType = CS.getContextualType(expr, /*forConstraint=*/true);
// FIXME: This is the wrong place to be opening the opaque type.
contextualType = CS.openOpaqueType(
contextualType, contextualPurpose, locator, /*ownerDecl=*/nullptr);
Type arrayElementType = contextualType->isArrayType();

Type eltType;

if (contextualType->isArray())
eltType = contextualType->getArrayElementType();

if (contextualType->isInlineArray())
eltType = contextualType->getInlineArrayElementType();

CS.addConstraint(ConstraintKind::LiteralConformsTo, contextualType,
arrayProto->getDeclaredInterfaceType(),
locator);
joinElementTypes(arrayElementType);
joinElementTypes(eltType);
return contextualType;
}

Expand Down
28 changes: 14 additions & 14 deletions lib/Sema/CSSimplify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6018,7 +6018,7 @@ bool ConstraintSystem::repairFailures(
// ```
if (rhs->isKnownStdlibCollectionType()) {
std::function<Type(Type)> getArrayOrSetType = [&](Type type) -> Type {
if (auto eltTy = type->isArrayType())
if (auto eltTy = type->getArrayElementType())
return getArrayOrSetType(eltTy);

if (auto eltTy = isSetType(type))
Expand Down Expand Up @@ -7992,7 +7992,7 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
if (inoutBaseType->isTypeVariableOrMember())
return formUnsolvedResult();

auto baseIsArray = inoutBaseType->isArrayType();
auto baseIsArray = inoutBaseType->isArray();

if (baseIsArray)
conversionsOrFixes.push_back(
Expand Down Expand Up @@ -8061,7 +8061,7 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
if (pointerKind == PTK_UnsafePointer
|| pointerKind == PTK_UnsafeRawPointer) {
if (!isAutoClosureArgument) {
if (type1->isArrayType()) {
if (type1->isArray()) {
conversionsOrFixes.push_back(
ConversionRestrictionKind::ArrayToPointer);

Expand Down Expand Up @@ -9263,7 +9263,7 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyTransitivelyConformsTo(
}

// Array<T> -> Unsafe{Raw}Pointer<T>
if (auto elt = resolvedTy->isArrayType()) {
if (auto elt = resolvedTy->getArrayElementType()) {
typesToCheck.push_back(getPointerFor(PTK_UnsafePointer, elt));
typesToCheck.push_back(getPointerFor(PTK_UnsafeRawPointer, elt));
}
Expand Down Expand Up @@ -9294,7 +9294,7 @@ static CheckedCastKind getCheckedCastKind(ConstraintSystem *cs,
Type fromType,
Type toType) {
// Array downcasts are handled specially.
if (fromType->isArrayType() && toType->isArrayType()) {
if (fromType->isArray() && toType->isArray()) {
return CheckedCastKind::ArrayDowncast;
}

Expand Down Expand Up @@ -9558,8 +9558,8 @@ ConstraintSystem::simplifyCheckedCastConstraint(
auto kind = getCheckedCastKind(this, fromType, toType);
switch (kind) {
case CheckedCastKind::ArrayDowncast: {
auto fromBaseType = fromType->isArrayType();
auto toBaseType = toType->isArrayType();
auto fromBaseType = fromType->getArrayElementType();
auto toBaseType = toType->getArrayElementType();

auto elementLocator =
locator.withPathElement(LocatorPathElt::GenericArgument(0));
Expand Down Expand Up @@ -12558,8 +12558,8 @@ ConstraintSystem::simplifyBridgingConstraint(Type type1,
};

// Bridging the elements of an array.
if (auto fromElement = unwrappedFromType->isArrayType()) {
if (auto toElement = unwrappedToType->isArrayType()) {
if (auto fromElement = unwrappedFromType->getArrayElementType()) {
if (auto toElement = unwrappedToType->getArrayElementType()) {
countOptionalInjections();
auto result = simplifyBridgingConstraint(
fromElement, toElement, subflags,
Expand Down Expand Up @@ -14838,7 +14838,7 @@ ConstraintSystem::simplifyRestrictedConstraintImpl(

auto t2 = type2->getDesugaredType();

auto baseType1 = getFixedTypeRecursive(obj1->isArrayType(), false);
auto baseType1 = getFixedTypeRecursive(obj1->getArrayElementType(), false);
auto ptr2 = getBaseTypeForPointer(t2);

increaseScore(SK_ValueToOptional, locator, ptr2.getInt());
Expand Down Expand Up @@ -14941,7 +14941,7 @@ ConstraintSystem::simplifyRestrictedConstraintImpl(

increaseScore(SK_ValueToPointerConversion, locator);

type1 = getFixedTypeRecursive(type1->getInOutObjectType()->isArrayType(),
type1 = getFixedTypeRecursive(type1->getInOutObjectType()->getArrayElementType(),
/*wantRValue=*/false);
LLVM_FALLTHROUGH;
}
Expand Down Expand Up @@ -14977,8 +14977,8 @@ ConstraintSystem::simplifyRestrictedConstraintImpl(

// T < U or T is bridged to V where V < U ===> Array<T> <c Array<U>
case ConversionRestrictionKind::ArrayUpcast: {
Type baseType1 = type1->isArrayType();
Type baseType2 = type2->isArrayType();
Type baseType1 = type1->getArrayElementType();
Type baseType2 = type2->getArrayElementType();

increaseScore(SK_CollectionUpcastConversion, locator);
return matchTypes(baseType1,
Expand Down Expand Up @@ -15774,7 +15774,7 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
auto dictionaryKeyTy = DependentMemberType::get(valueBaseTy, keyAssocTy);

// Extract the array element type.
auto elemTy = type1->isArrayType();
auto elemTy = type1->getArrayElementType();

ConstraintLocator *elemLoc = getConstraintLocator(AE->getElement(0));
ConstraintKind kind = isDictionaryType(dictTy)
Expand Down
2 changes: 1 addition & 1 deletion lib/Sema/ConstraintSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1692,7 +1692,7 @@ struct TypeSimplifier {
auto elementAssocTy = arrayProto->getAssociatedTypeMembers()[0];

if (proto == arrayProto && assocType == elementAssocTy) {
return lookupBaseType->isArrayType();
return lookupBaseType->getInlineArrayElementType();
}
}

Expand Down
4 changes: 2 additions & 2 deletions lib/Sema/TypeCheckConstraints.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1860,8 +1860,8 @@ TypeChecker::typeCheckCheckedCast(Type fromType, Type toType,
};

// Check for casts between specific concrete types that cannot succeed.
if (auto toElementType = toType->isArrayType()) {
if (auto fromElementType = fromType->isArrayType()) {
if (auto toElementType = toType->getArrayElementType()) {
if (auto fromElementType = fromType->getArrayElementType()) {
return checkElementCast(fromElementType, toElementType,
CheckedCastKind::ArrayDowncast);
}
Expand Down
8 changes: 8 additions & 0 deletions test/Sema/inlinearray.swift
Original file line number Diff line number Diff line change
Expand Up @@ -153,3 +153,11 @@ func testMismatches(_ x: [3 x Int], _ y: InlineArray<3, Int>) {
let _: [3 x String] = y // expected-error {{cannot assign value of type 'InlineArray<3, Int>' to type '[3 x String]'}}
// expected-note@-1 {{arguments to generic parameter 'Element' ('Int' and 'String') are expected to be equal}}
}

func testPointerConversion() {
var inlineArray = InlineArray<1, Int>(repeating: 0)
acceptPointer(&inlineArray) // expected-error {{cannot convert value of type 'UnsafeMutablePointer<InlineArray<1, Int>>' to expected argument type 'UnsafeMutablePointer<Int>'}}
// expected-note@-1 {{arguments to generic parameter 'Pointee' ('InlineArray<1, Int>' and 'Int') are expected to be equal}}
}

func acceptPointer(_ pointer: UnsafeMutablePointer<Int>) {}
2 changes: 1 addition & 1 deletion unittests/Sema/PlaceholderTypeInferenceTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ TEST_F(SemaTest, TestPlaceholderInferenceForArrayLiteral) {

auto &solution = solutions[0];

auto eltTy = solution.simplifyType(solution.getType(arrayExpr))->isArrayType();
auto eltTy = solution.simplifyType(solution.getType(arrayExpr))->getArrayElementType();
ASSERT_TRUE(eltTy);
ASSERT_TRUE(eltTy->is<StructType>());
ASSERT_EQ(eltTy->getAs<StructType>()->getDecl(), intTypeDecl);
Expand Down