From d9732a050fbb40f5bcf2f0dfe4b963f6f5955cf7 Mon Sep 17 00:00:00 2001 From: Brent Royal-Gordon Date: Tue, 2 Apr 2019 18:26:03 -0700 Subject: [PATCH 1/9] Allow the declaration of static subscripts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In this commit, MyStruct.self[0] parses and typechecks but the solution doesn’t apply correctly. MyStruct[0] gets diagnosed as an error. --- include/swift/AST/DiagnosticsCommon.def | 3 + include/swift/AST/DiagnosticsParse.def | 2 - include/swift/Parse/Parser.h | 3 +- lib/Parse/ParseDecl.cpp | 34 ++++++++---- test/Parse/subscripting.swift | 9 ++- test/attr/attr_override.swift | 73 +++++++++++++++++++++++-- test/decl/subscript/static.swift | 12 ++++ 7 files changed, 116 insertions(+), 20 deletions(-) create mode 100644 test/decl/subscript/static.swift diff --git a/include/swift/AST/DiagnosticsCommon.def b/include/swift/AST/DiagnosticsCommon.def index fb28ed59ad103..3a4b8fc5c58ec 100644 --- a/include/swift/AST/DiagnosticsCommon.def +++ b/include/swift/AST/DiagnosticsCommon.def @@ -84,6 +84,9 @@ ERROR(class_func_not_in_class,none, ERROR(class_var_not_in_class,none, "class properties are only allowed within classes; " "use 'static' to declare a %select{static|requirement fulfilled by either a static or class}0 property", (bool)) +ERROR(class_subscript_not_in_class,none, + "class subscripts are only allowed within classes; " + "use 'static' to declare a %select{static|requirement fulfilled by either a static or class}0 subscript", (bool)) // FIXME: Used by both the parser and the type-checker. ERROR(func_decl_without_brace,PointsToFirstBadToken, diff --git a/include/swift/AST/DiagnosticsParse.def b/include/swift/AST/DiagnosticsParse.def index 03320e3edba70..1444c08a723f2 100644 --- a/include/swift/AST/DiagnosticsParse.def +++ b/include/swift/AST/DiagnosticsParse.def @@ -392,8 +392,6 @@ ERROR(expected_lbrace_subscript_protocol,PointsToFirstBadToken, "{ get set } specifier", ()) ERROR(subscript_without_get,none, "subscript declarations must have a getter", ()) -ERROR(subscript_static,none, - "subscript cannot be marked %0", (StaticSpellingKind)) // initializer ERROR(invalid_nested_init,none, diff --git a/include/swift/Parse/Parser.h b/include/swift/Parse/Parser.h index 1a521c40d03d4..907992199cf32 100644 --- a/include/swift/Parse/Parser.h +++ b/include/swift/Parse/Parser.h @@ -1006,7 +1006,8 @@ class Parser { DeclAttributes &Attributes); ParserResult - parseDeclSubscript(ParseDeclOptions Flags, DeclAttributes &Attributes, + parseDeclSubscript(SourceLoc StaticLoc, StaticSpellingKind StaticSpelling, + ParseDeclOptions Flags, DeclAttributes &Attributes, SmallVectorImpl &Decls); ParserResult diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 8d1f51c47055b..2757873efdd80 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -2870,13 +2870,10 @@ Parser::parseDecl(ParseDeclOptions Flags, break; case tok::kw_subscript: { DeclParsingContext.setCreateSyntax(SyntaxKind::SubscriptDecl); - if (StaticLoc.isValid()) { - diagnose(Tok, diag::subscript_static, StaticSpelling) - .fixItRemove(SourceRange(StaticLoc)); - StaticLoc = SourceLoc(); - } llvm::SmallVector Entries; - DeclResult = parseDeclSubscript(Flags, Attributes, Entries); + DeclResult = parseDeclSubscript(StaticLoc, StaticSpelling, Flags, + Attributes, Entries); + StaticLoc = SourceLoc(); // we handled static if present. if (DeclResult.hasCodeCompletion() && isCodeCompletionFirstPass()) break; std::for_each(Entries.begin(), Entries.end(), Handler); @@ -6277,9 +6274,26 @@ parseDeclProtocol(ParseDeclOptions Flags, DeclAttributes &Attributes) { /// attribute-list? 'subscript' parameter-clause '->' type /// \endverbatim ParserResult -Parser::parseDeclSubscript(ParseDeclOptions Flags, +Parser::parseDeclSubscript(SourceLoc StaticLoc, + StaticSpellingKind StaticSpelling, + ParseDeclOptions Flags, DeclAttributes &Attributes, SmallVectorImpl &Decls) { + assert(StaticLoc.isInvalid() || StaticSpelling != StaticSpellingKind::None); + + if (StaticLoc.isValid()) { + if (Flags.contains(PD_InStruct) || Flags.contains(PD_InEnum) || + Flags.contains(PD_InProtocol)) { + if (StaticSpelling == StaticSpellingKind::KeywordClass) { + diagnose(Tok, diag::class_subscript_not_in_class, + Flags.contains(PD_InProtocol)) + .fixItReplace(StaticLoc, "static"); + + StaticSpelling = StaticSpellingKind::KeywordStatic; + } + } + } + ParserStatus Status; SourceLoc SubscriptLoc = consumeToken(tok::kw_subscript); @@ -6354,7 +6368,7 @@ Parser::parseDeclSubscript(ParseDeclOptions Flags, DeclName name = DeclName(Context, DeclBaseName::createSubscript(), argumentNames); auto *Subscript = new (Context) SubscriptDecl(name, - SourceLoc(), StaticSpellingKind::None, + StaticLoc, StaticSpelling, SubscriptLoc, Indices.get(), ArrowLoc, ElementTy.get(), CurDeclContext, @@ -6402,7 +6416,7 @@ Parser::parseDeclSubscript(ParseDeclOptions Flags, } else { Status |= parseGetSet(Flags, GenericParams, Indices.get(), ElementTy.get(), - accessors, Subscript, /*StaticLoc=*/SourceLoc()); + accessors, Subscript, StaticLoc); } bool Invalid = false; @@ -6413,7 +6427,7 @@ Parser::parseDeclSubscript(ParseDeclOptions Flags, } accessors.record(*this, Subscript, (Invalid || !Status.isSuccess()), - Flags, /*static*/ SourceLoc(), Attributes, + Flags, StaticLoc, Attributes, ElementTy.get(), Indices.get(), Decls); // No need to setLocalDiscriminator because subscripts cannot diff --git a/test/Parse/subscripting.swift b/test/Parse/subscripting.swift index c015ae2558820..376f43386cd42 100644 --- a/test/Parse/subscripting.swift +++ b/test/Parse/subscripting.swift @@ -155,7 +155,7 @@ struct A6 { } struct A7 { - static subscript(a: Int) -> Int { // expected-error {{subscript cannot be marked 'static'}} {{3-10=}} + static subscript(a: Int) -> Int { get { return 42 } @@ -163,7 +163,12 @@ struct A7 { } struct A7b { - class subscript(a: Float) -> Int { // expected-error {{subscript cannot be marked 'class'}} {{3-9=}} + class subscript(a: Float) -> Int { // expected-error {{class subscripts are only allowed within classes; use 'static' to declare a static subscript}} {{3-8=static}} + get { + return 42 + } + } + static subscript(x a: Float) -> Int { get { return 42 } diff --git a/test/attr/attr_override.swift b/test/attr/attr_override.swift index 44d01f3f63308..574c146b61194 100644 --- a/test/attr/attr_override.swift +++ b/test/attr/attr_override.swift @@ -40,7 +40,7 @@ class A { var v9: Int { return 5 } // expected-note{{attempt to override property here}} var v10: Int { return 5 } // expected-note{{attempt to override property here}} - subscript (i: Int) -> String { // expected-note{{potential overridden subscript 'subscript(_:)' here}} + subscript (i: Int) -> String { // expected-note{{potential overridden subscript 'subscript(_:)' here}} expected-note{{potential overridden subscript 'subscript(_:)' here}} get { return "hello" } @@ -49,7 +49,7 @@ class A { } } - subscript (d: Double) -> String { // expected-note{{overridden declaration is here}} expected-note{{potential overridden subscript 'subscript(_:)' here}} + subscript (d: Double) -> String { // expected-note{{overridden declaration is here}} expected-note{{potential overridden subscript 'subscript(_:)' here}} expected-note{{potential overridden subscript 'subscript(_:)' here}} get { return "hello" } @@ -57,16 +57,34 @@ class A { set { } } + + class subscript (i: String) -> String { // expected-note{{overridden declaration is here}} expected-note{{potential overridden subscript 'subscript(_:)' here}} + get { + return "hello" + } + + set { + } + } + + class subscript (a: [Int]) -> String { // expected-note{{potential overridden subscript 'subscript(_:)' here}} + get { + return "hello" + } + + set { + } + } - subscript (i: Int8) -> A { // expected-note{{potential overridden subscript 'subscript(_:)' here}} + subscript (i: Int8) -> A { // expected-note{{potential overridden subscript 'subscript(_:)' here}} expected-note{{potential overridden subscript 'subscript(_:)' here}} get { return self } } - subscript (i: Int16) -> A { // expected-note{{attempt to override subscript here}} expected-note{{potential overridden subscript 'subscript(_:)' here}} + subscript (i: Int16) -> A { // expected-note{{attempt to override subscript here}} expected-note{{potential overridden subscript 'subscript(_:)' here}} expected-note{{potential overridden subscript 'subscript(_:)' here}} get { return self } set { } } - + func overriddenInExtension() {} // expected-note {{overr}} } @@ -123,6 +141,51 @@ class B : A { set { } } + + override class subscript (i: Int) -> String { // expected-error{{subscript does not override any subscript from its superclass}} + get { + return "hello" + } + + set { + } + } + + static subscript (i: String) -> String { // expected-error{{overriding declaration requires an 'override' keyword}} {{10-10=override }} + get { + return "hello" + } + + set { + } + } + + static subscript (i: Double) -> String { + get { + return "hello" + } + + set { + } + } + + override class subscript (a: [Int]) -> String { + get { + return "hello" + } + + set { + } + } + + override subscript (a: [Int]) -> String { // expected-error{{subscript does not override any subscript from its superclass}} + get { + return "hello" + } + + set { + } + } // Covariant override subscript (i: Int8) -> B { diff --git a/test/decl/subscript/static.swift b/test/decl/subscript/static.swift new file mode 100644 index 0000000000000..3c82e36a794c8 --- /dev/null +++ b/test/decl/subscript/static.swift @@ -0,0 +1,12 @@ +// RUN: %target-typecheck-verify-swift + +// FIXME: Write proper tests (this file is mainly suitable for interactive testing) + +struct MyStruct { + static subscript(_ i: Int) -> String { + return "success" + } +} + +//print(MyStruct.self[0]) +//print(MyStruct[0]) From e42939d9bbaecc22282dbd205c0a9c56372fef3d Mon Sep 17 00:00:00 2001 From: Brent Royal-Gordon Date: Tue, 2 Apr 2019 18:26:03 -0700 Subject: [PATCH 2/9] Correctly apply typechecking solutions with subscripts on type instances --- lib/Sema/CSApply.cpp | 25 ++++++++++++++++++++++--- test/decl/subscript/static.swift | 2 +- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index 10554cb9b2027..fdd85a0038e12 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -1376,6 +1376,12 @@ namespace { auto &tc = cs.getTypeChecker(); auto baseTy = cs.getType(base)->getRValueType(); + + bool baseIsInstance = true; + if (auto baseMeta = baseTy->getAs()) { + baseIsInstance = false; + baseTy = baseMeta->getInstanceType(); + } // Check whether the base is 'super'. bool isSuper = base->isSuperExpr(); @@ -1461,9 +1467,22 @@ namespace { auto openedBaseType = getBaseType(openedFullFnType, /*wantsRValue*/ false); auto containerTy = solution.simplifyType(openedBaseType); - base = coerceObjectArgumentToType( - base, containerTy, subscript, AccessSemantics::Ordinary, - locator.withPathElement(ConstraintLocator::MemberRefBase)); + + if (baseIsInstance) { + base = coerceObjectArgumentToType( + base, containerTy, subscript, AccessSemantics::Ordinary, + locator.withPathElement(ConstraintLocator::MemberRefBase)); + } else { + base = coerceToType(base, + MetatypeType::get(containerTy), + locator.withPathElement( + ConstraintLocator::MemberRefBase)); + + if (!base) + return nullptr; + + base = cs.coerceToRValue(base); + } if (!base) return nullptr; diff --git a/test/decl/subscript/static.swift b/test/decl/subscript/static.swift index 3c82e36a794c8..c44117b2f9724 100644 --- a/test/decl/subscript/static.swift +++ b/test/decl/subscript/static.swift @@ -8,5 +8,5 @@ struct MyStruct { } } -//print(MyStruct.self[0]) +print(MyStruct.self[0]) //print(MyStruct[0]) From 7a41c3874bf92cca5991beeef4976ae4262e1260 Mon Sep 17 00:00:00 2001 From: Brent Royal-Gordon Date: Tue, 2 Apr 2019 18:26:03 -0700 Subject: [PATCH 3/9] Permit subscripting types without using .self --- lib/Sema/MiscDiagnostics.cpp | 4 +++- test/decl/subscript/static.swift | 32 ++++++++++++++++++++++++++++---- 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/lib/Sema/MiscDiagnostics.cpp b/lib/Sema/MiscDiagnostics.cpp index f4d7fc418d96a..7b53b112272c5 100644 --- a/lib/Sema/MiscDiagnostics.cpp +++ b/lib/Sema/MiscDiagnostics.cpp @@ -422,6 +422,7 @@ static void diagSyntacticUseRestrictions(TypeChecker &TC, const Expr *E, // Allow references to types as a part of: // - member references T.foo, T.Type, T.self, etc. // - constructor calls T() + // - Subscripts T[] if (auto *ParentExpr = Parent.getAsExpr()) { // This is an exhaustive list of the accepted syntactic forms. if (isa(ParentExpr) || @@ -433,7 +434,8 @@ static void diagSyntacticUseRestrictions(TypeChecker &TC, const Expr *E, isa(ParentExpr) || isa(ParentExpr) || isa(ParentExpr) || - isa(ParentExpr)) { + isa(ParentExpr) || + isa(ParentExpr)) { return; } } diff --git a/test/decl/subscript/static.swift b/test/decl/subscript/static.swift index c44117b2f9724..8c715a64e3198 100644 --- a/test/decl/subscript/static.swift +++ b/test/decl/subscript/static.swift @@ -3,10 +3,34 @@ // FIXME: Write proper tests (this file is mainly suitable for interactive testing) struct MyStruct { - static subscript(_ i: Int) -> String { - return "success" - } + static subscript(_ i: Int) -> String { + get { return "get \(i)" } + set { print("set \(i)") } + } } print(MyStruct.self[0]) -//print(MyStruct[0]) +print(MyStruct[0]) + +MyStruct.self[1] = "zyzyx" +MyStruct[2] = "asdfg" + +@dynamicMemberLookup +class Dyn { + static subscript(dynamicMember name: String) -> String { + return "Dyn.\(name)" + } +} + +print(Dyn.foo) +print(Dyn.bar) + +class Base { + static subscript(_ i: Int) -> String { return "Base" } +} +class DerivedGood: Base { + override static subscript(_ i: Int) -> String { return "DerivedGood" } +} + +print(DerivedGood[0]) + From 0fcb09d9cefd2516e6e217abcca88519871c4b93 Mon Sep 17 00:00:00 2001 From: Brent Royal-Gordon Date: Tue, 2 Apr 2019 18:26:03 -0700 Subject: [PATCH 4/9] Fix description of static subscripts in errors --- include/swift/AST/Decl.h | 2 ++ lib/AST/Decl.cpp | 15 ++++++++++++++- lib/Sema/TypeCheckDeclOverride.cpp | 1 + test/attr/attr_override.swift | 4 ++-- 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index 413c3081a9d63..2f173c204121e 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -139,6 +139,8 @@ enum class DescriptiveDeclKind : uint8_t { GenericClass, GenericType, Subscript, + StaticSubscript, + ClassSubscript, Constructor, Destructor, LocalFunction, diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 330dce61e2f6e..44e6b79f7da11 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -150,7 +150,6 @@ DescriptiveDeclKind Decl::getDescriptiveKind() const { TRIVIAL_KIND(GenericTypeParam); TRIVIAL_KIND(AssociatedType); TRIVIAL_KIND(Protocol); - TRIVIAL_KIND(Subscript); TRIVIAL_KIND(Constructor); TRIVIAL_KIND(Destructor); TRIVIAL_KIND(EnumElement); @@ -188,6 +187,18 @@ DescriptiveDeclKind Decl::getDescriptiveKind() const { } } + case DeclKind::Subscript: { + auto subscript = cast(this); + switch (subscript->getCorrectStaticSpelling()) { + case StaticSpellingKind::None: + return DescriptiveDeclKind::Subscript; + case StaticSpellingKind::KeywordStatic: + return DescriptiveDeclKind::StaticSubscript; + case StaticSpellingKind::KeywordClass: + return DescriptiveDeclKind::ClassSubscript; + } + } + case DeclKind::Accessor: { auto accessor = cast(this); @@ -279,6 +290,8 @@ StringRef Decl::getDescriptiveKindName(DescriptiveDeclKind K) { ENTRY(GenericClass, "generic class"); ENTRY(GenericType, "generic type"); ENTRY(Subscript, "subscript"); + ENTRY(StaticSubscript, "static subscript"); + ENTRY(ClassSubscript, "class subscript"); ENTRY(Constructor, "initializer"); ENTRY(Destructor, "deinitializer"); ENTRY(LocalFunction, "local function"); diff --git a/lib/Sema/TypeCheckDeclOverride.cpp b/lib/Sema/TypeCheckDeclOverride.cpp index d13115f4ce717..184fd4f57f605 100644 --- a/lib/Sema/TypeCheckDeclOverride.cpp +++ b/lib/Sema/TypeCheckDeclOverride.cpp @@ -1684,6 +1684,7 @@ static bool checkSingleOverride(ValueDecl *override, ValueDecl *base) { switch (baseKind) { case DescriptiveDeclKind::StaticProperty: case DescriptiveDeclKind::StaticMethod: + case DescriptiveDeclKind::StaticSubscript: override->diagnose(diag::override_static, baseKind); break; default: diff --git a/test/attr/attr_override.swift b/test/attr/attr_override.swift index 574c146b61194..146e65cd5687f 100644 --- a/test/attr/attr_override.swift +++ b/test/attr/attr_override.swift @@ -58,7 +58,7 @@ class A { } } - class subscript (i: String) -> String { // expected-note{{overridden declaration is here}} expected-note{{potential overridden subscript 'subscript(_:)' here}} + class subscript (i: String) -> String { // expected-note{{overridden declaration is here}} expected-note{{potential overridden class subscript 'subscript(_:)' here}} get { return "hello" } @@ -67,7 +67,7 @@ class A { } } - class subscript (a: [Int]) -> String { // expected-note{{potential overridden subscript 'subscript(_:)' here}} + class subscript (a: [Int]) -> String { // expected-note{{potential overridden class subscript 'subscript(_:)' here}} get { return "hello" } From 8b0e61aae0af1d717291a5cf83c0809ceee7139a Mon Sep 17 00:00:00 2001 From: Brent Royal-Gordon Date: Tue, 2 Apr 2019 18:26:03 -0700 Subject: [PATCH 5/9] Infer final on static subscripts --- lib/Sema/TypeCheckDecl.cpp | 2 +- test/decl/subscript/static.swift | 10 ++++------ 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index 3609dc840fd2c..bc85d1a474d8b 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -4081,7 +4081,7 @@ void TypeChecker::validateDecl(ValueDecl *D) { // Member subscripts need some special validation logic. if (SD->getDeclContext()->isTypeContext()) { // If this is a class member, mark it final if the class is final. - inferFinalAndDiagnoseIfNeeded(*this, SD, StaticSpellingKind::None); + inferFinalAndDiagnoseIfNeeded(*this, SD, SD->getStaticSpelling()); } // Perform accessor-related validation. diff --git a/test/decl/subscript/static.swift b/test/decl/subscript/static.swift index 8c715a64e3198..ff3483c0042db 100644 --- a/test/decl/subscript/static.swift +++ b/test/decl/subscript/static.swift @@ -25,12 +25,10 @@ class Dyn { print(Dyn.foo) print(Dyn.bar) -class Base { - static subscript(_ i: Int) -> String { return "Base" } +class BadBase { + static subscript(_ i: Int) -> String { return "Base" } // expected-note{{overridden declaration is here}} } -class DerivedGood: Base { - override static subscript(_ i: Int) -> String { return "DerivedGood" } +class BadDerived: BadBase { + override static subscript(_ i: Int) -> String { return "DerivedGood" } // expected-error{{cannot override static subscript}} } -print(DerivedGood[0]) - From 473fe7027e1b7fa8ab4ced51550ab47070265bb5 Mon Sep 17 00:00:00 2001 From: Brent Royal-Gordon Date: Tue, 2 Apr 2019 18:26:03 -0700 Subject: [PATCH 6/9] =?UTF-8?q?Make=20sure=20we=20don=E2=80=99t=20support?= =?UTF-8?q?=20@objc=20class=20subscripts?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Obj-C subscripts don’t work on class objects, but you can declare class methods with the appropriate names. We don’t want to half-support this. Emit an error if you try to write “@objc class subscript” and test that we don’t import the methods as subscripts. --- include/swift/AST/DiagnosticsSema.def | 2 ++ lib/Sema/TypeCheckDeclObjC.cpp | 10 ++++++ .../Inputs/custom-modules/ObjCSubscripts.h | 7 ++++ test/ClangImporter/objc_class_subscript.swift | 32 +++++++++++++++++++ test/attr/attr_objc.swift | 9 +++++- test/decl/subscript/static.swift | 1 - 6 files changed, 59 insertions(+), 2 deletions(-) create mode 100644 test/ClangImporter/objc_class_subscript.swift diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index cdc22f3fbd824..823e94fffe188 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -3638,6 +3638,8 @@ ERROR(objc_invalid_on_var,none, ERROR(objc_invalid_on_subscript,none, "subscript cannot be %" OBJC_ATTR_SELECT "0 because its type " "cannot be represented in Objective-C", (unsigned)) +ERROR(objc_invalid_on_static_subscript,none, + "%0 cannot be %" OBJC_ATTR_SELECT "1", (DescriptiveDeclKind, unsigned)) ERROR(objc_invalid_with_generic_params,none, "method cannot be %" OBJC_ATTR_SELECT "0 because it has generic " "parameters", (unsigned)) diff --git a/lib/Sema/TypeCheckDeclObjC.cpp b/lib/Sema/TypeCheckDeclObjC.cpp index 722a8dff81100..7c5546806076a 100644 --- a/lib/Sema/TypeCheckDeclObjC.cpp +++ b/lib/Sema/TypeCheckDeclObjC.cpp @@ -827,6 +827,16 @@ bool swift::isRepresentableInObjC(const SubscriptDecl *SD, ObjCReason Reason) { if (checkObjCInForeignClassContext(SD, Reason)) return false; + // Obj-C doesn't support class subscripts. + if (!SD->isInstanceMember()) { + if (Diagnose) { + SD->diagnose(diag::objc_invalid_on_static_subscript, + SD->getDescriptiveKind(), Reason); + describeObjCReason(SD, Reason); + } + return true; + } + if (!SD->hasInterfaceType()) { SD->getASTContext().getLazyResolver()->resolveDeclSignature( const_cast(SD)); diff --git a/test/ClangImporter/Inputs/custom-modules/ObjCSubscripts.h b/test/ClangImporter/Inputs/custom-modules/ObjCSubscripts.h index f73cda87f52cd..9913759a122c1 100644 --- a/test/ClangImporter/Inputs/custom-modules/ObjCSubscripts.h +++ b/test/ClangImporter/Inputs/custom-modules/ObjCSubscripts.h @@ -60,3 +60,10 @@ @interface KeySubscriptReversedOverrideSetter : KeySubscriptReversedBase - (void)setObject:(id)object forKeyedSubscript:(NSString *)key; @end + +@interface NoClassSubscript : NSObject ++ (id)objectAtIndexedSubscript:(int)i; ++ (void)setObject:(id)obj atIndexedSubscript:(int)i; ++ (id)objectForKeyedSubscript:(NSString *)subscript; ++ (void)setObject:(id)object forKeyedSubscript:(NSString *)key; +@end diff --git a/test/ClangImporter/objc_class_subscript.swift b/test/ClangImporter/objc_class_subscript.swift new file mode 100644 index 0000000000000..e784e00ec5b46 --- /dev/null +++ b/test/ClangImporter/objc_class_subscript.swift @@ -0,0 +1,32 @@ +// RUN: %empty-directory(%t) +// RUN: %build-clang-importer-objc-overlays + +// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk-nosource -I %t) -typecheck -I %S/Inputs/custom-modules %s -verify + +// REQUIRES: objc_interop + +import ObjCSubscripts + +func testClass() { + _ = NoClassSubscript[0] // expected-error{{value of type 'NoClassSubscript.Type' has no subscripts}} + NoClassSubscript[0] = "" // expected-error{{value of type 'NoClassSubscript.Type' has no subscripts}} + + _ = NoClassSubscript["foo"] // expected-error{{value of type 'NoClassSubscript.Type' has no subscripts}} + NoClassSubscript["foo"] = "" // expected-error{{value of type 'NoClassSubscript.Type' has no subscripts}} +} + +func testInstance(x: NoClassSubscript) { + _ = x[0] // expected-error{{value of type 'NoClassSubscript' has no subscripts}} + x[0] = "" // expected-error{{value of type 'NoClassSubscript' has no subscripts}} + + _ = x["foo"] // expected-error{{value of type 'NoClassSubscript' has no subscripts}} + x["foo"] = "" // expected-error{{value of type 'NoClassSubscript' has no subscripts}} +} + +func testClassMethods() { + _ = NoClassSubscript.object(atIndexedSubscript: 0) + NoClassSubscript.setObject("", atIndexedSubscript: 0) + + _ = NoClassSubscript.object(forKeyedSubscript: "foo") + NoClassSubscript.setObject("", forKeyedSubscript: "foo") +} diff --git a/test/attr/attr_objc.swift b/test/attr/attr_objc.swift index 4516b2a0779b3..e0ff04b04c8cc 100644 --- a/test/attr/attr_objc.swift +++ b/test/attr/attr_objc.swift @@ -158,6 +158,8 @@ class subject_class1 { // no-error @objc func subject_instanceFunc() {} // no-error + + } @objc @@ -506,7 +508,12 @@ class subject_subscriptGeneric { } } - +class subject_subscriptInvalid1 { + @objc class subscript(_ i: Int) -> AnyObject? { + // expected-error@-1 {{class subscript cannot be marked @objc}} + return nil + } +} class subject_subscriptInvalid2 { @objc diff --git a/test/decl/subscript/static.swift b/test/decl/subscript/static.swift index ff3483c0042db..8268d069dcbc0 100644 --- a/test/decl/subscript/static.swift +++ b/test/decl/subscript/static.swift @@ -31,4 +31,3 @@ class BadBase { class BadDerived: BadBase { override static subscript(_ i: Int) -> String { return "DerivedGood" } // expected-error{{cannot override static subscript}} } - From eb0d343ea7c0abf9233e5c79d2ce09d02750f465 Mon Sep 17 00:00:00 2001 From: Brent Royal-Gordon Date: Thu, 4 Apr 2019 11:04:03 -0700 Subject: [PATCH 7/9] [ASTPrinter] Print staticness of subscripts --- lib/AST/ASTPrinter.cpp | 3 +++ test/IDE/print_ast_tc_decls.swift | 7 +++++++ 2 files changed, 10 insertions(+) diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index a6a1d4568df20..08433f0124c0d 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -2874,6 +2874,9 @@ void PrintAST::visitSubscriptDecl(SubscriptDecl *decl) { printDocumentationComment(decl); printAttributes(decl); printAccess(decl); + if (!Options.SkipIntroducerKeywords && decl->isStatic() && + Options.PrintStaticKeyword) + printStaticKeyword(decl->getCorrectStaticSpelling()); printContextIfNeeded(decl); recordDeclLoc(decl, [&]{ Printer << "subscript"; diff --git a/test/IDE/print_ast_tc_decls.swift b/test/IDE/print_ast_tc_decls.swift index d61daf31ca756..5002ba7fdbf92 100644 --- a/test/IDE/print_ast_tc_decls.swift +++ b/test/IDE/print_ast_tc_decls.swift @@ -172,6 +172,13 @@ struct d0100_FooStruct { } } // PASS_COMMON-NEXT: {{^}} subscript(i: Int, j: Int) -> Double { get }{{$}} + + static subscript(i: Int) -> Double { + get { + return Double(i) + } + } +// PASS_COMMON-NEXT: {{^}} static subscript(i: Int) -> Double { get }{{$}} func bodyNameVoidFunc1(a: Int, b x: Float) {} // PASS_COMMON-NEXT: {{^}} func bodyNameVoidFunc1(a: Int, b x: Float){{$}} From c37fee1719e40950f7737563d939985353aca121 Mon Sep 17 00:00:00 2001 From: Brent Royal-Gordon Date: Tue, 2 Apr 2019 18:26:03 -0700 Subject: [PATCH 8/9] Add parallel tests for static subscripts This commit modifies various subscript-related test files to add static subscript equivalents of existing tests. --- test/Constraints/subscript.swift | 33 +++ .../generic_subscript_static.swift | 197 ++++++++++++++++++ test/Interpreter/subscripting.swift | 35 +++- test/Parse/subscripting.swift | 37 +++- test/SILGen/dynamic.swift | 25 +++ test/attr/attr_override.swift | 26 +-- test/decl/protocol/req/subscript.swift | 35 +++- test/decl/subscript/generic.swift | 30 +++ test/decl/subscript/static.swift | 30 ++- test/decl/subscript/subscripting.swift | 71 +++++++ 10 files changed, 485 insertions(+), 34 deletions(-) create mode 100644 test/Interpreter/generic_subscript_static.swift diff --git a/test/Constraints/subscript.swift b/test/Constraints/subscript.swift index 4ed7b803b93ad..d8fe7f3f380ed 100644 --- a/test/Constraints/subscript.swift +++ b/test/Constraints/subscript.swift @@ -33,6 +33,39 @@ func existentialSubscript(_ a: IntToStringSubscript) -> String { return a[17] } +// Static of above: + +// Subscript of archetype. +protocol IntToStringStaticSubscript { + static subscript (i : Int) -> String { get } +} + +class LameStaticDictionary { + static subscript (i : Int) -> String { + get { + return String(i) + } + } +} + +func archetypeStaticSubscript< + T : IntToStringStaticSubscript, U : LameStaticDictionary +>(_ t: T.Type, u: U.Type) -> String { + // Subscript an archetype. + if false { return t[17] } + + // Subscript an archetype for which the subscript operator is in a base class. + return u[17] +} + +// Subscript of existential type. +func existentialStaticSubscript( + _ a: IntToStringStaticSubscript.Type +) -> String { + return a[17] +} + + class MyDictionary { subscript (key : Key) -> Value { get {} diff --git a/test/Interpreter/generic_subscript_static.swift b/test/Interpreter/generic_subscript_static.swift new file mode 100644 index 0000000000000..10b6973483b12 --- /dev/null +++ b/test/Interpreter/generic_subscript_static.swift @@ -0,0 +1,197 @@ +//===--- generic_subscript.swift ------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +// RUN: %target-run-simple-swift +// REQUIRES: executable_test +// + +import StdlibUnittest + + +var GenericSubscriptTestSuite = TestSuite("GenericSubscriptStatic") + +var ts: [ObjectIdentifier: Any] = [:] + +struct S : P { + typealias Element = T + static var t: T { + get { + return ts[ObjectIdentifier(self)] as! T + } + set { + ts[ObjectIdentifier(self)] = newValue + } + } + + static subscript(a: (T) -> U, b: (U) -> T) -> U { + get { + print(T.self) + print(U.self) + + return a(t) + } + set { + print(T.self) + print(U.self) + + t = b(newValue) + } + } +} + +protocol P { + associatedtype Element + static subscript(a: (Element) -> U, b: (U) -> Element) -> U { get set } +} + +func increment(p: T.Type) where T.Element == String { + p[{Int($0)!}, {String($0)}] += 1 +} + +GenericSubscriptTestSuite.test("Basic") { + var s = S.self + s.t = "0" + increment(p: s) + expectEqual(s.t, "1") +} + +protocol AnySubscript { + static subscript(k: AnyHashable) -> Any? { get set } +} + +struct AnyDictionary : AnySubscript { + static var dict: [AnyHashable : Any] = [:] + + static subscript(k: AnyHashable) -> Any? { + get { + return dict[k] + } + set { + dict[k] = newValue + } + } +} + +extension AnySubscript { + static subscript(k k: K) -> V? { + get { + return self[k] as! V? + } + set { + self[k] = newValue + } + } +} + +GenericSubscriptTestSuite.test("ProtocolExtensionConcrete") { + var dict = AnyDictionary.self + + func doIt(dict: AnyDictionary.Type) { + dict["a" ] = 0 + dict[k: "a"]! += 1 + } + + doIt(dict: dict) + + expectEqual(dict["a"]! as! Int, 1) + expectEqual(dict[k: "a"]!, 1) +} + +GenericSubscriptTestSuite.test("ProtocolExtensionAbstract") { + var dict = AnyDictionary.self + + func doIt(dict: T.Type) { + dict["a" ] = 0 + dict[k: "a"]! += 1 + } + + doIt(dict: dict) + + expectEqual(dict["a"]! as! Int, 1) + expectEqual(dict[k: "a"]!, 1) +} + +protocol GenericSubscript : AnySubscript { + static subscript(k k: K) -> V? { get set } +} + +extension AnyDictionary : GenericSubscript { } + +GenericSubscriptTestSuite.test("ProtocolExtensionWitness") { + var dict = AnyDictionary.self + + func doIt(dict: T.Type) { + dict["a" ] = 0 + dict[k: "a"]! += 1 + } + + doIt(dict: dict) + + expectEqual(dict["a"]! as! Int, 1) + expectEqual(dict[k: "a"]!, 1) +} + +class EchoBase { + // In EchoDerived, subscript(a:) will be overridden. + class subscript(a a: T) -> String { + get { + return "EchoBase.Type.subscript(a: \(a))" + } + } + + // In EchoDerived, subscript(b:) will be overridden with a super call. + class subscript(b b: T) -> String { + get { + return "EchoBase.Type.subscript(b: \(b))" + } + } + + // In EchoDerived, subscript(c:) will not be overridden. + class subscript(c c: T) -> String { + get { + return "EchoBase.Type.subscript(c: \(c))" + } + } +} + +class EchoDerived: EchoBase { + override class subscript(a a: T) -> String { + get { + return "EchoDerived.Type.subscript(a: \(a))" + } + } + + override class subscript(b b: T) -> String { + get { + return "\(super[b: -b]) EchoDerived.Type.subscript(b: \(b))" + } + } + + class subscript(d d: T) -> String { + return "EchoDerived.Type.subscript(d: \(d))" + } +} + +GenericSubscriptTestSuite.test("Overrides") { + let base = EchoBase.self + let derived = EchoDerived.self + + expectEqual(base[a: 42], "EchoBase.Type.subscript(a: 42)") + expectEqual(base[b: 42], "EchoBase.Type.subscript(b: 42)") + expectEqual(base[c: 42], "EchoBase.Type.subscript(c: 42)") + + expectEqual(derived[a: 42], "EchoDerived.Type.subscript(a: 42)") + expectEqual(derived[b: 42], "EchoBase.Type.subscript(b: -42) EchoDerived.Type.subscript(b: 42)") + expectEqual(derived[c: 42], "EchoBase.Type.subscript(c: 42)") + expectEqual(derived[d: 42], "EchoDerived.Type.subscript(d: 42)") +} + +runAllTests() diff --git a/test/Interpreter/subscripting.swift b/test/Interpreter/subscripting.swift index 888b13181763a..269c280bc6e95 100644 --- a/test/Interpreter/subscripting.swift +++ b/test/Interpreter/subscripting.swift @@ -4,17 +4,28 @@ // Check that subscripts and functions named subscript can exist side-by-side struct Foo { subscript() -> String { - return "subscript" + return "instance subscript" } func `subscript`() -> String { - return "func" + return "instance func" + } + + static subscript() -> String { + return "static subscript" + } + + static func `subscript`() -> String { + return "static func" } } let f = Foo() -print(f[]) // CHECK: subscript -print(f.subscript()) // CHECK: func +print(f[]) // CHECK: instance subscript +print(f.subscript()) // CHECK: instance func +print(Foo[]) // CHECK: static subscript +print(Foo.subscript()) // CHECK: static func + // SR-7418 @@ -40,3 +51,19 @@ func foo(_ t: inout T) { var q = Q() foo(&q) // CHECK: I survived + +protocol PStatic { + static subscript(_: T) -> Int { get set } +} + +struct QStatic : PStatic { + static subscript(_ idx: T) -> Int { + get { return 0 } set { idx.foo() } + } +} +func fooStatic(_ t: T.Type) { + t[Idx()] += 1 +} + +fooStatic(QStatic.self) // CHECK: I survived + diff --git a/test/Parse/subscripting.swift b/test/Parse/subscripting.swift index 376f43386cd42..e2b52e5091818 100644 --- a/test/Parse/subscripting.swift +++ b/test/Parse/subscripting.swift @@ -57,6 +57,32 @@ struct X4 { } } +struct X5 { + static var stored: Int = 1 + + static subscript(i: Int) -> Int { + get { + return stored + i + } + set { + stored = newValue - i + } + } +} + +class X6 { + static var stored: Int = 1 + + class subscript(i: Int) -> Int { + get { + return stored + i + } + set { + stored = newValue - i + } + } +} + struct Y1 { var stored: Int subscript(_: i, j: Int) -> Int { // expected-error {{use of undeclared type 'i'}} @@ -155,20 +181,15 @@ struct A6 { } struct A7 { - static subscript(a: Int) -> Int { + class subscript(a: Float) -> Int { // expected-error {{class subscripts are only allowed within classes; use 'static' to declare a static subscript}} {{3-8=static}} get { return 42 } } } -struct A7b { - class subscript(a: Float) -> Int { // expected-error {{class subscripts are only allowed within classes; use 'static' to declare a static subscript}} {{3-8=static}} - get { - return 42 - } - } - static subscript(x a: Float) -> Int { +class A7b { + class static subscript(a: Float) -> Int { // expected-error {{'static' specified twice}} {{9-16=}} get { return 42 } diff --git a/test/SILGen/dynamic.swift b/test/SILGen/dynamic.swift index f06cb311c4681..9b20cc7276103 100644 --- a/test/SILGen/dynamic.swift +++ b/test/SILGen/dynamic.swift @@ -19,6 +19,10 @@ class Foo: Proto { get { return native } set {} } + class subscript(nativeType nativeType: Int) -> Int { + get { return nativeType } + set {} + } // @objc, so it has an ObjC entry point but can also be dispatched // by vtable @@ -48,6 +52,7 @@ protocol Proto { func nativeMethod() var nativeProp: Int { get set } subscript(native native: Int) -> Int { get set } + static subscript(nativeType nativeType: Int) -> Int { get set } func objcMethod() var objcProp: Int { get set } @@ -100,6 +105,10 @@ protocol Proto { // CHECK: class_method {{%.*}} : $Foo, #Foo.subscript!getter.1 : // CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s7dynamic3FooCAA5ProtoA2aDP6nativeS2i_tcisTW // CHECK: class_method {{%.*}} : $Foo, #Foo.subscript!setter.1 : +// CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s7dynamic3FooCAA5ProtoA2aDP10nativeTypeS2i_tcigZTW +// CHECK: class_method {{%.*}} : $@thick Foo.Type, #Foo.subscript!getter.1 : +// CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s7dynamic3FooCAA5ProtoA2aDP10nativeTypeS2i_tcisZTW +// CHECK: class_method {{%.*}} : $@thick Foo.Type, #Foo.subscript!setter.1 : // @objc witnesses use vtable dispatch: // CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s7dynamic3FooCAA5ProtoA2aDP10objcMethod{{[_0-9a-zA-Z]*}}FTW @@ -172,6 +181,15 @@ class Subclass: Foo { // CHECK: function_ref @$s7dynamic3FooC6nativeS2i_tcis : $@convention(method) (Int, Int, @guaranteed Foo) -> () } + override class subscript(nativeType nativeType: Int) -> Int { + get { return super[nativeType: nativeType] } + // CHECK-LABEL: sil hidden [ossa] @$s7dynamic8SubclassC10nativeTypeS2i_tcigZ + // CHECK: function_ref @$s7dynamic3FooC10nativeTypeS2i_tcigZ : $@convention(method) (Int, @thick Foo.Type) -> Int + set { super[nativeType: nativeType] = newValue } + // CHECK-LABEL: sil hidden [ossa] @$s7dynamic8SubclassC10nativeTypeS2i_tcisZ + // CHECK: function_ref @$s7dynamic3FooC10nativeTypeS2i_tcisZ : $@convention(method) (Int, Int, @thick Foo.Type) -> () + } + override init(objc: Int) { super.init(objc: objc) } @@ -267,6 +285,10 @@ func nativeMethodDispatch() { let y = c[native: 0] // CHECK: class_method {{%.*}} : $Foo, #Foo.subscript!setter.1 : c[native: 0] = y + // CHECK: class_method {{%.*}} : $@thick Foo.Type, #Foo.subscript!getter.1 : + let z = type(of: c)[nativeType: 0] + // CHECK: class_method {{%.*}} : $@thick Foo.Type, #Foo.subscript!setter.1 : + type(of: c)[nativeType: 0] = z } // CHECK-LABEL: sil hidden [ossa] @$s7dynamic18objcMethodDispatchyyF : $@convention(thin) () -> () @@ -507,6 +529,9 @@ public class ConcreteDerived : GenericBase { // CHECK-NEXT: #Foo.subscript!getter.1: {{.*}} : @$s7dynamic3FooC6nativeS2i_tcig // dynamic.Foo.subscript.getter : (native: Swift.Int) -> Swift.Int // CHECK-NEXT: #Foo.subscript!setter.1: {{.*}} : @$s7dynamic3FooC6nativeS2i_tcis // dynamic.Foo.subscript.setter : (native: Swift.Int) -> Swift.Int // CHECK-NEXT: #Foo.subscript!modify.1: +// CHECK-NEXT: #Foo.subscript!getter.1: {{.*}} : @$s7dynamic3FooC10nativeTypeS2i_tcigZ // static dynamic.Foo.subscript.getter : (nativeType: Swift.Int) -> Swift.Int +// CHECK-NEXT: #Foo.subscript!setter.1: {{.*}} : @$s7dynamic3FooC10nativeTypeS2i_tcisZ // static dynamic.Foo.subscript.setter : (nativeType: Swift.Int) -> Swift.Int +// CHECK-NEXT: #Foo.subscript!modify.1: // CHECK-NEXT: #Foo.init!allocator.1: {{.*}} : @$s7dynamic3FooC4objcACSi_tcfC // CHECK-NEXT: #Foo.objcMethod!1: {{.*}} : @$s7dynamic3FooC10objcMethodyyF // CHECK-NEXT: #Foo.objcProp!getter.1: {{.*}} : @$s7dynamic3FooC8objcPropSivg // dynamic.Foo.objcProp.getter : Swift.Int diff --git a/test/attr/attr_override.swift b/test/attr/attr_override.swift index 146e65cd5687f..c9b051ee4377d 100644 --- a/test/attr/attr_override.swift +++ b/test/attr/attr_override.swift @@ -40,7 +40,7 @@ class A { var v9: Int { return 5 } // expected-note{{attempt to override property here}} var v10: Int { return 5 } // expected-note{{attempt to override property here}} - subscript (i: Int) -> String { // expected-note{{potential overridden subscript 'subscript(_:)' here}} expected-note{{potential overridden subscript 'subscript(_:)' here}} + subscript (i: Int) -> String { // expected-note{{potential overridden subscript 'subscript(_:)' here}} get { return "hello" } @@ -49,7 +49,7 @@ class A { } } - subscript (d: Double) -> String { // expected-note{{overridden declaration is here}} expected-note{{potential overridden subscript 'subscript(_:)' here}} expected-note{{potential overridden subscript 'subscript(_:)' here}} + subscript (d: Double) -> String { // expected-note{{overridden declaration is here}} expected-note{{potential overridden subscript 'subscript(_:)' here}} get { return "hello" } @@ -58,7 +58,8 @@ class A { } } - class subscript (i: String) -> String { // expected-note{{overridden declaration is here}} expected-note{{potential overridden class subscript 'subscript(_:)' here}} + // FIXME(SR-10323): The second note is wrong; it should be "potential overridden class subscript 'subscript(_:)' here". This is a preexisting bug. + class subscript (i: String) -> String { // expected-note{{overridden declaration is here}} expected-note{{attempt to override subscript here}} get { return "hello" } @@ -67,7 +68,7 @@ class A { } } - class subscript (a: [Int]) -> String { // expected-note{{potential overridden class subscript 'subscript(_:)' here}} + class subscript (typeInSuperclass a: [Int]) -> String { get { return "hello" } @@ -76,15 +77,15 @@ class A { } } - subscript (i: Int8) -> A { // expected-note{{potential overridden subscript 'subscript(_:)' here}} expected-note{{potential overridden subscript 'subscript(_:)' here}} + subscript (i: Int8) -> A { // expected-note{{potential overridden subscript 'subscript(_:)' here}} get { return self } } - subscript (i: Int16) -> A { // expected-note{{attempt to override subscript here}} expected-note{{potential overridden subscript 'subscript(_:)' here}} expected-note{{potential overridden subscript 'subscript(_:)' here}} + subscript (i: Int16) -> A { // expected-note{{attempt to override subscript here}} expected-note{{potential overridden subscript 'subscript(_:)' here}} get { return self } set { } } - + func overriddenInExtension() {} // expected-note {{overr}} } @@ -142,7 +143,8 @@ class B : A { } } - override class subscript (i: Int) -> String { // expected-error{{subscript does not override any subscript from its superclass}} + // FIXME(SR-10323): This error is wrong; it should be "subscript does not override any subscript from its superclass". This is a preexisting bug. + override class subscript (i: Int) -> String { // expected-error{{cannot override mutable subscript of type '(Int) -> String' with covariant type '(String) -> String'}} get { return "hello" } @@ -169,7 +171,7 @@ class B : A { } } - override class subscript (a: [Int]) -> String { + override class subscript (typeInSuperclass a: [Int]) -> String { get { return "hello" } @@ -177,12 +179,12 @@ class B : A { set { } } - - override subscript (a: [Int]) -> String { // expected-error{{subscript does not override any subscript from its superclass}} + + override subscript (typeInSuperclass a: [Int]) -> String { // expected-error{{subscript does not override any subscript from its superclass}} get { return "hello" } - + set { } } diff --git a/test/decl/protocol/req/subscript.swift b/test/decl/protocol/req/subscript.swift index dbe67b3456c32..5f5e50b5d54d2 100644 --- a/test/decl/protocol/req/subscript.swift +++ b/test/decl/protocol/req/subscript.swift @@ -38,11 +38,12 @@ struct S1Error : P1 { // expected-error{{type 'S1Error' does not conform to prot protocol SubscriptGet { - subscript(a : Int) -> Int { get } + subscript(a : Int) -> Int { get } // expected-note {{protocol requires subscript with type '(Int) -> Int'; do you want to add a stub?}} } class SubscriptGet_Get : SubscriptGet { subscript(a : Int) -> Int { return 0 } // ok + // for static cross-conformance test below: expected-note@-1 {{candidate operates on an instance, not a type as required}} } class SubscriptGet_GetSet : SubscriptGet { @@ -92,3 +93,35 @@ struct GenericSubscriptWitness : GenericSubscriptProtocol { struct GenericSubscriptNoWitness : GenericSubscriptProtocol {} // expected-error@-1 {{type 'GenericSubscriptNoWitness' does not conform to protocol 'GenericSubscriptProtocol'}} + +//===----------------------------------------------------------------------===// +// Static subscript requirements +//===----------------------------------------------------------------------===// + +protocol StaticSubscriptGet { + static subscript(a : Int) -> Int { get } // expected-note {{protocol requires subscript with type '(Int) -> Int'; do you want to add a stub?}} +} + +class StaticSubscriptGet_Get : StaticSubscriptGet { + static subscript(a : Int) -> Int { return 0 } // ok + // for static cross-conformance test below: expected-note@-1 {{candidate operates on a type, not an instance as required}} +} + +class StaticSubscriptGet_GetSet : StaticSubscriptGet { + static subscript(a : Int) -> Int { get { return 42 } set {} } // ok +} + +protocol StaticSubscriptGetSet { + static subscript(a : Int) -> Int { get set } // expected-note {{protocol requires subscript with type '(Int) -> Int'}} +} + +class StaticSubscriptGetSet_Get : StaticSubscriptGetSet { // expected-error {{type 'StaticSubscriptGetSet_Get' does not conform to protocol 'StaticSubscriptGetSet'}} + static subscript(a : Int) -> Int { return 0 } // expected-note {{candidate is not settable, but protocol requires it}} +} + +class StaticSubscriptGetSet_GetSet : StaticSubscriptGetSet { + static subscript(a : Int) -> Int { get { return 42 } set {} } // ok +} + +extension SubscriptGet_Get: StaticSubscriptGet {} // expected-error {{type 'SubscriptGet_Get' does not conform to protocol 'StaticSubscriptGet'}} +extension StaticSubscriptGet_Get: SubscriptGet {} // expected-error {{type 'StaticSubscriptGet_Get' does not conform to protocol 'SubscriptGet'}} diff --git a/test/decl/subscript/generic.swift b/test/decl/subscript/generic.swift index da83c6f87a191..2f8c8bb16bba2 100644 --- a/test/decl/subscript/generic.swift +++ b/test/decl/subscript/generic.swift @@ -33,3 +33,33 @@ struct GenericType { return factory.init() } } + +struct StaticConcreteType { + static let c: [Int] = [] + + // Generic index type + static subscript(indices: C) -> [Int] + where C.Iterator.Element == Int { + return indices.map { c[$0] } + } + + // Generic element type + static subscript(factory: I.Type) -> I { + return factory.init() + } +} + +struct StaticGenericType { + static var c: T { fatalError() } + + // Generic index type + static subscript(indices: C) -> [T.Iterator.Element] + where C.Iterator.Element == T.Index { + return indices.map { c[$0] } + } + + // Generic element type + static subscript(factory: I.Type) -> I { + return factory.init() + } +} diff --git a/test/decl/subscript/static.swift b/test/decl/subscript/static.swift index 8268d069dcbc0..79e6aa0f437ad 100644 --- a/test/decl/subscript/static.swift +++ b/test/decl/subscript/static.swift @@ -1,19 +1,29 @@ // RUN: %target-typecheck-verify-swift -// FIXME: Write proper tests (this file is mainly suitable for interactive testing) - struct MyStruct { static subscript(_ i: Int) -> String { get { return "get \(i)" } - set { print("set \(i)") } + set { print("set \(i) = \(newValue)") } } } -print(MyStruct.self[0]) -print(MyStruct[0]) +func useMyStruct() { + print(MyStruct.self[0]) + print(MyStruct[0]) -MyStruct.self[1] = "zyzyx" -MyStruct[2] = "asdfg" + MyStruct.self[1] = "zyzyx" + MyStruct[2] = "asdfg" + + MyStruct()[0] // expected-error {{static member 'subscript' cannot be used on instance of type 'MyStruct'}} + MyStruct()[1] = "zyzyx" // expected-error {{static member 'subscript' cannot be used on instance of type 'MyStruct'}} +} + +struct BadStruct { + static subscript(_ i: Int) -> String { + nonmutating get { fatalError() } // expected-error{{static functions must not be declared mutating}} + mutating set { fatalError() } // expected-error{{static functions must not be declared mutating}} + } +} @dynamicMemberLookup class Dyn { @@ -22,8 +32,10 @@ class Dyn { } } -print(Dyn.foo) -print(Dyn.bar) +func useDyn() { + _ = Dyn.foo + _ = Dyn().bar // expected-error{{static member 'bar' cannot be used on instance of type 'Dyn'}} +} class BadBase { static subscript(_ i: Int) -> String { return "Base" } // expected-note{{overridden declaration is here}} diff --git a/test/decl/subscript/subscripting.swift b/test/decl/subscript/subscripting.swift index 3af6e60089898..89ec1e5bddadc 100644 --- a/test/decl/subscript/subscripting.swift +++ b/test/decl/subscript/subscripting.swift @@ -56,6 +56,38 @@ struct X4 { } } +struct X5 { + static var stored : Int = 1 + + static subscript (i : Int) -> Int { + get { + return stored + i + } + set { + stored = newValue - i + } + } +} + +class X6 { + static var stored : Int = 1 + + class subscript (i : Int) -> Int { + get { + return stored + i + } + set { + stored = newValue - i + } + } +} + +protocol XP1 { + subscript (i : Int) -> Int { get set } + static subscript (i : Int) -> Int { get set } +} + + // Semantic errors struct Y1 { var x : X @@ -84,6 +116,24 @@ class Y3 { } } +class Y4 { + var x = X() + + static subscript(idx: Int) -> X { + get { return x } // expected-error {{instance member 'x' cannot be used on type 'Y4'}} + set {} + } +} + +class Y5 { + static var x = X() + + subscript(idx: Int) -> X { + get { return x } // expected-error {{static member 'x' cannot be used on instance of type 'Y5'}} + set {} + } +} + protocol ProtocolGetSet0 { subscript(i: Int) -> Int {} // expected-error {{subscript declarations must have a getter}} @@ -199,6 +249,27 @@ func test_subscript(_ x2: inout X2, i: Int, j: Int, value: inout Int, no: NoSubs value = ret[i] ret[i] = value + + X5[i] = value + value = X5[i] +} + +func test_proto_static( + i: Int, value: inout Int, + existential: inout XP1, + generic: inout XP1Type + ) { + existential[i] = value + value = existential[i] + + type(of: existential)[i] = value + value = type(of: existential)[i] + + generic[i] = value + value = generic[i] + + XP1Type[i] = value + value = XP1Type[i] } func subscript_rvalue_materialize(_ i: inout Int) { From 7ae331dbca73e72bfdcf873b15826b8d316f831b Mon Sep 17 00:00:00 2001 From: Brent Royal-Gordon Date: Mon, 8 Apr 2019 13:12:32 -0700 Subject: [PATCH 9/9] [NFC] Pick a few nits for Jordan --- lib/Sema/TypeCheckDeclObjC.cpp | 2 +- test/Constraints/subscript.swift | 8 ++++---- test/Interpreter/SDK/dictionary_pattern_matching.swift | 10 +++++----- test/Interpreter/generic_subscript_static.swift | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/lib/Sema/TypeCheckDeclObjC.cpp b/lib/Sema/TypeCheckDeclObjC.cpp index 7c5546806076a..b383fcf2bb236 100644 --- a/lib/Sema/TypeCheckDeclObjC.cpp +++ b/lib/Sema/TypeCheckDeclObjC.cpp @@ -827,7 +827,7 @@ bool swift::isRepresentableInObjC(const SubscriptDecl *SD, ObjCReason Reason) { if (checkObjCInForeignClassContext(SD, Reason)) return false; - // Obj-C doesn't support class subscripts. + // ObjC doesn't support class subscripts. if (!SD->isInstanceMember()) { if (Diagnose) { SD->diagnose(diag::objc_invalid_on_static_subscript, diff --git a/test/Constraints/subscript.swift b/test/Constraints/subscript.swift index d8fe7f3f380ed..4e2485203a804 100644 --- a/test/Constraints/subscript.swift +++ b/test/Constraints/subscript.swift @@ -11,7 +11,7 @@ protocol IntToStringSubscript { subscript (i : Int) -> String { get } } -class LameDictionary { +class FauxDictionary { subscript (i : Int) -> String { get { return String(i) @@ -19,7 +19,7 @@ class LameDictionary { } } -func archetypeSubscript(_ t: T, u: U) +func archetypeSubscript(_ t: T, u: U) -> String { // Subscript an archetype. if false { return t[17] } @@ -40,7 +40,7 @@ protocol IntToStringStaticSubscript { static subscript (i : Int) -> String { get } } -class LameStaticDictionary { +class FauxStaticDictionary { static subscript (i : Int) -> String { get { return String(i) @@ -49,7 +49,7 @@ class LameStaticDictionary { } func archetypeStaticSubscript< - T : IntToStringStaticSubscript, U : LameStaticDictionary + T : IntToStringStaticSubscript, U : FauxStaticDictionary >(_ t: T.Type, u: U.Type) -> String { // Subscript an archetype. if false { return t[17] } diff --git a/test/Interpreter/SDK/dictionary_pattern_matching.swift b/test/Interpreter/SDK/dictionary_pattern_matching.swift index 7a98652806c95..b7b25cb928e48 100644 --- a/test/Interpreter/SDK/dictionary_pattern_matching.swift +++ b/test/Interpreter/SDK/dictionary_pattern_matching.swift @@ -11,7 +11,7 @@ struct State { let abbrev: String } -func stateFromPlistLame(_ plist: Dictionary) -> State? { +func stateFromPlistVerbose(_ plist: Dictionary) -> State? { if let name = plist["name"] as? NSString { if let population = plist["population"] as? NSNumber { if let abbrev = plist["abbrev"] as? NSString { @@ -62,22 +62,22 @@ let invalidStatePlist3: Dictionary = [ // CHECK: name: "California" // CHECK: population: 38040000 // CHECK: abbrev: "CA" -dump(stateFromPlistLame(goodStatePlist)) +dump(stateFromPlistVerbose(goodStatePlist)) // CHECK-LABEL: some: // CHECK: name: "California" // CHECK: population: 38040000 // CHECK: abbrev: "CA" dump(stateFromPlistCool(goodStatePlist)) // CHECK-LABEL: nil -dump(stateFromPlistLame(invalidStatePlist1)) +dump(stateFromPlistVerbose(invalidStatePlist1)) // CHECK-LABEL: nil dump(stateFromPlistCool(invalidStatePlist1)) // CHECK-LABEL: nil -dump(stateFromPlistLame(invalidStatePlist2)) +dump(stateFromPlistVerbose(invalidStatePlist2)) // CHECK-LABEL: nil dump(stateFromPlistCool(invalidStatePlist2)) // CHECK-LABEL: nil -dump(stateFromPlistLame(invalidStatePlist3)) +dump(stateFromPlistVerbose(invalidStatePlist3)) // CHECK-LABEL: nil dump(stateFromPlistCool(invalidStatePlist3)) diff --git a/test/Interpreter/generic_subscript_static.swift b/test/Interpreter/generic_subscript_static.swift index 10b6973483b12..77fb6f117c53a 100644 --- a/test/Interpreter/generic_subscript_static.swift +++ b/test/Interpreter/generic_subscript_static.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information