diff --git a/include/swift/AST/Types.h b/include/swift/AST/Types.h index a14a33ea13c..dc16ee631d5 100644 --- a/include/swift/AST/Types.h +++ b/include/swift/AST/Types.h @@ -987,9 +987,13 @@ public: /// type) from `DistributedActor`. bool isDistributedActor(); - /// Determine if the type in question is an Array and, if so, provide the + /// Determine if this type is an Array and, if so, provide the element type + /// of the array. + Type getArrayElementType(); + + /// Determine if this type is an InlineArray 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 diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index a2b09b39051..d78d66d68f6 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -829,15 +829,28 @@ CanType CanType::wrapInOptionalTypeImpl(CanType type) { return type->wrapInOptionalType()->getCanonicalType(); } -Type TypeBase::isArrayType() { - if (auto boundStruct = getAs()) { - if (isArray()) - return boundStruct->getGenericArgs()[0]; +Type TypeBase::getArrayElementType() { + if (!isArray()) + return Type(); - if (isInlineArray()) - return boundStruct->getGenericArgs()[1]; - } - return Type(); + if (!is()) + return Type(); + + // Array + auto boundStruct = castTo(); + return boundStruct->getGenericArgs()[0]; +} + +Type TypeBase::getInlineArrayElementType() { + if (!isInlineArray()) + return Type(); + + if (!is()) + return Type(); + + // InlineArray + auto boundStruct = castTo(); + return boundStruct->getGenericArgs()[1]; } Type TypeBase::getAnyPointerElementType(PointerTypeKind &PTK) { diff --git a/lib/SILGen/SILGenExpr.cpp b/lib/SILGen/SILGenExpr.cpp index 9c292bce4c9..ca38704b70c 100644 --- a/lib/SILGen/SILGenExpr.cpp +++ b/lib/SILGen/SILGenExpr.cpp @@ -6673,7 +6673,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; diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index 73f771f7c19..c2228bbd667 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -6906,7 +6906,7 @@ bool ExprRewriter::peepholeCollectionUpcast(Expr *expr, Type toType, // Array literals. if (auto arrayLiteral = dyn_cast(expr)) { - if (Type elementType = toType->isArrayType()) { + if (auto elementType = toType->getArrayElementType()) { peepholeArrayUpcast(arrayLiteral, toType, bridged, elementType, locator); return true; } diff --git a/lib/Sema/CSBindings.cpp b/lib/Sema/CSBindings.cpp index 027d7e50b18..807cdec5f30 100644 --- a/lib/Sema/CSBindings.cpp +++ b/lib/Sema/CSBindings.cpp @@ -1385,7 +1385,7 @@ static bool hasConversions(Type type) { return true; if (auto *structTy = type->getAs()) { - if (auto eltTy = structTy->isArrayType()) { + if (auto eltTy = structTy->getArrayElementType()) { return hasConversions(eltTy); } else if (auto pair = ConstraintSystem::isDictionaryType(structTy)) { return hasConversions(pair->second); diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index e021ce40f7a..acc0f261b3d 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -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) diff --git a/lib/Sema/CSFix.cpp b/lib/Sema/CSFix.cpp index 02eb015d26a..96e211a1775 100644 --- a/lib/Sema/CSFix.cpp +++ b/lib/Sema/CSFix.cpp @@ -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. @@ -1834,7 +1834,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; diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index 61427ffcfdf..69f17ad3dac 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -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(baseObjTy.getPointer())) { @@ -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; } diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index fd5e6b9842a..0bf0bbc04d5 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -6018,7 +6018,7 @@ bool ConstraintSystem::repairFailures( // ``` if (rhs->isKnownStdlibCollectionType()) { std::function getArrayOrSetType = [&](Type type) -> Type { - if (auto eltTy = type->isArrayType()) + if (auto eltTy = type->getArrayElementType()) return getArrayOrSetType(eltTy); if (auto eltTy = isSetType(type)) @@ -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( @@ -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); @@ -9263,7 +9263,7 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyTransitivelyConformsTo( } // Array -> Unsafe{Raw}Pointer - if (auto elt = resolvedTy->isArrayType()) { + if (auto elt = resolvedTy->getArrayElementType()) { typesToCheck.push_back(getPointerFor(PTK_UnsafePointer, elt)); typesToCheck.push_back(getPointerFor(PTK_UnsafeRawPointer, elt)); } @@ -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; } @@ -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)); @@ -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, @@ -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()); @@ -14941,7 +14941,7 @@ ConstraintSystem::simplifyRestrictedConstraintImpl( increaseScore(SK_ValueToPointerConversion, locator); - type1 = getFixedTypeRecursive(type1->getInOutObjectType()->isArrayType(), + type1 = getFixedTypeRecursive(type1->getInOutObjectType()->getArrayElementType(), /*wantRValue=*/false); LLVM_FALLTHROUGH; } @@ -14977,8 +14977,8 @@ ConstraintSystem::simplifyRestrictedConstraintImpl( // T < U or T is bridged to V where V < U ===> Array 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, @@ -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) diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index 7aea6720aaf..6b55b6746cb 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -1692,7 +1692,7 @@ struct TypeSimplifier { auto elementAssocTy = arrayProto->getAssociatedTypeMembers()[0]; if (proto == arrayProto && assocType == elementAssocTy) { - return lookupBaseType->isArrayType(); + return lookupBaseType->getInlineArrayElementType(); } } diff --git a/lib/Sema/TypeCheckConstraints.cpp b/lib/Sema/TypeCheckConstraints.cpp index 7a115626435..36f3790d719 100644 --- a/lib/Sema/TypeCheckConstraints.cpp +++ b/lib/Sema/TypeCheckConstraints.cpp @@ -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); } diff --git a/test/Sema/inlinearray.swift b/test/Sema/inlinearray.swift index 19d76644022..70751449ba3 100644 --- a/test/Sema/inlinearray.swift +++ b/test/Sema/inlinearray.swift @@ -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>' to expected argument type 'UnsafeMutablePointer'}} + // expected-note@-1 {{arguments to generic parameter 'Pointee' ('InlineArray<1, Int>' and 'Int') are expected to be equal}} +} + +func acceptPointer(_ pointer: UnsafeMutablePointer) {} diff --git a/unittests/Sema/PlaceholderTypeInferenceTests.cpp b/unittests/Sema/PlaceholderTypeInferenceTests.cpp index 62e4a4d1982..c43c4d2a692 100644 --- a/unittests/Sema/PlaceholderTypeInferenceTests.cpp +++ b/unittests/Sema/PlaceholderTypeInferenceTests.cpp @@ -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()); ASSERT_EQ(eltTy->getAs()->getDecl(), intTypeDecl);