diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index 01dc95b7acf..1dc10e596ec 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -724,9 +724,11 @@ void PrintAST::visitFuncDecl(FuncDecl *decl) { if (auto *TP = dyn_cast(ValueParam)) { if (!TP->isImplicit()) { for (auto &Elt : TP->getFields()) { - Identifier Name = Elt.getPattern()->getBoundName(); - if (!Name.empty()) - Printer << "(" << Name.str() << ")"; + auto *P = Elt.getPattern()->getSemanticsProvidingPattern(); + Identifier Name = P->getBoundName(); + if (!Name.empty() && !P->isImplicit()) + Printer << "(" << Name.str() << ")"; + break; } } } diff --git a/lib/AST/Verifier.cpp b/lib/AST/Verifier.cpp index fdb8ee3a241..fe0b1246514 100644 --- a/lib/AST/Verifier.cpp +++ b/lib/AST/Verifier.cpp @@ -1489,14 +1489,12 @@ struct ASTNodeBase {}; abort(); } - if (FD->isGetterOrSetter()) { + if (FD->isAccessor()) { unsigned NumExpectedParamPatterns = 1; if (FD->getImplicitSelfDecl()) NumExpectedParamPatterns++; - if (isa(FD->getAccessorStorageDecl())) - NumExpectedParamPatterns++; if (FD->getArgParamPatterns().size() != NumExpectedParamPatterns) { - Out << "getters and setters should not be curried"; + Out << "accessors should not be curried"; abort(); } } diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp index 89d24361206..65da7e1f96d 100644 --- a/lib/ClangImporter/ImportDecl.cpp +++ b/lib/ClangImporter/ImportDecl.cpp @@ -1978,12 +1978,12 @@ namespace { indices->getBoundName()), context)); getterArgs.push_back(pat); + } else { + // Otherwise, an empty tuple + getterArgs.push_back(TuplePattern::create(context, loc, { }, loc)); + getterArgs.back()->setType(TupleType::getEmpty(context)); } - // empty tuple - getterArgs.push_back(TuplePattern::create(context, loc, { }, loc)); - getterArgs.back()->setType(TupleType::getEmpty(context)); - // Form the type of the getter. auto getterType = elementTy; for (auto it = getterArgs.rbegin(), itEnd = getterArgs.rend(); @@ -2031,42 +2031,38 @@ namespace { // // (self) -> (value, index) -> () // - // while Swift subscript setters are curried as - // - // (self) -> (index)(value) -> () - // // Build a setter thunk with the latter signature that maps to the // former. // // Property setters are similar, but don't have indices. // Form the argument patterns. - SmallVector setterArgs; + SmallVector setterArgs; // 'self' setterArgs.push_back(createTypedNamedPattern(createSelfDecl(dc, false))); + + SmallVector ValueElts; + SmallVector ValueEltTys; + + auto valuePattern = tuple->getFields()[0].getPattern()->clone(context); + ValueElts.push_back(TuplePatternElt(valuePattern)); + ValueEltTys.push_back(TupleTypeElt(valuePattern->getType(), + valuePattern->getBoundName())); + // index, for subscript operations. if (indices) { // Clone the indices for the thunk. indices = indices->clone(context); - auto pat = TuplePattern::create(context, loc, TuplePatternElt(indices), - loc); - pat->setType(TupleType::get(TupleTypeElt(indices->getType(), - indices->getBoundName()), - context)); - setterArgs.push_back(pat); + ValueElts.push_back(TuplePatternElt(indices)); + ValueEltTys.push_back(TupleTypeElt(indices->getType(), + indices->getBoundName())); } - + // value - auto valuePattern = tuple->getFields()[0].getPattern()->clone(context); - setterArgs.push_back(TuplePattern::create(context, loc, - TuplePatternElt(valuePattern), - loc)); - setterArgs.back()->setType( - TupleType::get(TupleTypeElt(valuePattern->getType(), - valuePattern->getBoundName()), - context)); + setterArgs.push_back(TuplePattern::create(context, loc, ValueElts, loc)); + setterArgs.back()->setType(TupleType::get(ValueEltTys, context)); // Form the type of the setter. Type setterType = TupleType::getEmpty(context); diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 9502a081c0e..7ec0417e268 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -1144,11 +1144,53 @@ ParserResult Parser::parseDeclTypeAlias(bool WantDefinition, /// createGetterFunc - This function creates the getter function (with no body) /// for a computed property or subscript. -static FuncDecl *createAccessorFunc(SourceLoc DeclLoc, Pattern *NamePattern, +static FuncDecl *createAccessorFunc(SourceLoc DeclLoc, + TypedPattern *NamePattern, TypeLoc ElementTy, Pattern *Indices, SourceLoc StaticLoc, Parser::ParseDeclOptions Flags, AccessorKind Kind, Parser *P) { + // First task, set up the value argument pattern. This is the NamePattern + // (for setters) followed by the index list (for subscripts). For + // non-subscript getters, this degenerates down to "()". + // + // We put the 'value' argument before the subscript index list as a + // micro-optimization for Objective-C thunk generation. + Pattern *ValueArg; + { + SmallVector ValueArgElements; + SourceLoc StartLoc, EndLoc; + if (NamePattern) { + ValueArgElements.push_back(TuplePatternElt(NamePattern)); + StartLoc = NamePattern->getStartLoc(); + EndLoc = NamePattern->getEndLoc(); + } + + if (Indices) { + Indices = Indices->clone(P->Context, /*Implicit=*/true); + if (auto *PP = dyn_cast(Indices)) { + ValueArgElements.push_back(TuplePatternElt(PP->getSubPattern())); + } else { + auto *TP = cast(Indices); + ValueArgElements.append(TP->getFields().begin(), TP->getFields().end()); + } + + StartLoc = Indices->getStartLoc(); + EndLoc = Indices->getEndLoc(); + } + + if (NamePattern && Indices) { + StartLoc = Indices->getStartLoc(); + EndLoc = NamePattern->getEndLoc(); + } + + ValueArg = TuplePattern::create(P->Context, StartLoc, + ValueArgElements, EndLoc); + if (NamePattern && !NamePattern->isImplicit()) + ValueArg->setImplicit(); + } + + // Create the parameter list(s) for the getter. SmallVector Params; @@ -1156,12 +1198,8 @@ static FuncDecl *createAccessorFunc(SourceLoc DeclLoc, Pattern *NamePattern, if (Flags & Parser::PD_HasContainerType) Params.push_back(buildImplicitSelfParameter(DeclLoc, P->CurDeclContext)); - // Add the index clause if necessary. - if (Indices) - Params.push_back(Indices->clone(P->Context, /*Implicit=*/true)); - - // Add the (value) or () parameter clause. - Params.push_back(NamePattern); + // Add the "(value)" and subscript indices parameter clause. + Params.push_back(ValueArg); TypeLoc ReturnType; if (Kind == AccessorKind::IsGetter) // Getters return something @@ -1171,7 +1209,7 @@ static FuncDecl *createAccessorFunc(SourceLoc DeclLoc, Pattern *NamePattern, // Start the function. auto *D = FuncDecl::create(P->Context, StaticLoc, StaticSpellingKind::None, - /* FIXME(gribozavr)*/DeclLoc, Identifier(), + /* FIXME*/DeclLoc, Identifier(), DeclLoc, /*GenericParams=*/nullptr, Type(), Params, Params, ReturnType, P->CurDeclContext); @@ -1185,17 +1223,13 @@ static FuncDecl *createAccessorFunc(SourceLoc DeclLoc, Pattern *NamePattern, /// Parse a "(value)" specifier for "set:" or "willSet:" if present. Create a /// pattern to represent the spelled argument or the implicit one if it is /// missing. -static Pattern *parseOptionalAccessorArgument(SourceLoc SpecifierLoc, - TypeLoc ElementTy, - Parser &P, AccessorKind Kind) { +static TypedPattern * +parseOptionalAccessorArgument(SourceLoc SpecifierLoc, TypeLoc ElementTy, + Parser &P, AccessorKind Kind) { // Only set: and willSet: have a (value) parameter. get: and didSet: take a // () parameter always. if (Kind != AccessorKind::IsSetter && Kind != AccessorKind::IsWillSet) - return TuplePattern::create(P.Context, SourceLoc(), - ArrayRef(), - SourceLoc(), /*hasVararg=*/false, - SourceLoc(), /*Implicit=*/true); - + return nullptr; SourceLoc StartLoc, NameLoc, EndLoc; Identifier Name; @@ -1237,28 +1271,17 @@ static Pattern *parseOptionalAccessorArgument(SourceLoc SpecifierLoc, VarDecl *Value = new (Context) VarDecl(/*static*/false, /*IsVal*/true, NameLoc, Name, Type(), P.CurDeclContext); - Pattern *ValuePattern - = new (Context) TypedPattern(new (Context) NamedPattern(Value), - ElementTy.clone(Context)); - - TuplePatternElt ValueElt(ValuePattern); - Pattern *ValueParamsPattern - = TuplePattern::create(Context, StartLoc, ValueElt, EndLoc); - if (IsNameImplicit) { + if (IsNameImplicit) Value->setImplicit(); - ValueParamsPattern->setImplicit(); - } - - // The TypedPattern is always implicit because the ElementTy is not - // spelled inside the parameter list. It comes from elsewhere, and its - // source location should be ignored. - ValuePattern->setImplicit(); - return ValueParamsPattern; + auto *namedPat = new (Context) NamedPattern(Value, IsNameImplicit); + return new (Context) TypedPattern(namedPat, ElementTy.clone(Context), + /*Implicit*/true); } -/// \brief Parse a get-set clause, containing a getter and (optionally) -/// a setter. +/// \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. /// /// \verbatim /// get-set: @@ -1320,7 +1343,7 @@ bool Parser::parseGetSet(ParseDeclOptions Flags, Pattern *Indices, if (Tok.is(tok::l_paren)) diagnose(Loc, diag::protocol_setter_name); - Pattern *ValueNamePattern + auto *ValueNamePattern = parseOptionalAccessorArgument(Loc, ElementTy, *this, Kind); // Set up a function declaration. @@ -1391,7 +1414,7 @@ bool Parser::parseGetSet(ParseDeclOptions Flags, Pattern *Indices, // set: and willSet: can have an optional name. // var-set-name ::= '(' identifier ')' - Pattern *ValueNamePattern = + auto *ValueNamePattern = parseOptionalAccessorArgument(Loc, ElementTy, *this, Kind); SourceLoc ColonLoc = Tok.getLoc(); @@ -1514,15 +1537,13 @@ VarDecl *Parser::parseDeclVarGetSet(Pattern &pattern, ParseDeclOptions Flags, // Observing properties will have getters and setters synthesized by sema. // Create their prototypes now. - auto *ArgPattern = parseOptionalAccessorArgument(SourceLoc(), TyLoc, *this, - AccessorKind::IsGetter); - Get = createAccessorFunc(SourceLoc(), ArgPattern, TyLoc, nullptr, + Get = createAccessorFunc(SourceLoc(), /*ArgPattern*/nullptr, TyLoc, nullptr, StaticLoc, Flags, AccessorKind::IsGetter, this); Get->setImplicit(); Decls.push_back(Get); - ArgPattern = parseOptionalAccessorArgument(SourceLoc(), TyLoc, *this, - AccessorKind::IsSetter); + auto ArgPattern = parseOptionalAccessorArgument(SourceLoc(), TyLoc, *this, + AccessorKind::IsSetter); Set = createAccessorFunc(SourceLoc(), ArgPattern, TyLoc, nullptr, StaticLoc, Flags, AccessorKind::IsSetter, this); Set->setImplicit(); @@ -2601,7 +2622,7 @@ ParserStatus Parser::parseDeclSubscript(ParseDeclOptions Flags, SourceLoc LastValidLoc = LBLoc; FuncDecl *WillSet = nullptr, *DidSet = nullptr; - if (parseGetSet(Flags, Indices.get(),ElementTy.get(), + if (parseGetSet(Flags, Indices.get(), ElementTy.get(), Get, Set, WillSet, DidSet, LastValidLoc, /*StaticLoc*/ SourceLoc(), Decls)) Status.setIsParseError(); @@ -2638,12 +2659,10 @@ ParserStatus Parser::parseDeclSubscript(ParseDeclOptions Flags, // If we had no getter (e.g., because we're in SIL mode or because the // program isn't valid) create a stub here. if (!Get) { - auto ArgPattern = - parseOptionalAccessorArgument(SubscriptLoc, ElementTy.get(), *this, - AccessorKind::IsGetter); - Get = createAccessorFunc(SubscriptLoc, ArgPattern, ElementTy.get(), - Indices.get(), /*StaticLoc*/ SourceLoc(), - Flags, AccessorKind::IsGetter, this); + Get = createAccessorFunc(SubscriptLoc, /*ArgPattern*/ nullptr, + ElementTy.get(), Indices.get(), + /*StaticLoc*/ SourceLoc(), Flags, + AccessorKind::IsGetter, this); Get->setInvalid(); Get->setType(ErrorType::get(Context)); diff --git a/lib/SILGen/SILGenApply.cpp b/lib/SILGen/SILGenApply.cpp index 553e9d72f57..cf0e5dc971b 100644 --- a/lib/SILGen/SILGenApply.cpp +++ b/lib/SILGen/SILGenApply.cpp @@ -2618,15 +2618,13 @@ emitGetAccessor(SILLocation loc, AbstractStorageDecl *decl, emission.addCallSite(loc, std::move(selfValue), accessType.getResult()); accessType = cast(accessType.getResult()); } - // Index -> - if (subscripts) { - emission.addCallSite(loc, RValueSource(loc, std::move(subscripts)), - accessType.getResult()); - accessType = cast(accessType.getResult()); - } - // () -> - emission.addCallSite(loc, RValueSource(loc, emitEmptyTupleRValue(loc)), + // Index or () if none. + if (!subscripts) + subscripts = emitEmptyTupleRValue(loc); + + emission.addCallSite(loc, RValueSource(loc, std::move(subscripts)), accessType.getResult()); + // T return emission.apply(c); } @@ -2651,14 +2649,18 @@ void SILGenFunction::emitSetAccessor(SILLocation loc, AbstractStorageDecl *decl, emission.addCallSite(loc, std::move(selfValue), accessType.getResult()); accessType = cast(accessType.getResult()); } - // Index -> + + // (value) or (value, indices) if (subscripts) { - emission.addCallSite(loc, RValueSource(loc, std::move(subscripts)), - accessType.getResult()); - accessType = cast(accessType.getResult()); + // If we have a value and index list, create a new rvalue to represent the + // both of them together. The value goes first. + SmallVector Elts; + std::move(setValue).getAll(Elts); + std::move(subscripts).getAll(Elts); + setValue = RValue(Elts, accessType.getInput()); + } else { + setValue.rewriteType(accessType.getInput()); } - // T -> - setValue.rewriteType(accessType.getInput()); emission.addCallSite(loc, RValueSource(loc, std::move(setValue)), accessType.getResult()); // () @@ -2812,13 +2814,13 @@ RValue SILGenFunction::emitDynamicSubscriptExpr(DynamicSubscriptExpr *e, auto dynamicMethodTy = getDynamicMethodType(SGM, base, e->getMember().getDecl(), member, methodTy); - auto loweredMethodTy = getLoweredType(dynamicMethodTy, 2); + auto loweredMethodTy = getLoweredType(dynamicMethodTy, 1); SILValue memberArg = new (F.getModule()) SILArgument(loweredMethodTy, hasMemberBB); // Emit the application of 'self'. SILValue result = B.createPartialApply(e, memberArg, memberArg.getType(), {}, base, - getLoweredType(methodTy, 1)); + getLoweredType(methodTy, 0)); // Emit the index. llvm::SmallVector indexArgs; diff --git a/lib/SILGen/SILGenDecl.cpp b/lib/SILGen/SILGenDecl.cpp index b533b823ddf..9663041e0c0 100644 --- a/lib/SILGen/SILGenDecl.cpp +++ b/lib/SILGen/SILGenDecl.cpp @@ -65,13 +65,12 @@ Initialization::getSubInitializationsForTuple(SILGenFunction &gen, CanType type, SmallVectorImpl &buf, SILLocation Loc) { assert(canSplitIntoSubelementAddresses() && "Client shouldn't call this"); - auto tupleTy = cast(type); switch (kind) { case Kind::Tuple: return getSubInitializations(); case Kind::Ignored: // "Destructure" an ignored binding into multiple ignored bindings. - for (auto fieldType : tupleTy->getElementTypes()) { + for (auto fieldType : cast(type)->getElementTypes()) { (void) fieldType; buf.push_back(InitializationPtr(new BlackHoleInitialization())); } @@ -79,6 +78,7 @@ Initialization::getSubInitializationsForTuple(SILGenFunction &gen, CanType type, case Kind::LetValue: case Kind::SingleBuffer: { // Destructure the buffer into per-element buffers. + auto tupleTy = cast(type); SILValue baseAddr = getAddress(); for (unsigned i = 0, size = tupleTy->getNumElements(); i < size; ++i) { auto fieldType = tupleTy.getElementType(i); diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index 009596364a5..809650788cf 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -1486,7 +1486,15 @@ static bool isParamPatternRepresentableInObjC(TypeChecker &TC, if (NumParams == 0) return true; - if (NumParams != 1 && !AFD->hasSelectorStyleSignature()) { + // Setters on subscripts are allowed to have two arguments, the index and + // the set value. + bool isOK = false; + if (auto *FD = dyn_cast(AFD)) + if (NumParams == 2 && FD->getAccessorKind() == AccessorKind::IsSetter && + isa(FD->getAccessorStorageDecl())) + isOK = true; + + if (!isOK && NumParams != 1 && !AFD->hasSelectorStyleSignature()) { // If the function has two or more parameters, it should have a // selector-style declaration. if (Diagnose) diff --git a/test/IRGen/dynamic_lookup.sil b/test/IRGen/dynamic_lookup.sil index 385ed2a4bdd..530f72136d5 100644 --- a/test/IRGen/dynamic_lookup.sil +++ b/test/IRGen/dynamic_lookup.sil @@ -129,7 +129,7 @@ bb0(%0 : $DynamicLookup, %1 : $Int64): // CHECK-NEXT: [[HAS_SEL:%[0-9]+]] = call i1 @swift_objcRespondsToSelector(%objc_object* %0, i8* [[SEL]]) #0 // CHECK-NEXT: br i1 [[HAS_SEL]], label [[HAS_METHOD:%[0-9]+]], label [[HAS_METHOD:%[0-9]+]] - dynamic_method_br %11 : $Builtin.ObjCPointer, #X.subscript!getter.2.foreign, bb1, bb2 + dynamic_method_br %11 : $Builtin.ObjCPointer, #X.subscript!getter.1.foreign, bb1, bb2 bb1(%13 : $@cc(objc_method) @thin (Int64, Builtin.ObjCPointer) -> Int64): // Preds: bb0 %14 = partial_apply %13(%11) : $@cc(objc_method) @thin (Int64, Builtin.ObjCPointer) -> Int64 diff --git a/test/SIL/Parser/basic.sil b/test/SIL/Parser/basic.sil index f55dd8c6d5a..9001b4fd59a 100644 --- a/test/SIL/Parser/basic.sil +++ b/test/SIL/Parser/basic.sil @@ -1045,10 +1045,10 @@ bb0(%0 : $Int, %1 : $*P): // CHECK-LABEL: sil_vtable Foo { -// CHECK: #Foo.subscript!getter.2: _TC3tmp3Foo9subscriptFT1xSi1ySi_Sig -// CHECK: #Foo.subscript!setter.2: _TC3tmp3Foo9subscriptFT1xSi1ySi_Sis +// CHECK: #Foo.subscript!getter.1: _TC3tmp3Foo9subscriptFT1xSi1ySi_Sig +// CHECK: #Foo.subscript!setter.1: _TC3tmp3Foo9subscriptFT1xSi1ySi_Sis // CHECK: } sil_vtable Foo { - #Foo.subscript!getter.2: _TC3tmp3Foo9subscriptFT1xSi1ySi_Sig - #Foo.subscript!setter.2: _TC3tmp3Foo9subscriptFT1xSi1ySi_Sis + #Foo.subscript!getter.1: _TC3tmp3Foo9subscriptFT1xSi1ySi_Sig + #Foo.subscript!setter.1: _TC3tmp3Foo9subscriptFT1xSi1ySi_Sis } diff --git a/test/Serialization/Inputs/def_basic.sil b/test/Serialization/Inputs/def_basic.sil index 548797fabc8..ebaf055fd2a 100644 --- a/test/Serialization/Inputs/def_basic.sil +++ b/test/Serialization/Inputs/def_basic.sil @@ -961,16 +961,16 @@ bb0(%0 : $Int, %1 : $Int, %2 : $Int, %3 : $Foo): } // CHECK-LABEL: sil_vtable Foo { -// CHECK: #Foo.subscript!getter.2: _TFC3tmp3Foog9subscriptFT1xSi1ySi_Si -// CHECK: #Foo.subscript!setter.2: _TFC3tmp3Foos9subscriptFT1xSi1ySi_Si +// CHECK: #Foo.subscript!getter.1: _TFC3tmp3Foog9subscriptFT1xSi1ySi_Si +// CHECK: #Foo.subscript!setter.1: _TFC3tmp3Foos9subscriptFT1xSi1ySi_Si // CHECK: } // CHECK_DECL-LABEL: sil_vtable Foo { -// CHECK_DECL: #Foo.subscript!getter.2: _TFC3tmp3Foog9subscriptFT1xSi1ySi_Si -// CHECK_DECL: #Foo.subscript!setter.2: _TFC3tmp3Foos9subscriptFT1xSi1ySi_Si +// CHECK_DECL: #Foo.subscript!getter.1: _TFC3tmp3Foog9subscriptFT1xSi1ySi_Si +// CHECK_DECL: #Foo.subscript!setter.1: _TFC3tmp3Foos9subscriptFT1xSi1ySi_Si // CHECK_DECL: } sil_vtable Foo { - #Foo.subscript!getter.2: _TFC3tmp3Foog9subscriptFT1xSi1ySi_Si - #Foo.subscript!setter.2: _TFC3tmp3Foos9subscriptFT1xSi1ySi_Si + #Foo.subscript!getter.1: _TFC3tmp3Foog9subscriptFT1xSi1ySi_Si + #Foo.subscript!setter.1: _TFC3tmp3Foos9subscriptFT1xSi1ySi_Si } protocol AssocReqt {