diff --git a/docs/ABI/Mangling.rst b/docs/ABI/Mangling.rst index 04be4c0e201af..2dcdba7a80658 100644 --- a/docs/ABI/Mangling.rst +++ b/docs/ABI/Mangling.rst @@ -954,6 +954,7 @@ productions: type ::= base-type "XSq" // sugared Optional type type ::= base-type "XSa" // sugared Array type type ::= key-type value-type "XSD" // sugared Dictionary type + type ::= count-type element-type "XSA" // sugared InlineArray type Generics ~~~~~~~~ diff --git a/include/swift/AST/ASTBridging.h b/include/swift/AST/ASTBridging.h index 3a31cee12ab29..be5331dc56454 100644 --- a/include/swift/AST/ASTBridging.h +++ b/include/swift/AST/ASTBridging.h @@ -2702,6 +2702,11 @@ BridgedImplicitlyUnwrappedOptionalTypeRepr_createParsed( BridgedASTContext cContext, BridgedTypeRepr base, BridgedSourceLoc cExclamationLoc); +SWIFT_NAME("BridgedInlineArrayTypeRepr.createParsed(_:count:element:brackets:)") +BridgedInlineArrayTypeRepr BridgedInlineArrayTypeRepr_createParsed( + BridgedASTContext cContext, BridgedTypeRepr cCountType, + BridgedTypeRepr cElementType, BridgedSourceRange cBracketsRange); + SWIFT_NAME("BridgedInverseTypeRepr.createParsed(_:tildeLoc:constraint:)") BridgedInverseTypeRepr BridgedInverseTypeRepr_createParsed(BridgedASTContext cContext, diff --git a/include/swift/AST/ASTDemangler.h b/include/swift/AST/ASTDemangler.h index 5f94702275de3..702072ddb3c83 100644 --- a/include/swift/AST/ASTDemangler.h +++ b/include/swift/AST/ASTDemangler.h @@ -248,6 +248,8 @@ class ASTBuilder { Type createArrayType(Type base); + Type createInlineArrayType(Type count, Type element); + Type createDictionaryType(Type key, Type value); Type createIntegerType(intptr_t value); diff --git a/include/swift/AST/DiagnosticsParse.def b/include/swift/AST/DiagnosticsParse.def index f13bc9ab9a3fe..b4f3be3adb315 100644 --- a/include/swift/AST/DiagnosticsParse.def +++ b/include/swift/AST/DiagnosticsParse.def @@ -878,6 +878,10 @@ NOTE(subscript_array_element_fix_it_add_comma, none, "add a separator between " NOTE(subscript_array_element_fix_it_remove_space, none, "remove the space between the elements to silence this warning", ()) +// Inline Array +ERROR(expected_rsquare_inline_array,none, + "expected ']' in inline array type", ()) + // Tuple Types ERROR(expected_rparen_tuple_type_list,none, "expected ')' at end of tuple list", ()) diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 13fe9fe3101e7..3915a90914509 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -6069,7 +6069,7 @@ NOTE(note_recursive_enum_case_here,none, ERROR(sugar_type_not_found,none, "broken standard library: cannot find " - "%select{Array|Optional|ImplicitlyUnwrappedOptional|Dictionary|" + "%select{Array|Optional|InlineArray|Dictionary|" "Error}0 type", (unsigned)) ERROR(optional_intrinsics_not_found,none, "broken standard library: cannot find intrinsic operations on " @@ -8334,6 +8334,9 @@ ERROR(invalid_value_for_type_same_type,none, ERROR(inlinearray_literal_incorrect_count,none, "expected %0 elements in inline array literal, but got %1", (Type, Type)) +ERROR(inline_array_type_backwards,none, + "element count must precede inline array element type", ()) + //===----------------------------------------------------------------------===// // MARK: @abi Attribute //===----------------------------------------------------------------------===// diff --git a/include/swift/AST/PrintOptions.h b/include/swift/AST/PrintOptions.h index 392aefeeea347..8c2773f282e71 100644 --- a/include/swift/AST/PrintOptions.h +++ b/include/swift/AST/PrintOptions.h @@ -590,6 +590,10 @@ struct PrintOptions { /// Whether to always desugar array types from `[base_type]` to `Array` bool AlwaysDesugarArraySliceTypes = false; + /// Whether to always desugar inline array types from + /// `[ x ]` to `InlineArray` + bool AlwaysDesugarInlineArrayTypes = false; + /// Whether to always desugar dictionary types /// from `[key_type:value_type]` to `Dictionary` bool AlwaysDesugarDictionaryTypes = false; diff --git a/include/swift/AST/TypeNodes.def b/include/swift/AST/TypeNodes.def index d71c5c40d4f22..5ae2e5c658401 100644 --- a/include/swift/AST/TypeNodes.def +++ b/include/swift/AST/TypeNodes.def @@ -217,6 +217,7 @@ ABSTRACT_SUGARED_TYPE(Sugar, Type) SUGARED_TYPE(Optional, UnarySyntaxSugarType) SUGARED_TYPE(VariadicSequence, UnarySyntaxSugarType) TYPE_RANGE(UnarySyntaxSugar, ArraySlice, VariadicSequence) + SUGARED_TYPE(InlineArray, SyntaxSugarType) SUGARED_TYPE(Dictionary, SyntaxSugarType) TYPE_RANGE(SyntaxSugar, ArraySlice, Dictionary) TYPE_RANGE(Sugar, TypeAlias, Dictionary) diff --git a/include/swift/AST/TypeRepr.h b/include/swift/AST/TypeRepr.h index 9db22a1ac1fe2..9f34e84f07e9c 100644 --- a/include/swift/AST/TypeRepr.h +++ b/include/swift/AST/TypeRepr.h @@ -641,6 +641,35 @@ class ArrayTypeRepr : public TypeRepr { friend class TypeRepr; }; +/// An InlineArray type e.g `[2 x Foo]`, sugar for `InlineArray<2, Foo>`. +class InlineArrayTypeRepr : public TypeRepr { + TypeRepr *Count; + TypeRepr *Element; + SourceRange Brackets; + + InlineArrayTypeRepr(TypeRepr *count, TypeRepr *element, SourceRange brackets) + : TypeRepr(TypeReprKind::InlineArray), Count(count), Element(element), + Brackets(brackets) {} + +public: + static InlineArrayTypeRepr *create(ASTContext &ctx, TypeRepr *count, + TypeRepr *element, SourceRange brackets); + + TypeRepr *getCount() const { return Count; } + TypeRepr *getElement() const { return Element; } + SourceRange getBrackets() const { return Brackets; } + + static bool classof(const TypeRepr *T) { + return T->getKind() == TypeReprKind::InlineArray; + } + +private: + SourceLoc getStartLocImpl() const { return Brackets.Start; } + SourceLoc getEndLocImpl() const { return Brackets.End; } + void printImpl(ASTPrinter &Printer, const PrintOptions &Opts) const; + friend class TypeRepr; +}; + /// A dictionary type. /// \code /// [K : V] @@ -1626,6 +1655,7 @@ inline bool TypeRepr::isSimple() const { case TypeReprKind::Fixed: case TypeReprKind::Self: case TypeReprKind::Array: + case TypeReprKind::InlineArray: case TypeReprKind::SILBox: case TypeReprKind::Isolated: case TypeReprKind::Sending: diff --git a/include/swift/AST/TypeReprNodes.def b/include/swift/AST/TypeReprNodes.def index fa1999791ab61..babd74c2b7714 100644 --- a/include/swift/AST/TypeReprNodes.def +++ b/include/swift/AST/TypeReprNodes.def @@ -49,6 +49,7 @@ ABSTRACT_TYPEREPR(DeclRef, TypeRepr) TYPEREPR(UnqualifiedIdent, DeclRefTypeRepr) TYPEREPR(QualifiedIdent, DeclRefTypeRepr) TYPEREPR(Function, TypeRepr) +TYPEREPR(InlineArray, TypeRepr) TYPEREPR(Array, TypeRepr) TYPEREPR(Dictionary, TypeRepr) TYPEREPR(Optional, TypeRepr) diff --git a/include/swift/AST/TypeTransform.h b/include/swift/AST/TypeTransform.h index 4acdf4888217f..8662e15be487c 100644 --- a/include/swift/AST/TypeTransform.h +++ b/include/swift/AST/TypeTransform.h @@ -894,6 +894,25 @@ case TypeKind::Id: return ArraySliceType::get(baseTy); } + case TypeKind::InlineArray: { + auto ty = cast(base); + auto countTy = doIt(ty->getCountType(), TypePosition::Invariant); + if (!countTy) + return Type(); + + // Currently the element type is invariant for InlineArray. + // FIXME: Should we allow covariance? + auto eltTy = doIt(ty->getElementType(), TypePosition::Invariant); + if (!eltTy) + return Type(); + + if (countTy.getPointer() == ty->getCountType().getPointer() && + eltTy.getPointer() == ty->getElementType().getPointer()) + return t; + + return InlineArrayType::get(countTy, eltTy); + } + case TypeKind::Optional: { auto optional = cast(base); auto baseTy = doIt(optional->getBaseType(), pos); diff --git a/include/swift/AST/Types.h b/include/swift/AST/Types.h index ce075022c4182..2b4b89eac38c9 100644 --- a/include/swift/AST/Types.h +++ b/include/swift/AST/Types.h @@ -6197,6 +6197,27 @@ class ArraySliceType : public UnarySyntaxSugarType { } }; +/// An InlineArray type e.g `[2 x Foo]`, sugar for `InlineArray<2, Foo>`. +class InlineArrayType : public SyntaxSugarType { + Type Count; + Type Elt; + + InlineArrayType(const ASTContext &ctx, Type count, Type elt, + RecursiveTypeProperties properties) + : SyntaxSugarType(TypeKind::InlineArray, ctx, properties), Count(count), + Elt(elt) {} + +public: + static InlineArrayType *get(Type count, Type elt); + + Type getCountType() const { return Count; } + Type getElementType() const { return Elt; } + + static bool classof(const TypeBase *T) { + return T->getKind() == TypeKind::InlineArray; + } +}; + /// The type T?, which is always sugar for a library type. class OptionalType : public UnarySyntaxSugarType { OptionalType(const ASTContext &ctx,Type base, diff --git a/include/swift/Basic/Features.def b/include/swift/Basic/Features.def index 8e0a2568640ef..b9175e6eb1255 100644 --- a/include/swift/Basic/Features.def +++ b/include/swift/Basic/Features.def @@ -509,6 +509,9 @@ EXPERIMENTAL_FEATURE(SwiftSettings, false) /// Syntax sugar features for concurrency. EXPERIMENTAL_FEATURE(ConcurrencySyntaxSugar, true) +/// Enable syntax sugar type '[3 x Int]' for Inline Array +EXPERIMENTAL_FEATURE(InlineArrayTypeSugar, false) + /// Allow declaration of compile-time values EXPERIMENTAL_FEATURE(CompileTimeValues, true) diff --git a/include/swift/Demangling/DemangleNodes.def b/include/swift/Demangling/DemangleNodes.def index 33af2aa1c4bb8..519f839d7e9bd 100644 --- a/include/swift/Demangling/DemangleNodes.def +++ b/include/swift/Demangling/DemangleNodes.def @@ -330,6 +330,7 @@ NODE(AssociatedTypeGenericParamRef) NODE(SugaredOptional) NODE(SugaredArray) NODE(SugaredDictionary) +NODE(SugaredInlineArray) NODE(SugaredParen) // Removed in Swift 6.TBD // Added in Swift 5.1 diff --git a/include/swift/Demangling/TypeDecoder.h b/include/swift/Demangling/TypeDecoder.h index 4b99605a434cc..724f6d01d019f 100644 --- a/include/swift/Demangling/TypeDecoder.h +++ b/include/swift/Demangling/TypeDecoder.h @@ -1466,6 +1466,22 @@ class TypeDecoder { return Builder.createArrayType(base.getType()); } + case NodeKind::SugaredInlineArray: { + if (Node->getNumChildren() < 2) { + return MAKE_NODE_TYPE_ERROR(Node, + "fewer children (%zu) than required (2)", + Node->getNumChildren()); + } + auto count = decodeMangledType(Node->getChild(0), depth + 1); + if (count.isError()) + return count; + + auto element = decodeMangledType(Node->getChild(1), depth + 1); + if (element.isError()) + return element; + + return Builder.createInlineArrayType(count.getType(), element.getType()); + } case NodeKind::SugaredDictionary: { if (Node->getNumChildren() < 2) return MAKE_NODE_TYPE_ERROR(Node, diff --git a/include/swift/Parse/Parser.h b/include/swift/Parse/Parser.h index 40442bc445a70..f834cb84ce9b6 100644 --- a/include/swift/Parse/Parser.h +++ b/include/swift/Parse/Parser.h @@ -1458,6 +1458,14 @@ class Parser { ParserResult parseTypeTupleBody(); ParserResult parseTypeArray(ParserResult Base); + /// Whether the parser is at the start of an InlineArray type body. + bool isStartOfInlineArrayTypeBody(); + + /// Parse an InlineArray type '[' integer 'x' type ']'. + /// + /// NOTE: 'isStartOfInlineArrayTypeBody' must be true. + ParserResult parseTypeInlineArray(SourceLoc lSquare); + /// Parse a collection type. /// type-simple: /// '[' type ']' @@ -1691,8 +1699,14 @@ class Parser { /// and the expression will parse with the '<' as an operator. bool canParseAsGenericArgumentList(); + bool canParseTypeSimple(); + bool canParseTypeSimpleOrComposition(); + bool canParseTypeScalar(); bool canParseType(); + bool canParseStartOfInlineArrayType(); + bool canParseCollectionType(); + /// Returns true if a simple type identifier can be parsed. /// /// \verbatim diff --git a/include/swift/RemoteInspection/TypeRefBuilder.h b/include/swift/RemoteInspection/TypeRefBuilder.h index 2fa93eda58fda..a6b44e69fdb98 100644 --- a/include/swift/RemoteInspection/TypeRefBuilder.h +++ b/include/swift/RemoteInspection/TypeRefBuilder.h @@ -917,6 +917,12 @@ class TypeRefBuilder { return nullptr; } + const TypeRef *createInlineArrayType(const TypeRef *count, + const TypeRef *element) { + // TypeRefs don't contain sugared types + return nullptr; + } + const TypeRef *createDictionaryType(const TypeRef *key, const TypeRef *value) { // TypeRefs don't contain sugared types diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 16969fd5d0867..4d2e39a272a6a 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -547,6 +547,7 @@ struct ASTContext::Implementation { llvm::DenseMap, ExistentialMetatypeType*> ExistentialMetatypeTypes; llvm::DenseMap ArraySliceTypes; + llvm::DenseMap, InlineArrayType *> InlineArrayTypes; llvm::DenseMap VariadicSequenceTypes; llvm::DenseMap, DictionaryType *> DictionaryTypes; llvm::DenseMap OptionalTypes; @@ -5427,6 +5428,21 @@ ArraySliceType *ArraySliceType::get(Type base) { return entry = new (C, arena) ArraySliceType(C, base, properties); } +InlineArrayType *InlineArrayType::get(Type count, Type elt) { + auto properties = + count->getRecursiveProperties() | elt->getRecursiveProperties(); + auto arena = getArena(properties); + + const ASTContext &C = count->getASTContext(); + + auto *&entry = C.getImpl().getArena(arena).InlineArrayTypes[{count, elt}]; + if (entry) + return entry; + + entry = new (C, arena) InlineArrayType(C, count, elt, properties); + return entry; +} + VariadicSequenceType *VariadicSequenceType::get(Type base) { auto properties = base->getRecursiveProperties(); auto arena = getArena(properties); diff --git a/lib/AST/ASTDemangler.cpp b/lib/AST/ASTDemangler.cpp index ace05a93c14ad..9caff1e65bea7 100644 --- a/lib/AST/ASTDemangler.cpp +++ b/lib/AST/ASTDemangler.cpp @@ -1054,6 +1054,10 @@ Type ASTBuilder::createArrayType(Type base) { return ArraySliceType::get(base); } +Type ASTBuilder::createInlineArrayType(Type count, Type element) { + return InlineArrayType::get(count, element); +} + Type ASTBuilder::createDictionaryType(Type key, Type value) { return DictionaryType::get(key, value); } diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index 342bdac713355..68c8b0747bffb 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -4544,6 +4544,13 @@ class PrintTypeRepr : public TypeReprVisitor, printFoot(); } + void visitInlineArrayTypeRepr(InlineArrayTypeRepr *T, Label label) { + printCommon("type_inline_array", label); + printRec(T->getCount(), Label::always("count")); + printRec(T->getElement(), Label::always("element")); + printFoot(); + } + void visitDictionaryTypeRepr(DictionaryTypeRepr *T, Label label) { printCommon("type_dictionary", label); printRec(T->getKey(), Label::optional("key")); @@ -6388,6 +6395,13 @@ namespace { printFoot(); } + void visitInlineArrayType(InlineArrayType *T, Label label) { + printCommon("inline_array_type", label); + printRec(T->getCountType(), Label::always("count")); + printRec(T->getElementType(), Label::always("element")); + printFoot(); + } + void visitOptionalType(OptionalType *T, Label label) { printCommon("optional_type", label); printRec(T->getBaseType(), Label::optional("base_type")); diff --git a/lib/AST/ASTMangler.cpp b/lib/AST/ASTMangler.cpp index 5e15654a2535b..01c3c740dd288 100644 --- a/lib/AST/ASTMangler.cpp +++ b/lib/AST/ASTMangler.cpp @@ -1574,6 +1574,18 @@ void ASTMangler::appendType(Type type, GenericSignature sig, appendOperator("XSa"); return; + case TypeKind::InlineArray: { + assert(DWARFMangling && "sugared types are only legal for the debugger"); + auto *T = cast(tybase); + appendType(T->getCountType(), sig, forDecl); + appendType(T->getElementType(), sig, forDecl); + // Note we don't have a known-type mangling for InlineArray, we can + // use 'A' since it's incredibly unlikely + // AutoreleasingUnsafeMutablePointer will ever receive type sugar. + appendOperator("XSA"); + return; + } + case TypeKind::VariadicSequence: assert(DWARFMangling && "sugared types are only legal for the debugger"); appendType(cast(tybase)->getBaseType(), sig, forDecl); diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index 0064885da2c24..3af8185404934 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -7066,6 +7066,18 @@ class TypePrinter : public TypeVisitor { } } + void visitInlineArrayType(InlineArrayType *T) { + if (Options.AlwaysDesugarInlineArrayTypes) { + visit(T->getDesugaredType()); + } else { + Printer << "["; + visit(T->getCountType()); + Printer << " x "; + visit(T->getElementType()); + Printer << "]"; + } + } + void visitDictionaryType(DictionaryType *T) { if (Options.AlwaysDesugarDictionaryTypes) { visit(T->getDesugaredType()); diff --git a/lib/AST/ASTWalker.cpp b/lib/AST/ASTWalker.cpp index 83c753aaef212..69db7cb525514 100644 --- a/lib/AST/ASTWalker.cpp +++ b/lib/AST/ASTWalker.cpp @@ -2248,6 +2248,10 @@ bool Traversal::visitArrayTypeRepr(ArrayTypeRepr *T) { return doIt(T->getBase()); } +bool Traversal::visitInlineArrayTypeRepr(InlineArrayTypeRepr *T) { + return doIt(T->getCount()) || doIt(T->getElement()); +} + bool Traversal::visitDictionaryTypeRepr(DictionaryTypeRepr *T) { return doIt(T->getKey()) || doIt(T->getValue()); } diff --git a/lib/AST/Bridging/TypeReprBridging.cpp b/lib/AST/Bridging/TypeReprBridging.cpp index f7e0e6991e92c..e87a215fa363f 100644 --- a/lib/AST/Bridging/TypeReprBridging.cpp +++ b/lib/AST/Bridging/TypeReprBridging.cpp @@ -100,6 +100,14 @@ BridgedErrorTypeRepr BridgedErrorTypeRepr_create(BridgedASTContext cContext, return ErrorTypeRepr::create(cContext.unbridged(), cRange.unbridged()); } +BridgedInlineArrayTypeRepr BridgedInlineArrayTypeRepr_createParsed( + BridgedASTContext cContext, BridgedTypeRepr cCountType, + BridgedTypeRepr cElementType, BridgedSourceRange cBracketsRange) { + return InlineArrayTypeRepr::create( + cContext.unbridged(), cCountType.unbridged(), cElementType.unbridged(), + cBracketsRange.unbridged()); +} + BridgedInverseTypeRepr BridgedInverseTypeRepr_createParsed(BridgedASTContext cContext, BridgedSourceLoc cTildeLoc, diff --git a/lib/AST/FeatureSet.cpp b/lib/AST/FeatureSet.cpp index 5860ee1db04cc..727ed12959b20 100644 --- a/lib/AST/FeatureSet.cpp +++ b/lib/AST/FeatureSet.cpp @@ -195,6 +195,12 @@ static bool usesFeatureNonescapableTypes(Decl *decl) { return false; } +static bool usesFeatureInlineArrayTypeSugar(Decl *D) { + return usesTypeMatching(D, [&](Type ty) { + return isa(ty.getPointer()); + }); +} + UNINTERESTING_FEATURE(StaticExclusiveOnly) UNINTERESTING_FEATURE(ExtractConstantsFromMembers) UNINTERESTING_FEATURE(GroupActorErrors) diff --git a/lib/AST/NameLookup.cpp b/lib/AST/NameLookup.cpp index ab18b712a4ad4..d3ea7e008a910 100644 --- a/lib/AST/NameLookup.cpp +++ b/lib/AST/NameLookup.cpp @@ -3167,6 +3167,10 @@ directReferencesForTypeRepr(Evaluator &evaluator, ASTContext &ctx, result.first.push_back(ctx.getArrayDecl()); return result; + case TypeReprKind::InlineArray: + result.first.push_back(ctx.getInlineArrayDecl()); + return result; + case TypeReprKind::Attributed: { auto attributed = cast(typeRepr); return directReferencesForTypeRepr(evaluator, ctx, diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index c4f5d3beadd9f..43d8bb18e6c9a 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -1997,6 +1997,9 @@ Type SugarType::getSinglyDesugaredTypeSlow() { case TypeKind::VariadicSequence: implDecl = Context->getArrayDecl(); break; + case TypeKind::InlineArray: + implDecl = Context->getInlineArrayDecl(); + break; case TypeKind::Optional: implDecl = Context->getOptionalDecl(); break; @@ -2012,8 +2015,11 @@ Type SugarType::getSinglyDesugaredTypeSlow() { if (auto Ty = dyn_cast(this)) { UnderlyingType = BoundGenericType::get(implDecl, Type(), Ty->getBaseType()); } else if (auto Ty = dyn_cast(this)) { - UnderlyingType = BoundGenericType::get(implDecl, Type(), - { Ty->getKeyType(), Ty->getValueType() }); + UnderlyingType = BoundGenericType::get( + implDecl, Type(), {Ty->getKeyType(), Ty->getValueType()}); + } else if (auto Ty = dyn_cast(this)) { + UnderlyingType = BoundGenericType::get( + implDecl, Type(), {Ty->getCountType(), Ty->getElementType()}); } else { llvm_unreachable("Not UnarySyntaxSugarType or DictionaryType?"); } diff --git a/lib/AST/TypeRepr.cpp b/lib/AST/TypeRepr.cpp index e6e64eb9ddacc..5bbd3665e05c0 100644 --- a/lib/AST/TypeRepr.cpp +++ b/lib/AST/TypeRepr.cpp @@ -311,6 +311,13 @@ SourceLoc DeclRefTypeRepr::getEndLocImpl() const { return getNameLoc().getEndLoc(); } +InlineArrayTypeRepr *InlineArrayTypeRepr::create(ASTContext &ctx, + TypeRepr *count, + TypeRepr *element, + SourceRange brackets) { + return new (ctx) InlineArrayTypeRepr(count, element, brackets); +} + static void printTypeRepr(const TypeRepr *TyR, ASTPrinter &Printer, const PrintOptions &Opts) { if (TyR == nullptr) @@ -473,6 +480,15 @@ void FunctionTypeRepr::printImpl(ASTPrinter &Printer, Printer.printStructurePost(PrintStructureKind::FunctionType); } +void InlineArrayTypeRepr::printImpl(ASTPrinter &Printer, + const PrintOptions &Opts) const { + Printer << "["; + printTypeRepr(getCount(), Printer, Opts); + Printer << " x "; + printTypeRepr(getElement(), Printer, Opts); + Printer << "]"; +} + void ArrayTypeRepr::printImpl(ASTPrinter &Printer, const PrintOptions &Opts) const { Printer << "["; diff --git a/lib/AST/TypeWalker.cpp b/lib/AST/TypeWalker.cpp index 5c2aa8ee3c196..9954fab3ca653 100644 --- a/lib/AST/TypeWalker.cpp +++ b/lib/AST/TypeWalker.cpp @@ -187,6 +187,10 @@ class Traversal : public TypeVisitor return doIt(ty->getBaseType()); } + bool visitInlineArrayType(InlineArrayType *ty) { + return doIt(ty->getCountType()) || doIt(ty->getElementType()); + } + bool visitDictionaryType(DictionaryType *ty) { return doIt(ty->getKeyType()) || doIt(ty->getValueType()); } diff --git a/lib/ASTGen/Sources/ASTGen/SourceFile.swift b/lib/ASTGen/Sources/ASTGen/SourceFile.swift index 04d839c70a3a8..41b2bc3a58f1c 100644 --- a/lib/ASTGen/Sources/ASTGen/SourceFile.swift +++ b/lib/ASTGen/Sources/ASTGen/SourceFile.swift @@ -79,6 +79,7 @@ extension Parser.ExperimentalFeatures { mapFeature(.ABIAttribute, to: .abiAttribute) mapFeature(.OldOwnershipOperatorSpellings, to: .oldOwnershipOperatorSpellings) mapFeature(.KeyPathWithMethodMembers, to: .keypathWithMethodMembers) + mapFeature(.InlineArrayTypeSugar, to: .inlineArrayTypeSugar) } } diff --git a/lib/ASTGen/Sources/ASTGen/Types.swift b/lib/ASTGen/Sources/ASTGen/Types.swift index 1e83de013b1f3..a0cd884131f0b 100644 --- a/lib/ASTGen/Sources/ASTGen/Types.swift +++ b/lib/ASTGen/Sources/ASTGen/Types.swift @@ -38,6 +38,8 @@ extension ASTGenVisitor { return self.generate(functionType: node).asTypeRepr case .identifierType(let node): return self.generate(identifierType: node) + case .inlineArrayType(let node): + return self.generate(inlineArrayType: node).asTypeRepr case .implicitlyUnwrappedOptionalType(let node): return self.generate(implicitlyUnwrappedOptionalType: node).asTypeRepr case .memberType(let node): @@ -102,6 +104,18 @@ extension ASTGenVisitor { ).asTypeRepr } + func generate(inlineArrayType node: InlineArrayTypeSyntax) -> BridgedInlineArrayTypeRepr { + .createParsed( + self.ctx, + count: self.generate(genericArgument: node.count.argument), + element: self.generate(genericArgument: node.element.argument), + brackets: BridgedSourceRange( + start: self.generateSourceLoc(node.leftSquare), + end: self.generateSourceLoc(node.rightSquare) + ) + ) + } + func generate(memberType node: MemberTypeSyntax) -> BridgedDeclRefTypeRepr { let (name, nameLoc) = self.generateIdentifierAndSourceLoc(node.name) diff --git a/lib/ConstExtract/ConstExtract.cpp b/lib/ConstExtract/ConstExtract.cpp index 89dec36fca778..2cc24eb231011 100644 --- a/lib/ConstExtract/ConstExtract.cpp +++ b/lib/ConstExtract/ConstExtract.cpp @@ -92,6 +92,7 @@ std::string toFullyQualifiedTypeNameString(const swift::Type &Type) { Options.FullyQualifiedTypes = true; Options.PreferTypeRepr = true; Options.AlwaysDesugarArraySliceTypes = true; + Options.AlwaysDesugarInlineArrayTypes = true; Options.AlwaysDesugarDictionaryTypes = true; Options.AlwaysDesugarOptionalTypes = true; Options.PrintTypeAliasUnderlyingType = true; diff --git a/lib/Demangling/Demangler.cpp b/lib/Demangling/Demangler.cpp index a3306da7a0019..338b23b130ccb 100644 --- a/lib/Demangling/Demangler.cpp +++ b/lib/Demangling/Demangler.cpp @@ -3927,6 +3927,12 @@ NodePointer Demangler::demangleSpecialType() { case 'a': return createType(createWithChild(Node::Kind::SugaredArray, popNode(Node::Kind::Type))); + case 'A': { + NodePointer element = popNode(Node::Kind::Type); + NodePointer count = popNode(Node::Kind::Type); + return createType(createWithChildren(Node::Kind::SugaredInlineArray, + count, element)); + } case 'D': { NodePointer value = popNode(Node::Kind::Type); NodePointer key = popNode(Node::Kind::Type); diff --git a/lib/Demangling/NodePrinter.cpp b/lib/Demangling/NodePrinter.cpp index a6698b65dab5c..cc221f2938e6b 100644 --- a/lib/Demangling/NodePrinter.cpp +++ b/lib/Demangling/NodePrinter.cpp @@ -328,6 +328,7 @@ class NodePrinter { case Node::Kind::TypeSymbolicReference: case Node::Kind::SugaredOptional: case Node::Kind::SugaredArray: + case Node::Kind::SugaredInlineArray: case Node::Kind::SugaredDictionary: case Node::Kind::SugaredParen: case Node::Kind::Integer: @@ -3289,6 +3290,14 @@ NodePointer NodePrinter::print(NodePointer Node, unsigned depth, print(Node->getChild(0), depth + 1); Printer << "]"; return nullptr; + case Node::Kind::SugaredInlineArray: { + Printer << "["; + print(Node->getChild(0), depth + 1); + Printer << " x "; + print(Node->getChild(1), depth + 1); + Printer << "]"; + return nullptr; + } case Node::Kind::SugaredDictionary: Printer << "["; print(Node->getChild(0), depth + 1); diff --git a/lib/Demangling/OldRemangler.cpp b/lib/Demangling/OldRemangler.cpp index bdae2c4d2d8c7..84a51c39740b0 100644 --- a/lib/Demangling/OldRemangler.cpp +++ b/lib/Demangling/OldRemangler.cpp @@ -2866,6 +2866,10 @@ ManglingError Remangler::mangleSugaredArray(Node *node, unsigned depth) { return MANGLING_ERROR(ManglingError::UnsupportedNodeKind, node); } +ManglingError Remangler::mangleSugaredInlineArray(Node *node, unsigned depth) { + return MANGLING_ERROR(ManglingError::UnsupportedNodeKind, node); +} + ManglingError Remangler::mangleSugaredDictionary(Node *node, unsigned depth) { return MANGLING_ERROR(ManglingError::UnsupportedNodeKind, node); } diff --git a/lib/Demangling/Remangler.cpp b/lib/Demangling/Remangler.cpp index 3d491ec0212da..020b7804f97a0 100644 --- a/lib/Demangling/Remangler.cpp +++ b/lib/Demangling/Remangler.cpp @@ -3808,6 +3808,14 @@ ManglingError Remangler::mangleSugaredArray(Node *node, unsigned depth) { return ManglingError::Success; } +ManglingError +Remangler::mangleSugaredInlineArray(Node *node, unsigned int depth) { + RETURN_IF_ERROR(mangleType(node->getChild(0), depth + 1)); + RETURN_IF_ERROR(mangleType(node->getChild(1), depth + 1)); + Buffer << "XSA"; + return ManglingError::Success; +} + ManglingError Remangler::mangleSugaredDictionary(Node *node, unsigned depth) { RETURN_IF_ERROR(mangleType(node->getChild(0), depth + 1)); RETURN_IF_ERROR(mangleType(node->getChild(1), depth + 1)); diff --git a/lib/IRGen/IRGenDebugInfo.cpp b/lib/IRGen/IRGenDebugInfo.cpp index 630c1c813bc16..88c1b2e61ba51 100644 --- a/lib/IRGen/IRGenDebugInfo.cpp +++ b/lib/IRGen/IRGenDebugInfo.cpp @@ -2261,6 +2261,7 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo { // SyntaxSugarType derivations. case TypeKind::Dictionary: case TypeKind::ArraySlice: + case TypeKind::InlineArray: case TypeKind::Optional: case TypeKind::VariadicSequence: { auto *SyntaxSugarTy = cast(BaseTy); diff --git a/lib/Migrator/APIDiffMigratorPass.cpp b/lib/Migrator/APIDiffMigratorPass.cpp index 544268eaeb7dd..042a6e13bc1a0 100644 --- a/lib/Migrator/APIDiffMigratorPass.cpp +++ b/lib/Migrator/APIDiffMigratorPass.cpp @@ -166,6 +166,10 @@ class ChildIndexFinder : public TypeReprVisitor { return handleParent(T, T->getBase()); } + FoundResult visitInlineArrayTypeRepr(InlineArrayTypeRepr *T) { + return handleParent(T, T->getCount(), T->getElement()); + } + FoundResult visitDictionaryTypeRepr(DictionaryTypeRepr *T) { return handleParent(T, T->getKey(), T->getValue()); } diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 3bdf7757f0d11..54a6db4f0ed31 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -3521,6 +3521,15 @@ ParserResult Parser::parseExprCollection() { *this, LSquareLoc, StructureMarkerKind::OpenSquare); + // Check to see if we can parse an InlineArray type. + if (isStartOfInlineArrayTypeBody()) { + auto result = parseTypeInlineArray(LSquareLoc); + if (result.isNull() || result.isParseErrorOrHasCompletion()) + return ParserStatus(result); + + return makeParserResult(new (Context) TypeExpr(result.get())); + } + // [] is always an array. if (Tok.is(tok::r_square)) { RSquareLoc = consumeToken(tok::r_square); diff --git a/lib/Parse/ParseType.cpp b/lib/Parse/ParseType.cpp index 00934a7cd6869..414b6056bac9d 100644 --- a/lib/Parse/ParseType.cpp +++ b/lib/Parse/ParseType.cpp @@ -1311,6 +1311,40 @@ ParserResult Parser::parseTypeTupleBody() { SourceRange(LPLoc, RPLoc))); } +ParserResult Parser::parseTypeInlineArray(SourceLoc lSquare) { + ASSERT(Context.LangOpts.hasFeature(Feature::InlineArrayTypeSugar)); + + ParserStatus status; + + // 'isStartOfInlineArrayTypeBody' means we should at least have a type and 'x' + // to start with. + auto count = parseTypeOrValue(); + auto *countTy = count.get(); + status |= count; + + // 'x' + consumeToken(tok::identifier); + + // Allow parsing a value for better recovery, Sema will diagnose any + // mismatch. + auto element = parseTypeOrValue(); + if (element.hasCodeCompletion() || element.isNull()) + return element; + + auto *elementTy = element.get(); + status |= element; + + SourceLoc rSquare; + if (parseMatchingToken(tok::r_square, rSquare, + diag::expected_rsquare_inline_array, lSquare)) { + status.setIsParseError(); + } + + SourceRange brackets(lSquare, rSquare); + auto *result = + InlineArrayTypeRepr::create(Context, countTy, elementTy, brackets); + return makeParserResult(status, result); +} /// parseTypeArray - Parse the type-array production, given that we /// are looking at the initial l_square. Note that this index @@ -1364,6 +1398,10 @@ ParserResult Parser::parseTypeCollection() { Parser::StructureMarkerRAII parsingCollection(*this, Tok); SourceLoc lsquareLoc = consumeToken(); + // Check to see if we can parse as InlineArray. + if (isStartOfInlineArrayTypeBody()) + return parseTypeInlineArray(lsquareLoc); + // Parse the element type. ParserResult firstTy = parseType(diag::expected_element_type); Status |= firstTy; @@ -1575,23 +1613,7 @@ bool Parser::canParseGenericArguments() { } } -bool Parser::canParseType() { - // 'repeat' starts a pack expansion type. - consumeIf(tok::kw_repeat); - - // Accept 'inout' at for better recovery. - consumeIf(tok::kw_inout); - - if (Tok.isContextualKeyword("some")) { - consumeToken(); - } else if (Tok.isContextualKeyword("any")) { - consumeToken(); - } else if (Tok.isContextualKeyword("each")) { - consumeToken(); - } else if (Tok.isContextualKeyword("sending")) { - consumeToken(); - } - +bool Parser::canParseTypeSimple() { switch (Tok.getKind()) { case tok::kw_Self: case tok::kw_Any: @@ -1619,6 +1641,8 @@ bool Parser::canParseType() { if (!Tok.is(tok::integer_literal)) return false; + + consumeToken(); } break; @@ -1637,14 +1661,7 @@ bool Parser::canParseType() { return canParseType(); } case tok::l_square: - consumeToken(); - if (!canParseType()) - return false; - if (consumeIf(tok::colon)) { - if (!canParseType()) - return false; - } - if (!consumeIf(tok::r_square)) + if (!canParseCollectionType()) return false; break; case tok::kw__: @@ -1685,14 +1702,44 @@ bool Parser::canParseType() { } break; } + return true; +} + +bool Parser::canParseTypeSimpleOrComposition() { + auto canParseElement = [&]() -> bool { + if (Tok.isContextualKeyword("some")) { + consumeToken(); + } else if (Tok.isContextualKeyword("any")) { + consumeToken(); + } else if (Tok.isContextualKeyword("each")) { + consumeToken(); + } + + return canParseTypeSimple(); + }; + if (!canParseElement()) + return false; while (Tok.isContextualPunctuator("&")) { consumeToken(); - // FIXME: Should be 'canParseTypeSimple', but we don't have one. - if (!canParseType()) + // Note we include 'some', 'any', and 'each' here for better recovery. + if (!canParseElement()) return false; } + return true; +} + +bool Parser::canParseTypeScalar() { + // Accept 'inout' at for better recovery. + consumeIf(tok::kw_inout); + + if (Tok.isContextualKeyword("sending")) + consumeToken(); + + if (!canParseTypeSimpleOrComposition()) + return false; + if (isAtFunctionTypeArrow()) { // Handle type-function if we have an '->' with optional // 'async' and/or 'throws'. @@ -1707,22 +1754,84 @@ bool Parser::canParseType() { if (!consumeIf(tok::arrow)) return false; - - if (!canParseType()) + + if (!canParseTypeScalar()) return false; - - return true; } + return true; +} + +bool Parser::canParseType() { + // 'repeat' starts a pack expansion type. + consumeIf(tok::kw_repeat); + + if (!canParseTypeScalar()) + return false; // Parse pack expansion 'T...'. if (Tok.isEllipsis()) { Tok.setKind(tok::ellipsis); consumeToken(); } + return true; +} + +bool Parser::canParseStartOfInlineArrayType() { + if (!Context.LangOpts.hasFeature(Feature::InlineArrayTypeSugar)) + return false; + + // We must have at least '[ x', which cannot be any other kind of + // expression or type. We specifically look for any type, not just integers + // for better recovery in e.g cases where the user writes '[Int x 2]'. We + // only do type-scalar since variadics would be ambiguous e.g 'Int...x'. + if (!canParseTypeScalar()) + return false; + // For now we don't allow multi-line since that would require + // disambiguation. + if (Tok.isAtStartOfLine() || !Tok.isContextualKeyword("x")) + return false; + + consumeToken(); return true; } +bool Parser::isStartOfInlineArrayTypeBody() { + if (!Context.LangOpts.hasFeature(Feature::InlineArrayTypeSugar)) + return false; + + BacktrackingScope backtrack(*this); + return canParseStartOfInlineArrayType(); +} + +bool Parser::canParseCollectionType() { + if (!consumeIf(tok::l_square)) + return false; + + // Check to see if we have an InlineArray sugar type. + if (Context.LangOpts.hasFeature(Feature::InlineArrayTypeSugar)) { + CancellableBacktrackingScope backtrack(*this); + if (canParseStartOfInlineArrayType()) { + backtrack.cancelBacktrack(); + if (!canParseType()) + return false; + if (!consumeIf(tok::r_square)) + return false; + return true; + } + } + + if (!canParseType()) + return false; + + if (consumeIf(tok::colon)) { + if (!canParseType()) + return false; + } + + return consumeIf(tok::r_square); +} + bool Parser::canParseTypeIdentifier() { // Parse an identifier. // diff --git a/lib/Sema/CSSolver.cpp b/lib/Sema/CSSolver.cpp index 968b44cae8def..8e8b57cc7c982 100644 --- a/lib/Sema/CSSolver.cpp +++ b/lib/Sema/CSSolver.cpp @@ -1181,6 +1181,11 @@ void ConstraintSystem::shrink(Expr *expr) { if (boundGeneric->hasUnresolvedType()) return boundGeneric; + // Avoid handling InlineArray, building a tuple would be wrong, and + // we want to eliminate shrink. + if (boundGeneric->getDecl() == ctx.getInlineArrayDecl()) + return Type(); + llvm::SmallVector params; for (auto &type : boundGeneric->getGenericArgs()) { // One of the generic arguments in invalid or unresolved. diff --git a/lib/Sema/TypeCheckAvailability.cpp b/lib/Sema/TypeCheckAvailability.cpp index 73368bb8ef871..32c323d838f86 100644 --- a/lib/Sema/TypeCheckAvailability.cpp +++ b/lib/Sema/TypeCheckAvailability.cpp @@ -3145,7 +3145,26 @@ class TypeReprAvailabilityWalker : public ASTWalker { return MacroWalking::ArgumentsAndExpansion; } + bool checkInlineArrayTypeRepr(InlineArrayTypeRepr *T) { + // Has the same availability as InlineArray. + auto &ctx = where.getDeclContext()->getASTContext(); + auto *D = ctx.getInlineArrayDecl(); + if (!D) { + // If we have a broken stdlib we will have already diagnosed. + return false; + } + return diagnoseDeclAvailability(D, T->getSourceRange(), /*call*/ nullptr, + where, flags); + } + PreWalkAction walkToTypeReprPre(TypeRepr *T) override { + if (auto *IAT = dyn_cast(T)) { + if (checkInlineArrayTypeRepr(IAT)) { + foundAnyIssues = true; + } + return Action::Continue(); + } + auto *declRefTR = dyn_cast(T); if (!declRefTR) return Action::Continue(); diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index efa5a5b1d9621..eb0a446ff5624 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -746,9 +746,30 @@ namespace { /// to see if it's a valid parameter for integer arguments or other value /// generic parameters. class ValueMatchVisitor : public TypeMatcher { - public: ValueMatchVisitor() {} + public: + static bool check(ASTContext &ctx, Type paramTy, Type argTy, + SourceLoc loc) { + auto matcher = ValueMatchVisitor(); + if (argTy->hasError() || matcher.match(paramTy, argTy)) + return false; + + // If the parameter is a value, then we're trying to substitute a + // non-value type like 'Int' or 'T' to our value. + if (paramTy->isValueParameter()) { + ctx.Diags.diagnose(loc, diag::cannot_pass_type_for_value_generic, + argTy, paramTy); + } else { + // Otherwise, we're trying to use a value type (either an integer + // directly or another generic value parameter) for a non-value + // parameter. + ctx.Diags.diagnose(loc, diag::value_type_used_in_type_parameter, + argTy, paramTy); + } + return true; + } + bool mismatch(TypeBase *firstType, TypeBase *secondType, Type sugaredFirstType) { return true; @@ -763,9 +784,18 @@ namespace { if (secondType->is()) return true; + // For type variable substitutions, the constraint system should + // handle any mismatches (currently this only happens for unbound + // opening though). + if (secondType->isTypeVariableOrMember()) + return true; + return false; } + if (secondType->is()) + return false; + return true; } @@ -1019,11 +1049,6 @@ static Type applyGenericArguments(Type type, return ErrorType::get(ctx); args.push_back(substTy); - - // The type we're binding to may not have value parameters, but one of the - // arguments may be a value parameter so diagnose this situation as well. - if (substTy->isValueParameter()) - hasValueParam = true; } // Make sure we have the right number of generic arguments. @@ -1093,31 +1118,6 @@ static Type applyGenericArguments(Type type, } } - if (hasValueParam) { - ValueMatchVisitor matcher; - - for (auto i : indices(genericParams->getParams())) { - auto param = genericParams->getParams()[i]->getDeclaredInterfaceType(); - auto arg = args[i]; - - if (!matcher.match(param, arg)) { - // If the parameter is a value, then we're trying to substitute a - // non-value type like 'Int' or 'T' to our value. - if (param->isValueParameter()) { - diags.diagnose(loc, diag::cannot_pass_type_for_value_generic, arg, param); - return ErrorType::get(ctx); - - // Otherwise, we're trying to use a value type (either an integer - // directly or another generic value parameter) for a non-value - // parameter. - } else { - diags.diagnose(loc, diag::value_type_used_in_type_parameter, arg, param); - return ErrorType::get(ctx); - } - } - } - } - // Construct the substituted type. const auto result = resolution.applyUnboundGenericArguments( decl, unboundType->getParent(), loc, args); @@ -1183,6 +1183,7 @@ Type TypeResolution::applyUnboundGenericArguments( "invalid arguments, use applyGenericArguments to emit diagnostics " "and collect arguments to pack generic parameters"); + auto &ctx = getASTContext(); TypeSubstitutionMap subs; // Get the interface type for the declaration. We will be substituting @@ -1241,12 +1242,16 @@ Type TypeResolution::applyUnboundGenericArguments( auto innerParams = decl->getGenericParams()->getParams(); for (unsigned i : indices(innerParams)) { auto origTy = innerParams[i]->getDeclaredInterfaceType(); - auto origGP = origTy->getCanonicalType()->castTo(); + auto paramTy = origTy->getCanonicalType()->castTo(); auto substTy = genericArgs[i]; - // Enter a substitution. - subs[origGP] = substTy; + // Ensure the value-ness of the argument matches the parameter. + if (ValueMatchVisitor::check(ctx, origTy, substTy, loc)) + substTy = ErrorType::get(ctx); + + // Enter the substitution. + subs[paramTy] = substTy; skipRequirementsCheck |= substTy->hasTypeVariable() || substTy->hasUnboundGenericType(); @@ -1289,13 +1294,13 @@ Type TypeResolution::applyUnboundGenericArguments( if (loc.isValid()) { TypeChecker::diagnoseRequirementFailure( result.getRequirementFailureInfo(), loc, noteLoc, - UnboundGenericType::get(decl, parentTy, getASTContext()), + UnboundGenericType::get(decl, parentTy, ctx), genericSig.getGenericParams(), substitutions); } LLVM_FALLTHROUGH; case CheckRequirementsResult::SubstitutionFailure: - return ErrorType::get(getASTContext()); + return ErrorType::get(ctx); case CheckRequirementsResult::Success: break; } @@ -2332,6 +2337,8 @@ namespace { TypeResolutionOptions options); NeverNullType resolveArrayType(ArrayTypeRepr *repr, TypeResolutionOptions options); + NeverNullType resolveInlineArrayType(InlineArrayTypeRepr *repr, + TypeResolutionOptions options); NeverNullType resolveDictionaryType(DictionaryTypeRepr *repr, TypeResolutionOptions options); NeverNullType resolveOptionalType(OptionalTypeRepr *repr, @@ -2770,6 +2777,9 @@ NeverNullType TypeResolver::resolveType(TypeRepr *repr, case TypeReprKind::Array: return resolveArrayType(cast(repr), options); + case TypeReprKind::InlineArray: + return resolveInlineArrayType(cast(repr), options); + case TypeReprKind::Dictionary: return resolveDictionaryType(cast(repr), options); @@ -5259,6 +5269,53 @@ TypeResolver::resolveCompileTimeLiteralTypeRepr(CompileTimeLiteralTypeRepr *repr return resolveType(repr->getBase(), options); } +NeverNullType +TypeResolver::resolveInlineArrayType(InlineArrayTypeRepr *repr, + TypeResolutionOptions options) { + ASTContext &ctx = getASTContext(); + auto argOptions = options.withoutContext().withContext( + TypeResolverContext::ValueGenericArgument); + + // It's possible the user accidentally wrote '[Int x 4]', correct that here. + auto *countRepr = repr->getCount(); + auto *eltRepr = repr->getElement(); + if (!isa(countRepr) && isa(eltRepr)) { + std::swap(countRepr, eltRepr); + ctx.Diags + .diagnose(countRepr->getStartLoc(), diag::inline_array_type_backwards) + .fixItExchange(countRepr->getSourceRange(), eltRepr->getSourceRange()); + } + + auto countTy = resolveType(countRepr, argOptions); + if (countTy->hasError()) + return ErrorType::get(getASTContext()); + + auto eltTy = resolveType(eltRepr, argOptions); + if (eltTy->hasError()) + return ErrorType::get(getASTContext()); + + { + // If the standard library isn't loaded, we ought to let the user know + // something has gone terribly wrong, since it will otherwise break + // type canonicalization. + auto *inlineArrayDecl = ctx.getInlineArrayDecl(); + if (!inlineArrayDecl) { + ctx.Diags.diagnose(repr->getBrackets().Start, diag::sugar_type_not_found, + 2); + return ErrorType::get(ctx); + } + + // Make sure we can substitute the generic args. + auto ty = resolution.applyUnboundGenericArguments( + inlineArrayDecl, + /*parentTy=*/nullptr, repr->getStartLoc(), {countTy, eltTy}); + if (ty->hasError()) + return ErrorType::get(ctx); + } + + return InlineArrayType::get(countTy, eltTy); +} + NeverNullType TypeResolver::resolveArrayType(ArrayTypeRepr *repr, TypeResolutionOptions options) { auto baseTy = resolveType(repr->getBase(), options.withoutContext()); @@ -6306,6 +6363,7 @@ class ExistentialTypeSyntaxChecker : public ASTWalker { case TypeReprKind::Fixed: case TypeReprKind::Self: case TypeReprKind::Array: + case TypeReprKind::InlineArray: case TypeReprKind::SILBox: case TypeReprKind::Isolated: case TypeReprKind::Sending: diff --git a/lib/Serialization/DeclTypeRecordNodes.def b/lib/Serialization/DeclTypeRecordNodes.def index c62a94b8b41b9..1b6cf318e9392 100644 --- a/lib/Serialization/DeclTypeRecordNodes.def +++ b/lib/Serialization/DeclTypeRecordNodes.def @@ -99,6 +99,7 @@ TYPE(BOUND_GENERIC) TYPE(GENERIC_FUNCTION) TYPE(ARRAY_SLICE) +TYPE(INLINE_ARRAY) TYPE(DICTIONARY) TYPE(REFERENCE_STORAGE) TYPE(UNBOUND_GENERIC) diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp index 64cb86be9c8bb..2653c9fa9e219 100644 --- a/lib/Serialization/Deserialization.cpp +++ b/lib/Serialization/Deserialization.cpp @@ -7961,6 +7961,22 @@ Expected DESERIALIZE_TYPE(ARRAY_SLICE_TYPE)( return ArraySliceType::get(baseTy.get()); } +Expected DESERIALIZE_TYPE(INLINE_ARRAY_TYPE)( + ModuleFile &MF, SmallVectorImpl &scratch, StringRef blobData) { + TypeID countID, elementID; + decls_block::InlineArrayTypeLayout::readRecord(scratch, countID, elementID); + + auto countTy = MF.getTypeChecked(countID); + if (!countTy) + return countTy.takeError(); + + auto elementTy = MF.getTypeChecked(elementID); + if (!elementTy) + return elementTy.takeError(); + + return InlineArrayType::get(countTy.get(), elementTy.get()); +} + Expected DESERIALIZE_TYPE(DICTIONARY_TYPE)( ModuleFile &MF, SmallVectorImpl &scratch, StringRef blobData) { TypeID keyID, valueID; diff --git a/lib/Serialization/ModuleFormat.h b/lib/Serialization/ModuleFormat.h index 30e5be7afe9d8..5beedb656eb64 100644 --- a/lib/Serialization/ModuleFormat.h +++ b/lib/Serialization/ModuleFormat.h @@ -58,7 +58,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0; /// describe what change you made. The content of this comment isn't important; /// it just ensures a conflict if two people change the module format. /// Don't worry about adhering to the 80-column limit for this line. -const uint16_t SWIFTMODULE_VERSION_MINOR = 926; // abstract conformances +const uint16_t SWIFTMODULE_VERSION_MINOR = 927; // InlineArray type /// A standard hash seed used for all string hashes in a serialized module. /// @@ -1485,6 +1485,12 @@ namespace decls_block { SYNTAX_SUGAR_TYPE_LAYOUT(VariadicSequenceTypeLayout, VARIADIC_SEQUENCE_TYPE); SYNTAX_SUGAR_TYPE_LAYOUT(ExistentialTypeLayout, EXISTENTIAL_TYPE); + TYPE_LAYOUT(InlineArrayTypeLayout, + INLINE_ARRAY_TYPE, + TypeIDField, // count type + TypeIDField // element type + ); + TYPE_LAYOUT(DictionaryTypeLayout, DICTIONARY_TYPE, TypeIDField, // key type diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index 5371b176325bf..ee449ee67885a 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -5978,6 +5978,14 @@ class Serializer::TypeSerializer : public TypeVisitor { serializeSimpleWrapper(sliceTy->getBaseType()); } + void visitInlineArrayType(const InlineArrayType *T) { + using namespace decls_block; + unsigned abbrCode = S.DeclTypeAbbrCodes[InlineArrayTypeLayout::Code]; + InlineArrayTypeLayout::emitRecord(S.Out, S.ScratchRecord, abbrCode, + S.addTypeRef(T->getCountType()), + S.addTypeRef(T->getElementType())); + } + void visitDictionaryType(const DictionaryType *dictTy) { using namespace decls_block; unsigned abbrCode = S.DeclTypeAbbrCodes[DictionaryTypeLayout::Code]; diff --git a/stdlib/public/runtime/MetadataLookup.cpp b/stdlib/public/runtime/MetadataLookup.cpp index eeb5b6ed0c273..2d458b11417f8 100644 --- a/stdlib/public/runtime/MetadataLookup.cpp +++ b/stdlib/public/runtime/MetadataLookup.cpp @@ -2444,6 +2444,12 @@ class DecodedMetadataBuilder { return BuiltType(); } + TypeLookupErrorOr createInlineArrayType(BuiltType count, + BuiltType element) { + // Mangled types for building metadata don't contain sugared types + return BuiltType(); + } + TypeLookupErrorOr createDictionaryType(BuiltType key, BuiltType value) { // Mangled types for building metadata don't contain sugared types diff --git a/test/ASTGen/types.swift b/test/ASTGen/types.swift index 17426fbd273b5..1ee9cd362392d 100644 --- a/test/ASTGen/types.swift +++ b/test/ASTGen/types.swift @@ -2,18 +2,22 @@ // RUN: %target-swift-frontend-dump-parse -enable-experimental-feature ParserASTGen \ // RUN: -enable-experimental-feature NamedOpaqueTypes \ +// RUN: -enable-experimental-feature InlineArrayTypeSugar \ // RUN: | %sanitize-address > %t/astgen.ast // RUN: %target-swift-frontend-dump-parse \ // RUN: -enable-experimental-feature NamedOpaqueTypes \ +// RUN: -enable-experimental-feature InlineArrayTypeSugar \ // RUN: | %sanitize-address > %t/cpp-parser.ast // RUN: %diff -u %t/astgen.ast %t/cpp-parser.ast // RUN: %target-typecheck-verify-swift -enable-experimental-feature ParserASTGen \ -// RUN: -enable-experimental-feature NamedOpaqueTypes +// RUN: -enable-experimental-feature NamedOpaqueTypes \ +// RUN: -enable-experimental-feature InlineArrayTypeSugar // REQUIRES: swift_feature_ParserASTGen // REQUIRES: swift_feature_NamedOpaqueTypes +// REQUIRES: swift_feature_InlineArrayTypeSugar // rdar://116686158 // UNSUPPORTED: asan @@ -78,4 +82,12 @@ typealias TestSpecifierAndAttr = (__owned @Sendable @escaping () async -> T) let globalOptionalInt: _? = 42 let optionalIntArray: Array<_> = [42] +@available(SwiftStdlib 9999, *) +func testInlineArray() { + let _: [3 x Int] = [1, 2, 3] + let _: [_ x _] = [1, 2] + let _ = [3 x Int](repeating: 0) + let _ = [3 x _](repeating: 0) +} + func testNamedOpaqueReturnTy() -> T { return () } diff --git a/test/DebugInfo/sugar_inline_array.swift b/test/DebugInfo/sugar_inline_array.swift new file mode 100644 index 0000000000000..30072aea303d9 --- /dev/null +++ b/test/DebugInfo/sugar_inline_array.swift @@ -0,0 +1,15 @@ +// RUN: %target-swift-frontend %s -emit-ir -enable-experimental-feature InlineArrayTypeSugar -disable-availability-checking -g -o - | %FileCheck %s + +// REQUIRES: swift_feature_InlineArrayTypeSugar + +let a: ([3 x Int], InlineArray<3, Int>) = ([1, 2, 3], [1, 2, 3]) +let b: ([3 x [1 x String]], InlineArray<3, InlineArray<1, String>>) = ([[""], [""], [""]], [[""], [""], [""]]) + +// CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "$s$2_SiXSA_s11InlineArrayVy$2_SiGtD", {{.*}}) +// CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "$s$2_$0_SSXSAXSA_s11InlineArrayVy$2_ABy$0_SSGGtD", {{.*}}) + +// RUN: swift-demangle 's$2_SiXSA_s11InlineArrayVy$2_SiGtD' | %FileCheck %s --check-prefix SIMPLE +// SIMPLE: ([3 x Swift.Int], Swift.InlineArray<3, Swift.Int>) + +// RUN: swift-demangle 's$2_$0_SSXSAXSA_s11InlineArrayVy$2_ABy$0_SSGGtD' | %FileCheck %s --check-prefix NESTED +// NESTED: ([3 x [1 x Swift.String]], Swift.InlineArray<3, Swift.InlineArray<1, Swift.String>>) diff --git a/test/IDE/complete_inline_array.swift b/test/IDE/complete_inline_array.swift new file mode 100644 index 0000000000000..26dd743123446 --- /dev/null +++ b/test/IDE/complete_inline_array.swift @@ -0,0 +1,9 @@ +// RUN: %batch-code-completion -enable-experimental-feature InlineArrayTypeSugar + +// REQUIRES: swift_feature_InlineArrayTypeSugar + +struct FooBar {} + +[3 x #^COMPLETE_TOPLEVEL?check=COMPLETE^# +let _: [3 x #^COMPLETE_TYPE?check=COMPLETE^# +// COMPLETE: Decl[Struct]/CurrModule: FooBar[#FooBar#]; name=FooBar diff --git a/test/Sema/inline_array_availability.swift b/test/Sema/inline_array_availability.swift new file mode 100644 index 0000000000000..5ab09c4a6e97a --- /dev/null +++ b/test/Sema/inline_array_availability.swift @@ -0,0 +1,18 @@ +// RUN: %target-typecheck-verify-swift -enable-experimental-feature InlineArrayTypeSugar -target %target-cpu-apple-macosx15.0 + +// REQUIRES: swift_feature_InlineArrayTypeSugar +// REQUIRES: OS=macosx + +func foo(x: InlineArray<3, Int>) {} +// expected-error@-1 {{'InlineArray' is only available in}} +// expected-note@-2 {{add @available attribute to enclosing global function}} + +func bar(x: [3 x Int]) {} +// expected-error@-1 {{'InlineArray' is only available in}} +// expected-note@-2 {{add @available attribute to enclosing global function}} + +@available(SwiftStdlib 9999, *) +func baz(x: InlineArray<3, Int>) {} + +@available(SwiftStdlib 9999, *) +func qux(x: [3 x Int]) {} diff --git a/test/Sema/inlinearray.swift b/test/Sema/inlinearray.swift index 85f36866f4c8d..19d766440224a 100644 --- a/test/Sema/inlinearray.swift +++ b/test/Sema/inlinearray.swift @@ -1,4 +1,6 @@ -// RUN: %target-typecheck-verify-swift -disable-availability-checking +// RUN: %target-typecheck-verify-swift -disable-availability-checking -enable-experimental-feature InlineArrayTypeSugar + +// REQUIRES: swift_feature_InlineArrayTypeSugar let a: InlineArray = [1, 2, 3] // Ok, InlineArray<3, Int> let b: InlineArray<_, Int> = [1, 2, 3] // Ok, InlineArray<3, Int> @@ -9,6 +11,30 @@ let e: InlineArray<2, _> = [1] // expected-error {{expected '2' elements in inli let f: InlineArray<_, Int> = ["hello"] // expected-error {{cannot convert value of type 'String' to expected element type 'Int'}} +let g: InlineArray<1, 1> // expected-error {{cannot use value type '1' for generic argument 'Element'}} + +let _: [3 x Int] = [1, 2, 3] // Ok, InlineArray<3, Int> +let _: [_ x Int] = [1, 2, 3] // Ok, InlineArray<3, Int> +let _: [3 x _] = [1, 2, 3] // Ok, InlineArray<3, Int> +let _: [_ x _] = ["", "", ""] // Ok, InlineArray<3, String> + +let _: [3 x [3 x Int]] = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] +let _: [3 x [3 x Int]] = [[1, 2], [3, 4, 5, 6]] +// expected-error@-1 {{'3' elements in inline array literal, but got '2'}} +// expected-error@-2 2{{cannot convert value of type '[Int]' to expected element type '[3 x Int]'}} + +let _ = [3 x [3 x Int]](repeating: [1, 2]) // expected-error {{expected '3' elements in inline array literal, but got '2'}} +let _ = [3 x [_ x Int]](repeating: [1, 2]) + +let _: [Int x 10] = [1, 2] // expected-error {{element count must precede inline array element type}} {{15-17=Int}} {{9-12=10}} +// expected-error@-1 {{expected '10' elements in inline array literal, but got '2'}} + +let _: [4 x _] = [1, 2, 3] // expected-error {{expected '4' elements in inline array literal, but got '3'}} +let _: [3 x Int] = [1, 2, 3, 4] // expected-error {{expected '3' elements in inline array literal, but got '4'}} +let _: [3 x String] = [1, 2, 3] // expected-error 3{{cannot convert value of type 'Int' to expected element type 'String'}} +let _: [3 x String] = [1] // expected-error {{cannot convert value of type 'Int' to expected element type 'String'}} +// expected-error@-1 {{expected '3' elements in inline array literal, but got '1'}} + func takeVectorOf2(_: InlineArray<2, T>) {} takeVectorOf2([1, 2]) // Ok @@ -37,6 +63,13 @@ takeVectorOf2Int(["hello", "world"]) // expected-error {{cannot convert value of takeVectorOf2Int(["hello", "world", "!"]) // expected-error {{cannot convert value of type '[String]' to expected argument type 'InlineArray<2, Int>'}} +func takeSugarVectorOf2(_: [2 x T], ty: T.Type = T.self) {} +takeSugarVectorOf2([1, 2]) +takeSugarVectorOf2(["hello"]) // expected-error {{expected '2' elements in inline array literal, but got '1'}} +takeSugarVectorOf2(["hello"], ty: Int.self) // expected-error {{cannot convert value of type '[String]' to expected argument type '[2 x Int]'}} +takeSugarVectorOf2(["hello", "hi"], ty: Int.self) // expected-error 2{{cannot convert value of type 'String' to expected element type 'Int'}} + + struct X { var sprites: InlineArray<2, Int> } @@ -78,3 +111,45 @@ extension InlineArray where Element: ~Copyable { } } } + +extension [3 x Int] { // expected-note 2{{where 'count' = '2'}} expected-note {{where 'Element' = 'String'}} + func methodOnSugar() {} +} + +func testExtension( + _ a: [3 x Int], + _ b: InlineArray<3, Int>, + _ c: [2 x Int], + _ d: [2 x String] +) { + a.enumerated { _, _ in } + a.methodOnSugar() + b.methodOnSugar() + c.methodOnSugar() + // expected-error@-1 {{referencing instance method 'methodOnSugar()' on 'InlineArray' requires the types '2' and '3' be equivalent}} + d.methodOnSugar() + // expected-error@-1 {{referencing instance method 'methodOnSugar()' on 'InlineArray' requires the types '2' and '3' be equivalent}} + // expected-error@-2 {{referencing instance method 'methodOnSugar()' on 'InlineArray' requires the types 'String' and 'Int' be equivalent}} +} + +func redecl(_ x: InlineArray<2, Int>) {} // expected-note {{'redecl' previously declared here}} +func redecl(_ x: [2 x Int]) {} // expected-error {{invalid redeclaration of 'redecl'}} + +func noRedecl(_ x: InlineArray<2, Int>) {} +func noRedecl(_ x: [3 x Int]) {} +func noRedecl(_ x: [2 x String]) {} +func noRedecl(_ x: [3 x String]) {} + +func testMismatches(_ x: [3 x Int], _ y: InlineArray<3, Int>) { + let _: InlineArray<3, Int> = x + let _: InlineArray<4, Int> = x // expected-error {{cannot assign value of type '[3 x Int]' to type 'InlineArray<4, Int>'}} + // expected-note@-1 {{arguments to generic parameter 'count' ('3' and '4') are expected to be equal}} + let _: InlineArray<3, String> = x // expected-error {{cannot assign value of type '[3 x Int]' to type 'InlineArray<3, String>'}} + // expected-note@-1 {{arguments to generic parameter 'Element' ('Int' and 'String') are expected to be equal}} + + let _: [3 x Int] = y + let _: [4 x Int] = y // expected-error {{cannot assign value of type 'InlineArray<3, Int>' to type '[4 x Int]'}} + // expected-note@-1 {{arguments to generic parameter 'count' ('3' and '4') are expected to be equal}} + 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}} +} diff --git a/test/Sema/value_generics.swift b/test/Sema/value_generics.swift index 5467102931978..0f5d38b9dce15 100644 --- a/test/Sema/value_generics.swift +++ b/test/Sema/value_generics.swift @@ -66,7 +66,9 @@ func h(_: (Int, 123)) {} // expected-error {{expected type}} func i(_: () -> 123) {} // expected-error {{expected type}} func j(_: (A<123>) -> ()) {} // OK func k(_: some 123) {} // expected-error {{expected parameter type following ':'}} -func l(_: GenericWithIntParam<123, Int>) {} // expected-error {{cannot pass type 'Int' as a value for generic value 'N'}} +func l(_: GenericWithIntParam<123, Int>) {} +// expected-error@-1 {{cannot pass type 'Int' as a value for generic value 'N'}} +// expected-error@-2 {{cannot use value type '123' for generic argument 'T'}} func m(_: GenericWithIntParam) {} // OK typealias One = 1 // expected-error {{expected type in type alias declaration}} diff --git a/test/type/inline_array.swift b/test/type/inline_array.swift new file mode 100644 index 0000000000000..1e31a217c1c9d --- /dev/null +++ b/test/type/inline_array.swift @@ -0,0 +1,109 @@ +// RUN: %target-typecheck-verify-swift -enable-experimental-feature InlineArrayTypeSugar -disable-availability-checking + +// REQUIRES: swift_feature_InlineArrayTypeSugar + +let _: [3 x Int] +let _ = [3 x Int](repeating: 0) +let _ = [3 x [3 x Int]](repeating: [1, 2, 3]) + +let _ = [[3 x Int] x Int]() // expected-error {{cannot pass type '[3 x Int]' as a value for generic value 'count'}} + +do { + let _: [3 x + // expected-error@-1 {{expected type}} +} + +do { + let _: [3 x Int // expected-note {{to match this opening '['}} +} // expected-error {{expected ']' in inline array type}} + +// We don't currently allow multi-line. +func testMultiline(_ x: Int) { + let _ = [ // expected-error {{cannot call value of non-function type '[Int]'}} + 3 // expected-error {{expected ',' separator}} + x + Int + ](repeating: 0) + + let _ = [3 + x + Int + ](repeating: 0) + // expected-error@-4 {{expected ',' separator}} + // expected-error@-5 {{cannot call value of non-function type '[Int]'}} + + let _ = [3 + x Int](repeating: 0) + // expected-error@-2 {{cannot call value of non-function type '[Int]'}} + // expected-error@-3 {{expected ',' separator}} + + // This is okay. + let _ = [3 x + Int](repeating: 0) + + // So's this + let _ = [ + 3 x Int + ](repeating: 0) +} + +protocol P {} +protocol Q {} + +struct S {} + +let _ = S<[3 x Int]>() +let _ = S<[[3 x Int]]>() + +// Make sure we can recover for different type productions as the LHS. +let _ = S<[[Int x 3]]>() +// expected-error@-1 {{element count must precede inline array element type}} +let _ = S<[@escaping () -> Int x 3]>() +// expected-error@-1 {{element count must precede inline array element type}} +// expected-error@-2 {{@escaping attribute may only be used in function parameter position}} +let _ = S<[Int.Type x 3]>() +// expected-error@-1 {{element count must precede inline array element type}} +let _ = S<[sending P & Q x 3]>() +// expected-error@-1 {{element count must precede inline array element type}} +// expected-error@-2 {{'sending' may only be used on parameters and results}} +let _ = S<[some P & Q -> Int x 3]>() +// expected-error@-1 {{element count must precede inline array element type}} +// expected-error@-2 {{single argument function types require parentheses}} +// expected-error@-3 {{'some' types are only permitted in properties, subscripts, and functions}} +let _ = S<[~P x 3]>() +// expected-error@-1 {{element count must precede inline array element type}} +// expected-error@-2 {{type 'P' cannot be suppressed}} +let _ = S<[(Int, String) x 3]>() +// expected-error@-1 {{element count must precede inline array element type}} +let _ = S<[[3 x Int] x 3]>() +// expected-error@-1 {{element count must precede inline array element type}} +let _ = S<[[Int] x 3]>() +// expected-error@-1 {{element count must precede inline array element type}} +let _ = S<[Array x 3]>() +// expected-error@-1 {{element count must precede inline array element type}} +let _ = S<[_ x 3]>() +// expected-error@-1 {{element count must precede inline array element type}} +// expected-error@-2 {{could not infer type for placeholder}} +let _ = S<[_? x 3]>() +// expected-error@-1 {{element count must precede inline array element type}} +// expected-error@-2 {{could not infer type for placeholder}} +let _ = S<[_?x 3]>() +// expected-error@-1 {{element count must precede inline array element type}} +// expected-error@-2 {{could not infer type for placeholder}} +let _ = S<[_! x 3]>() +// expected-error@-1 {{element count must precede inline array element type}} +// expected-warning@-2 {{using '!' here is deprecated; this is an error in the Swift 5 language mode}} +// expected-note@-3 {{use '?' instead}} +// expected-error@-4 {{could not infer type for placeholder}} +let _ = S<[_!x 3]>() +// expected-error@-1 {{element count must precede inline array element type}} +// expected-warning@-2 {{using '!' here is deprecated; this is an error in the Swift 5 language mode}} +// expected-note@-3 {{use '?' instead}} +// expected-error@-4 {{could not infer type for placeholder}} +let _ = S<[Int?x 3]>() +// expected-error@-1 {{element count must precede inline array element type}} + +func testEllipsis(_ x: Int) { + // Make sure this isn't parsed as ' x ' + let _ = [x...x] +} diff --git a/test/type/inline_array_disabled.swift b/test/type/inline_array_disabled.swift new file mode 100644 index 0000000000000..4f4a790b4c4f7 --- /dev/null +++ b/test/type/inline_array_disabled.swift @@ -0,0 +1,19 @@ +// RUN: %target-typecheck-verify-swift + +// Make sure InlineArray type sugar is disabled by default. +// FIXME: The recovery here really isn't great. +do { + let _: [3 x Int] // expected-note {{to match this opening '['}} + // expected-error@-1 4{{expected}} + // expected-error@-2 4{{consecutive statements on a line must be separated by ';'}} + // expected-warning@-3 2{{is unused}} + // expected-error@-4 {{cannot find 'x' in scope}} + // expected-note@-5 {{add arguments after the type to construct a value of the type}} + // expected-note@-6 {{use '.self' to reference the type object}} +} +do { + let _ = [3 x Int]() + // expected-error@-1 {{cannot call value of non-function type '[Int]'}} + // expected-error@-2 {{expected ',' separator}} + // expected-error@-3 {{cannot find 'x' in scope}} +}