From ecda0757926e242f6022b7010c7ec2c6fe0b7cb1 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Wed, 22 Feb 2017 20:32:35 -0800 Subject: [PATCH 1/3] AST: Fix signature of GenericParamList::create() --- include/swift/AST/Decl.h | 2 +- lib/AST/Decl.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index fa2f32fe5db52..8300e36e5e772 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -1213,7 +1213,7 @@ class GenericParamList final : SourceLoc LAngleLoc, ArrayRef Params, SourceLoc WhereLoc, - MutableArrayRef Requirements, + ArrayRef Requirements, SourceLoc RAngleLoc); MutableArrayRef getParams() { diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index e491cc17fab94..659b85a1d8264 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -496,7 +496,7 @@ GenericParamList::create(const ASTContext &Context, SourceLoc LAngleLoc, ArrayRef Params, SourceLoc WhereLoc, - MutableArrayRef Requirements, + ArrayRef Requirements, SourceLoc RAngleLoc) { unsigned Size = totalSizeToAlloc(Params.size()); void *Mem = Context.Allocate(Size, alignof(GenericParamList)); From fdb0a18647c8bf9b3027476bd877f25ef446604e Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Wed, 22 Feb 2017 15:26:56 -0800 Subject: [PATCH 2/3] AST: Add a GenericParamList::clone() method This will be immediately needed for generic subscripts, and also for fixing the remaining cases where initializer inheritance doesn't work. --- include/swift/AST/Decl.h | 7 +++++ lib/AST/Decl.cpp | 62 +++++++++++++++++++++++++++++++++++++++- lib/AST/Type.cpp | 3 +- lib/Parse/ParseDecl.cpp | 21 ++++++++++++++ 4 files changed, 91 insertions(+), 2 deletions(-) diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index 8300e36e5e772..1fddf63df99e9 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -1332,6 +1332,11 @@ class GenericParamList final : return depth; } + /// Create a copy of the generic parameter list and all of its generic + /// parameter declarations. The copied generic parameters are re-parented + /// to the given DeclContext. + GenericParamList *clone(DeclContext *dc) const; + void print(raw_ostream &OS); void dump(); }; @@ -2501,6 +2506,8 @@ class GenericTypeParamDecl : public AbstractTypeParamDecl { unsigned Index : 16; public: + static const unsigned InvalidDepth = 0xFFFF; + /// Construct a new generic type parameter. /// /// \param dc The DeclContext in which the generic type parameter's owner diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 659b85a1d8264..b6eeb2b36c32b 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -506,6 +506,66 @@ GenericParamList::create(const ASTContext &Context, RAngleLoc); } +GenericParamList * +GenericParamList::clone(DeclContext *dc) const { + auto &ctx = dc->getASTContext(); + SmallVector params; + for (auto param : getParams()) { + auto *newParam = new (ctx) GenericTypeParamDecl( + dc, param->getName(), param->getNameLoc(), + GenericTypeParamDecl::InvalidDepth, + param->getIndex()); + params.push_back(newParam); + + SmallVector inherited; + for (auto loc : param->getInherited()) + inherited.push_back(loc.clone(ctx)); + newParam->setInherited(ctx.AllocateCopy(inherited)); + } + + SmallVector requirements; + for (auto reqt : getRequirements()) { + switch (reqt.getKind()) { + case RequirementReprKind::TypeConstraint: { + auto first = reqt.getSubjectLoc(); + auto second = reqt.getConstraintLoc(); + reqt = RequirementRepr::getTypeConstraint( + first.clone(ctx), + reqt.getColonLoc(), + second.clone(ctx)); + break; + } + case RequirementReprKind::SameType: { + auto first = reqt.getFirstTypeLoc(); + auto second = reqt.getSecondTypeLoc(); + reqt = RequirementRepr::getSameType( + first.clone(ctx), + reqt.getEqualLoc(), + second.clone(ctx)); + break; + } + case RequirementReprKind::LayoutConstraint: { + auto first = reqt.getSubjectLoc(); + auto layout = reqt.getLayoutConstraintLoc(); + reqt = RequirementRepr::getLayoutConstraint( + first.clone(ctx), + reqt.getColonLoc(), + layout); + break; + } + } + + requirements.push_back(reqt); + } + + return GenericParamList::create(ctx, + getLAngleLoc(), + params, + getWhereLoc(), + requirements, + getRAngleLoc()); +} + void GenericParamList::addTrailingWhereClause( ASTContext &ctx, SourceLoc trailingWhereLoc, @@ -3812,7 +3872,7 @@ ParamDecl::ParamDecl(ParamDecl *PD) DefaultValueAndIsVariadic(nullptr, PD->DefaultValueAndIsVariadic.getInt()), IsTypeLocImplicit(PD->IsTypeLocImplicit), defaultArgumentKind(PD->defaultArgumentKind) { - typeLoc = PD->getTypeLoc(); + typeLoc = PD->getTypeLoc().clone(PD->getASTContext()); if (PD->hasInterfaceType()) setInterfaceType(PD->getInterfaceType()); } diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 1a4288d2249cf..521fcb2869351 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -1181,7 +1181,8 @@ CanType TypeBase::getCanonicalType() { case TypeKind::GenericTypeParam: { GenericTypeParamType *gp = cast(this); auto gpDecl = gp->getDecl(); - assert(gpDecl->getDepth() != 0xFFFF && "parameter hasn't been validated"); + assert(gpDecl->getDepth() != GenericTypeParamDecl::InvalidDepth && + "parameter hasn't been validated"); Result = GenericTypeParamType::get(gpDecl->getDepth(), gpDecl->getIndex(), gpDecl->getASTContext()); break; diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 5ee406f13c870..4d9760a8ebb4f 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -4219,6 +4219,27 @@ void Parser::ParsedAccessors::record(Parser &P, AbstractStorageDecl *storage, } } + #if 0 + // Subscript accessors are not logically nested inside the subscript, + // once all the accessors are in place, we must clone the subscript's + // generic parameter list for each accessor. + if (auto *subscript = dyn_cast(storage)) { + if (auto *genericParams = subscript->getGenericParams()) { + auto prepareSubscriptAccessor = [&](FuncDecl *func) { + if (func) + func->setGenericParams(genericParams->clone(func)); + }; + + prepareSubscriptAccessor(Get); + prepareSubscriptAccessor(Set); + prepareSubscriptAccessor(Addressor); + prepareSubscriptAccessor(MutableAddressor); + prepareSubscriptAccessor(WillSet); + prepareSubscriptAccessor(DidSet); + } + } + #endif + if (Set || Get) { if (attrs.hasAttribute()) // Turn this into a stored property with trivial accessors. From 928a74c47ed9230f1b6ba9325bbf75834b1bca17 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Sun, 19 Feb 2017 20:34:28 -0800 Subject: [PATCH 3/3] Parse: Support for generic subscripts --- include/swift/Parse/Parser.h | 8 +- lib/Parse/ParseDecl.cpp | 106 +++++++++++------- lib/Parse/ParseGeneric.cpp | 8 +- lib/Sema/CodeSynthesis.cpp | 12 +- lib/Sema/TypeCheckGeneric.cpp | 6 +- .../invalid_constraint_lookup.swift | 3 +- test/Parse/subscripting.swift | 3 +- test/decl/class/override.swift | 27 +++++ test/decl/protocol/req/properties.swift | 54 +++++++++ test/decl/protocol/req/subscript.swift | 77 +++++-------- test/decl/subscript/generic.swift | 35 ++++++ 11 files changed, 238 insertions(+), 101 deletions(-) create mode 100644 test/decl/protocol/req/properties.swift create mode 100644 test/decl/subscript/generic.swift diff --git a/include/swift/Parse/Parser.h b/include/swift/Parse/Parser.h index d0f9ffcb054d2..5496801008302 100644 --- a/include/swift/Parse/Parser.h +++ b/include/swift/Parse/Parser.h @@ -791,13 +791,17 @@ class Parser { }; bool parseGetSetImpl(ParseDeclOptions Flags, - ParameterList *Indices, TypeLoc ElementTy, + GenericParamList *GenericParams, + ParameterList *Indices, + TypeLoc ElementTy, ParsedAccessors &accessors, SourceLoc &LastValidLoc, SourceLoc StaticLoc, SourceLoc VarLBLoc, SmallVectorImpl &Decls); bool parseGetSet(ParseDeclOptions Flags, - ParameterList *Indices, TypeLoc ElementTy, + GenericParamList *GenericParams, + ParameterList *Indices, + TypeLoc ElementTy, ParsedAccessors &accessors, SourceLoc StaticLoc, SmallVectorImpl &Decls); void recordAccessors(AbstractStorageDecl *storage, ParseDeclOptions flags, diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 4d9760a8ebb4f..0b449e69f19f3 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -3270,8 +3270,10 @@ ParserResult Parser::parseDeclAssociatedType(Parser::ParseDeclOptions /// This function creates an accessor function (with no body) for a computed /// property or subscript. static FuncDecl *createAccessorFunc(SourceLoc DeclLoc, ParameterList *param, + GenericParamList *GenericParams, + ParameterList *Indices, TypeLoc ElementTy, - ParameterList *Indices, SourceLoc StaticLoc, + SourceLoc StaticLoc, Parser::ParseDeclOptions Flags, AccessorKind Kind, AddressorKind addressorKind, @@ -3399,8 +3401,11 @@ static FuncDecl *createAccessorFunc(SourceLoc DeclLoc, ParameterList *param, /*FIXME FuncLoc=*/DeclLoc, Identifier(), /*NameLoc=*/DeclLoc, /*Throws=*/false, /*ThrowsLoc=*/SourceLoc(), AccessorKeywordLoc, - /*GenericParams=*/nullptr, - Params, ReturnType, P->CurDeclContext); + (GenericParams + ? GenericParams->clone(P->CurDeclContext) + : nullptr), + Params, ReturnType, + P->CurDeclContext); // Non-static set/willSet/didSet/materializeForSet/mutableAddress // default to mutating. get/address default to @@ -3644,7 +3649,9 @@ static void diagnoseRedundantAccessors(Parser &P, SourceLoc loc, /// \brief Parse a get-set clause, optionally containing a getter, setter, /// willSet, and/or didSet clauses. 'Indices' is a paren or tuple pattern, /// specifying the index list for a subscript. -bool Parser::parseGetSetImpl(ParseDeclOptions Flags, ParameterList *Indices, +bool Parser::parseGetSetImpl(ParseDeclOptions Flags, + GenericParamList *GenericParams, + ParameterList *Indices, TypeLoc ElementTy, ParsedAccessors &accessors, SourceLoc &LastValidLoc, SourceLoc StaticLoc, SourceLoc VarLBLoc, @@ -3718,7 +3725,8 @@ bool Parser::parseGetSetImpl(ParseDeclOptions Flags, ParameterList *Indices, = parseOptionalAccessorArgument(Loc, ElementTy, *this, Kind); // Set up a function declaration. - TheDecl = createAccessorFunc(Loc, ValueNameParams, ElementTy, Indices, + TheDecl = createAccessorFunc(Loc, ValueNameParams, + GenericParams, Indices, ElementTy, StaticLoc, Flags, Kind, addressorKind, this, AccessorKeywordLoc); TheDecl->getAttrs() = Attributes; @@ -3849,7 +3857,8 @@ bool Parser::parseGetSetImpl(ParseDeclOptions Flags, ParameterList *Indices, } // Set up a function declaration. - TheDecl = createAccessorFunc(Loc, ValueNamePattern, ElementTy, Indices, + TheDecl = createAccessorFunc(Loc, ValueNamePattern, + GenericParams, Indices, ElementTy, StaticLoc, Flags, Kind, addressorKind, this, AccessorKeywordLoc); TheDecl->getAttrs() = Attributes; @@ -3862,6 +3871,10 @@ bool Parser::parseGetSetImpl(ParseDeclOptions Flags, ParameterList *Indices, for (auto PL : TheDecl->getParameterLists()) addParametersToScope(PL); + if (TheDecl->isGeneric()) + for (auto *GP : TheDecl->getGenericParams()->getParams()) + addToScope(GP); + // Establish the new context. ParseFunctionBody CC(*this, TheDecl); @@ -3896,15 +3909,17 @@ bool Parser::parseGetSetImpl(ParseDeclOptions Flags, ParameterList *Indices, return false; } -bool Parser::parseGetSet(ParseDeclOptions Flags, ParameterList *Indices, +bool Parser::parseGetSet(ParseDeclOptions Flags, + GenericParamList *GenericParams, + ParameterList *Indices, TypeLoc ElementTy, ParsedAccessors &accessors, SourceLoc StaticLoc, SmallVectorImpl &Decls) { accessors.LBLoc = consumeToken(tok::l_brace); SourceLoc LastValidLoc = accessors.LBLoc; - bool Invalid = parseGetSetImpl(Flags, Indices, ElementTy, accessors, - LastValidLoc, StaticLoc, accessors.LBLoc, - Decls); + bool Invalid = parseGetSetImpl(Flags, GenericParams, Indices, ElementTy, + accessors, LastValidLoc, StaticLoc, + accessors.LBLoc, Decls); // Parse the final '}'. if (Invalid) @@ -3990,7 +4005,8 @@ VarDecl *Parser::parseDeclVarGetSet(Pattern *pattern, // Parse getter and setter. ParsedAccessors accessors; - if (parseGetSet(Flags, /*Indices=*/nullptr, TyLoc, accessors, StaticLoc, + if (parseGetSet(Flags, /*GenericParams=*/nullptr, + /*Indices=*/nullptr, TyLoc, accessors, StaticLoc, Decls)) Invalid = true; @@ -4058,11 +4074,16 @@ void Parser::ParsedAccessors::record(Parser &P, AbstractStorageDecl *storage, } }; + GenericParamList *genericParams = nullptr; + if (auto *subscript = dyn_cast(storage)) + genericParams = subscript->getGenericParams(); + // Create an implicit accessor declaration. auto createImplicitAccessor = [&](AccessorKind kind, AddressorKind addressorKind, ParameterList *argList) -> FuncDecl* { - auto accessor = createAccessorFunc(SourceLoc(), argList, elementTy, indices, + auto accessor = createAccessorFunc(SourceLoc(), argList, + genericParams, indices, elementTy, staticLoc, flags, kind, addressorKind, &P, SourceLoc()); accessor->setImplicit(); @@ -4219,27 +4240,6 @@ void Parser::ParsedAccessors::record(Parser &P, AbstractStorageDecl *storage, } } - #if 0 - // Subscript accessors are not logically nested inside the subscript, - // once all the accessors are in place, we must clone the subscript's - // generic parameter list for each accessor. - if (auto *subscript = dyn_cast(storage)) { - if (auto *genericParams = subscript->getGenericParams()) { - auto prepareSubscriptAccessor = [&](FuncDecl *func) { - if (func) - func->setGenericParams(genericParams->clone(func)); - }; - - prepareSubscriptAccessor(Get); - prepareSubscriptAccessor(Set); - prepareSubscriptAccessor(Addressor); - prepareSubscriptAccessor(MutableAddressor); - prepareSubscriptAccessor(WillSet); - prepareSubscriptAccessor(DidSet); - } - } - #endif - if (Set || Get) { if (attrs.hasAttribute()) // Turn this into a stored property with trivial accessors. @@ -5430,7 +5430,7 @@ parseDeclProtocol(ParseDeclOptions Flags, DeclAttributes &Attributes) { /// decl-subscript: /// subscript-head get-set /// subscript-head -/// 'subscript' attribute-list parameter-clause '->' type +/// attribute-list? 'subscript' parameter-clause '->' type /// \endverbatim ParserResult Parser::parseDeclSubscript(ParseDeclOptions Flags, @@ -5439,6 +5439,20 @@ Parser::parseDeclSubscript(ParseDeclOptions Flags, ParserStatus Status; SourceLoc SubscriptLoc = consumeToken(tok::kw_subscript); + // Parse the generic-params, if present. + Optional GenericsScope; + GenericsScope.emplace(this, ScopeKind::Generics); + GenericParamList *GenericParams; + bool GPHasCodeCompletion = false; + + auto Result = maybeParseGenericParams(); + GenericParams = Result.getPtrOrNull(); + GPHasCodeCompletion |= Result.hasCodeCompletion(); + + if (GPHasCodeCompletion && !CodeCompletion) + return makeParserCodeCompletionStatus(); + + // Parse the parameter list. SmallVector argumentNames; ParserResult Indices = parseSingleParameterClause(ParameterContextKind::Subscript, @@ -5459,19 +5473,32 @@ Parser::parseDeclSubscript(ParseDeclOptions Flags, if (ElementTy.isNull() || ElementTy.hasCodeCompletion()) return ParserStatus(ElementTy); - + diagnoseWhereClauseInGenericParamList(GenericParams); + + // Parse a 'where' clause if present, adding it to our GenericParamList. + if (Tok.is(tok::kw_where)) { + auto whereStatus = parseFreestandingGenericWhereClause(GenericParams); + if (whereStatus.shouldStopParsing()) + return whereStatus; + } + // Build an AST for the subscript declaration. DeclName name = DeclName(Context, Context.Id_subscript, argumentNames); auto *Subscript = new (Context) SubscriptDecl(name, SubscriptLoc, Indices.get(), ArrowLoc, ElementTy.get(), CurDeclContext, - /*GenericParams=*/nullptr); + GenericParams); Subscript->getAttrs() = Attributes; - + + // Code completion for the generic type params. + // + // FIXME: What is this? + if (GPHasCodeCompletion) + CodeCompletion->setDelayedParsedDecl(Subscript); + Decls.push_back(Subscript); - // '{' // Parse getter and setter. ParsedAccessors accessors; @@ -5485,7 +5512,8 @@ Parser::parseDeclSubscript(ParseDeclOptions Flags, diagnose(Tok, diag::expected_lbrace_subscript); Status.setIsParseError(); } else { - if (parseGetSet(Flags, Indices.get(), ElementTy.get(), + if (parseGetSet(Flags, GenericParams, + Indices.get(), ElementTy.get(), accessors, /*StaticLoc=*/SourceLoc(), Decls)) Status.setIsParseError(); } diff --git a/lib/Parse/ParseGeneric.cpp b/lib/Parse/ParseGeneric.cpp index 1f9da272363fa..fcf84282519b1 100644 --- a/lib/Parse/ParseGeneric.cpp +++ b/lib/Parse/ParseGeneric.cpp @@ -94,10 +94,10 @@ Parser::parseGenericParameters(SourceLoc LAngleLoc) { // We always create generic type parameters with a depth of zero. // Semantic analysis fills in the depth when it processes the generic // parameter list. - auto Param = new (Context) GenericTypeParamDecl(CurDeclContext, Name, - NameLoc, - /*Bogus depth=*/0xFFFF, - GenericParams.size()); + auto Param = new (Context) GenericTypeParamDecl( + CurDeclContext, Name, NameLoc, + GenericTypeParamDecl::InvalidDepth, + GenericParams.size()); if (!Inherited.empty()) Param->setInherited(Context.AllocateCopy(Inherited)); GenericParams.push_back(Param); diff --git a/lib/Sema/CodeSynthesis.cpp b/lib/Sema/CodeSynthesis.cpp index 8b059a51a1d36..2756738ce7875 100644 --- a/lib/Sema/CodeSynthesis.cpp +++ b/lib/Sema/CodeSynthesis.cpp @@ -326,10 +326,20 @@ static FuncDecl *createMaterializeForSetPrototype(AbstractStorageDecl *storage, }; Type retTy = TupleType::get(retElts, ctx); + // Accessors of generic subscripts get a copy of the subscript's + // generic parameter list, because they're not nested inside the + // subscript. + GenericParamList *genericParams = nullptr; + if (auto *subscript = dyn_cast(storage)) + genericParams = subscript->getGenericParams(); + auto *materializeForSet = FuncDecl::create( ctx, /*StaticLoc=*/SourceLoc(), StaticSpellingKind::None, loc, Identifier(), loc, /*Throws=*/false, /*ThrowsLoc=*/SourceLoc(), - /*AccessorKeywordLoc=*/SourceLoc(), /*GenericParams=*/nullptr, + /*AccessorKeywordLoc=*/SourceLoc(), + (genericParams + ? genericParams->clone(DC) + : nullptr), params, TypeLoc::withoutLoc(retTy), DC); materializeForSet->setImplicit(); diff --git a/lib/Sema/TypeCheckGeneric.cpp b/lib/Sema/TypeCheckGeneric.cpp index 5246eda79a77d..737fa2f314558 100644 --- a/lib/Sema/TypeCheckGeneric.cpp +++ b/lib/Sema/TypeCheckGeneric.cpp @@ -788,7 +788,11 @@ void TypeChecker::configureInterfaceType(AbstractFunctionDecl *func, if (initFuncTy) cast(func)->setInitializerInterfaceType(initFuncTy); - checkReferencedGenericParams(func, sig, *this); + // We get bogus errors here with generic subscript materializeForSet. + if (!isa(func) || + cast(func)->getAccessorKind() != + AccessorKind::IsMaterializeForSet) + checkReferencedGenericParams(func, sig, *this); } /// diff --git a/test/Constraints/invalid_constraint_lookup.swift b/test/Constraints/invalid_constraint_lookup.swift index 4d85c03871a5c..46db4fb5f5498 100644 --- a/test/Constraints/invalid_constraint_lookup.swift +++ b/test/Constraints/invalid_constraint_lookup.swift @@ -9,7 +9,8 @@ func f(_ rhs: U) -> X { // expected-error {{use of undeclared type 'X } struct Zzz { - subscript (a: Foo) -> Zzz { // expected-error {{use of undeclared type 'Foo'}} + // FIXME: Duplicate diagnostics + subscript (a: Foo) -> Zzz { // expected-error 2{{use of undeclared type 'Foo'}} get: // expected-error {{expected '{' to start getter definition}} set: for i in value {} diff --git a/test/Parse/subscripting.swift b/test/Parse/subscripting.swift index 0351c5bb3bdd0..a81c6aeaf7238 100644 --- a/test/Parse/subscripting.swift +++ b/test/Parse/subscripting.swift @@ -59,7 +59,8 @@ struct X4 { struct Y1 { var stored: Int - subscript(_: i, j: Int) -> Int { // expected-error {{use of undeclared type 'i'}} + // FIXME: Duplicate diagnostics + subscript(_: i, j: Int) -> Int { // expected-error 3{{use of undeclared type 'i'}} get { return stored + j } diff --git a/test/decl/class/override.swift b/test/decl/class/override.swift index 26be350e2119c..2396c86c46f20 100644 --- a/test/decl/class/override.swift +++ b/test/decl/class/override.swift @@ -277,3 +277,30 @@ class Derived24646184 : Base24646184 { override func foo(ok: Ty) { } override func foo(ok: SubTy) { } } + + +// Generic subscripts + +class GenericSubscriptBase { + var dict: [AnyHashable : Any] = [:] + + subscript(t: T) -> U { + get { + return dict[t] as! U + } + set { + dict[t] = newValue + } + } +} + +class GenericSubscriptDerived : GenericSubscriptBase { + override subscript(t: K) -> V { + get { + return super[t] + } + set { + super[t] = newValue + } + } +} diff --git a/test/decl/protocol/req/properties.swift b/test/decl/protocol/req/properties.swift new file mode 100644 index 0000000000000..08f6746c30569 --- /dev/null +++ b/test/decl/protocol/req/properties.swift @@ -0,0 +1,54 @@ +// RUN: %target-typecheck-verify-swift + +//===----------------------------------------------------------------------===// +// Get-only property requirements +//===----------------------------------------------------------------------===// + +protocol PropertyGet { + var x : Int { get } // expected-note {{protocol requires property 'x' with type 'Int'}} +} + +class PropertyGet_Stored : PropertyGet { + var x : Int = 0 // ok +} + +class PropertyGet_Immutable : PropertyGet { + let x : Int = 0 // ok. +} + +class PropertyGet_ComputedGetSet : PropertyGet { + var x : Int { get { return 0 } set {} } // ok +} + +class PropertyGet_ComputedGet : PropertyGet { + var x : Int { return 0 } // ok +} + +struct PropertyGet_StaticVar : PropertyGet { // expected-error {{type 'PropertyGet_StaticVar' does not conform to protocol 'PropertyGet'}} + static var x : Int = 42 // expected-note {{candidate operates on a type, not an instance as required}} +} + + +//===----------------------------------------------------------------------===// +// Get-Set property requirements +//===----------------------------------------------------------------------===// + +protocol PropertyGetSet { + var x : Int { get set } // expected-note 2{{protocol requires property 'x' with type 'Int'}} +} + +class PropertyGetSet_Stored : PropertyGetSet { + var x : Int = 0 // ok +} + +class PropertyGetSet_Immutable : PropertyGetSet { // expected-error {{type 'PropertyGetSet_Immutable' does not conform to protocol 'PropertyGetSet'}} + let x : Int = 0 // expected-note {{candidate is not settable, but protocol requires it}} +} + +class PropertyGetSet_ComputedGetSet : PropertyGetSet { + var x : Int { get { return 42 } set {} } // ok +} + +class PropertyGetSet_ComputedGet : PropertyGetSet { // expected-error {{type 'PropertyGetSet_ComputedGet' does not conform to protocol 'PropertyGetSet'}} + var x : Int { return 42 } // expected-note {{candidate is not settable, but protocol requires it}} +} diff --git a/test/decl/protocol/req/subscript.swift b/test/decl/protocol/req/subscript.swift index 96cc801f59903..dbe67b3456c32 100644 --- a/test/decl/protocol/req/subscript.swift +++ b/test/decl/protocol/req/subscript.swift @@ -32,58 +32,6 @@ struct S1Error : P1 { // expected-error{{type 'S1Error' does not conform to prot } -//===----------------------------------------------------------------------===// -// Get-only property requirements -//===----------------------------------------------------------------------===// - -protocol PropertyGet { - var x : Int { get } // expected-note {{protocol requires property 'x' with type 'Int'}} -} - -class PropertyGet_Stored : PropertyGet { - var x : Int = 0 // ok -} - -class PropertyGet_Immutable : PropertyGet { - let x : Int = 0 // ok. -} - -class PropertyGet_ComputedGetSet : PropertyGet { - var x : Int { get { return 0 } set {} } // ok -} - -class PropertyGet_ComputedGet : PropertyGet { - var x : Int { return 0 } // ok -} - -struct PropertyGet_StaticVar : PropertyGet { // expected-error {{type 'PropertyGet_StaticVar' does not conform to protocol 'PropertyGet'}} - static var x : Int = 42 // expected-note {{candidate operates on a type, not an instance as required}} -} - -//===----------------------------------------------------------------------===// -// Get-Set property requirements -//===----------------------------------------------------------------------===// - -protocol PropertyGetSet { - var x : Int { get set } // expected-note 2{{protocol requires property 'x' with type 'Int'}} -} - -class PropertyGetSet_Stored : PropertyGetSet { - var x : Int = 0 // ok -} - -class PropertyGetSet_Immutable : PropertyGetSet { // expected-error {{type 'PropertyGetSet_Immutable' does not conform to protocol 'PropertyGetSet'}} - let x : Int = 0 // expected-note {{candidate is not settable, but protocol requires it}} -} - -class PropertyGetSet_ComputedGetSet : PropertyGetSet { - var x : Int { get { return 42 } set {} } // ok -} - -class PropertyGetSet_ComputedGet : PropertyGetSet { // expected-error {{type 'PropertyGetSet_ComputedGet' does not conform to protocol 'PropertyGetSet'}} - var x : Int { return 42 } // expected-note {{candidate is not settable, but protocol requires it}} -} - //===----------------------------------------------------------------------===// // Get-only subscript requirements //===----------------------------------------------------------------------===// @@ -119,3 +67,28 @@ class SubscriptGetSet_GetSet : SubscriptGetSet { subscript(a : Int) -> Int { get { return 42 } set {} } // ok } +//===----------------------------------------------------------------------===// +// Generic subscript requirements +//===----------------------------------------------------------------------===// + +protocol Initable { + init() +} + +protocol GenericSubscriptProtocol { + subscript(t: T.Type) -> T { get set } + // expected-note@-1 {{protocol requires subscript with type ' (T.Type) -> T'; do you want to add a stub?}} +} + +struct GenericSubscriptWitness : GenericSubscriptProtocol { + subscript(t: T.Type) -> T { + get { + return t.init() + } + + set { } + } +} + +struct GenericSubscriptNoWitness : GenericSubscriptProtocol {} +// expected-error@-1 {{type 'GenericSubscriptNoWitness' does not conform to protocol 'GenericSubscriptProtocol'}} diff --git a/test/decl/subscript/generic.swift b/test/decl/subscript/generic.swift new file mode 100644 index 0000000000000..da83c6f87a191 --- /dev/null +++ b/test/decl/subscript/generic.swift @@ -0,0 +1,35 @@ +// RUN: %target-typecheck-verify-swift + +protocol Initable { + init() +} + +struct ConcreteType { + let c: [Int] + + // Generic index type + subscript(indices: C) -> [Int] + where C.Iterator.Element == Int { + return indices.map { c[$0] } + } + + // Generic element type + subscript(factory: I.Type) -> I { + return factory.init() + } +} + +struct GenericType { + let c: T + + // Generic index type + subscript(indices: C) -> [T.Iterator.Element] + where C.Iterator.Element == T.Index { + return indices.map { c[$0] } + } + + // Generic element type + subscript(factory: I.Type) -> I { + return factory.init() + } +}