Skip to content

Commit 6bb36b5

Browse files
committed
Sema: Subscript default arguments
Fixes <https://bugs.swift.org/browse/SR-6118>.
1 parent 043d76a commit 6bb36b5

19 files changed

+308
-44
lines changed

include/swift/AST/DiagnosticsParse.def

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -821,8 +821,6 @@ ERROR(untyped_pattern_ellipsis,none,
821821
"'...' cannot be applied to a subpattern which is not explicitly typed", ())
822822
ERROR(no_default_arg_closure,none,
823823
"default arguments are not allowed in closures", ())
824-
ERROR(no_default_arg_subscript,none,
825-
"default arguments are not allowed in subscripts", ())
826824
ERROR(no_default_arg_curried,none,
827825
"default arguments are not allowed in curried parameter lists", ())
828826
ERROR(var_pattern_in_var,none,

include/swift/Parse/Parser.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1098,8 +1098,8 @@ class Parser {
10981098
/// all the arguments, not just those that have default arguments.
10991099
unsigned claimNextIndex() { return NextIndex++; }
11001100

1101-
/// Set the parsed context for all the initializers to the given
1102-
/// function.
1101+
/// Set the parsed context of all default argument initializers to
1102+
/// the given function, enum case or subscript.
11031103
void setFunctionContext(DeclContext *DC, ParameterList *paramList);
11041104

11051105
DefaultArgumentInfo() {

lib/AST/ASTVerifier.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -761,6 +761,7 @@ class Verifier : public ASTWalker {
761761
FUNCTION_LIKE(DestructorDecl)
762762
FUNCTION_LIKE(FuncDecl)
763763
FUNCTION_LIKE(EnumElementDecl)
764+
FUNCTION_LIKE(SubscriptDecl)
764765
SCOPE_LIKE(NominalTypeDecl)
765766
SCOPE_LIKE(ExtensionDecl)
766767

lib/AST/Decl.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5551,8 +5551,10 @@ const ParamDecl *swift::getParameterAt(ValueDecl *source, unsigned index) {
55515551
const ParameterList *paramList;
55525552
if (auto *AFD = dyn_cast<AbstractFunctionDecl>(source)) {
55535553
paramList = AFD->getParameters();
5554+
} else if (auto *EED = dyn_cast<EnumElementDecl>(source)) {
5555+
paramList = EED->getParameterList();
55545556
} else {
5555-
paramList = cast<EnumElementDecl>(source)->getParameterList();
5557+
paramList = cast<SubscriptDecl>(source)->getIndices();
55565558
}
55575559

55585560
return paramList->get(index);

lib/AST/DeclContext.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -318,8 +318,10 @@ ResilienceExpansion DeclContext::getResilienceExpansion() const {
318318
const ValueDecl *VD;
319319
if (auto *FD = dyn_cast<AbstractFunctionDecl>(dc)) {
320320
VD = FD;
321+
} else if (auto *EED = dyn_cast<EnumElementDecl>(dc)) {
322+
VD = EED;
321323
} else {
322-
VD = cast<EnumElementDecl>(dc);
324+
VD = cast<SubscriptDecl>(dc);
323325
}
324326

325327
auto access =

lib/Parse/ParseDecl.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6364,10 +6364,11 @@ Parser::parseDeclSubscript(ParseDeclOptions Flags,
63646364
return makeParserCodeCompletionStatus();
63656365

63666366
// Parse the parameter list.
6367+
DefaultArgumentInfo DefaultArgs;
63676368
SmallVector<Identifier, 4> argumentNames;
63686369
ParserResult<ParameterList> Indices
63696370
= parseSingleParameterClause(ParameterContextKind::Subscript,
6370-
&argumentNames);
6371+
&argumentNames, &DefaultArgs);
63716372
Status |= Indices;
63726373

63736374
SignatureHasCodeCompletion |= Indices.hasCodeCompletion();
@@ -6419,6 +6420,8 @@ Parser::parseDeclSubscript(ParseDeclOptions Flags,
64196420
nullptr);
64206421
Subscript->getAttrs() = Attributes;
64216422

6423+
DefaultArgs.setFunctionContext(Subscript, Subscript->getIndices());
6424+
64226425
// Parse a 'where' clause if present, adding it to our GenericParamList.
64236426
if (Tok.is(tok::kw_where)) {
64246427
ContextChange CC(*this, Subscript);

lib/Parse/ParsePattern.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -92,13 +92,11 @@ static ParserStatus parseDefaultArgument(
9292
case Parser::ParameterContextKind::Operator:
9393
case Parser::ParameterContextKind::Initializer:
9494
case Parser::ParameterContextKind::EnumElement:
95+
case Parser::ParameterContextKind::Subscript:
9596
break;
9697
case Parser::ParameterContextKind::Closure:
9798
diagID = diag::no_default_arg_closure;
9899
break;
99-
case Parser::ParameterContextKind::Subscript:
100-
diagID = diag::no_default_arg_subscript;
101-
break;
102100
case Parser::ParameterContextKind::Curried:
103101
diagID = diag::no_default_arg_curried;
104102
break;
@@ -609,7 +607,8 @@ mapParsedParameters(Parser &parser,
609607
assert((paramContext == Parser::ParameterContextKind::Function ||
610608
paramContext == Parser::ParameterContextKind::Operator ||
611609
paramContext == Parser::ParameterContextKind::Initializer ||
612-
paramContext == Parser::ParameterContextKind::EnumElement) &&
610+
paramContext == Parser::ParameterContextKind::EnumElement ||
611+
paramContext == Parser::ParameterContextKind::Subscript) &&
613612
"Default arguments are only permitted on the first param clause");
614613
DefaultArgumentKind kind = getDefaultArgKind(param.DefaultArg);
615614
result->setDefaultArgumentKind(kind);

lib/SIL/TypeLowering.cpp

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1755,9 +1755,14 @@ static CanAnyFunctionType getDefaultArgGeneratorInterfaceType(
17551755
}
17561756

17571757
// Get the generic signature from the surrounding context.
1758-
auto funcInfo = TC.getConstantInfo(SILDeclRef(VD));
1759-
return CanAnyFunctionType::get(funcInfo.FormalType.getOptGenericSignature(),
1760-
{}, canResultTy);
1758+
CanGenericSignature sig;
1759+
if (auto *afd = dyn_cast<AbstractFunctionDecl>(VD)) {
1760+
auto funcInfo = TC.getConstantInfo(SILDeclRef(VD));
1761+
sig = funcInfo.FormalType.getOptGenericSignature();
1762+
} else {
1763+
sig = TC.getEffectiveGenericSignature(DC);
1764+
}
1765+
return CanAnyFunctionType::get(sig, {}, canResultTy);
17611766
}
17621767

17631768
/// Get the type of a stored property initializer, () -> T.
@@ -1940,7 +1945,8 @@ CanAnyFunctionType TypeConverter::makeConstantInterfaceType(SILDeclRef c) {
19401945
return getGlobalAccessorType(var->getInterfaceType()->getCanonicalType());
19411946
}
19421947
case SILDeclRef::Kind::DefaultArgGenerator:
1943-
return getDefaultArgGeneratorInterfaceType(*this, vd, vd->getDeclContext(),
1948+
return getDefaultArgGeneratorInterfaceType(*this, vd,
1949+
vd->getInnermostDeclContext(),
19441950
c.defaultArgIndex);
19451951
case SILDeclRef::Kind::StoredPropertyInitializer:
19461952
return getStoredPropertyInitializerInterfaceType(*this,
@@ -1995,7 +2001,10 @@ TypeConverter::getConstantGenericEnvironment(SILDeclRef c) {
19952001
return cast<ClassDecl>(vd)->getGenericEnvironmentOfContext();
19962002
case SILDeclRef::Kind::DefaultArgGenerator:
19972003
// Use the generic environment of the original function.
1998-
return getConstantGenericEnvironment(SILDeclRef(c.getDecl()));
2004+
if (auto *afd = dyn_cast<AbstractFunctionDecl>(c.getDecl()))
2005+
return getConstantGenericEnvironment(SILDeclRef(c.getDecl()));
2006+
return c.getDecl()->getInnermostDeclContext()
2007+
->getGenericEnvironmentOfContext();
19992008
case SILDeclRef::Kind::StoredPropertyInitializer:
20002009
// Use the generic environment of the containing type.
20012010
return c.getDecl()->getDeclContext()->getGenericEnvironmentOfContext();

lib/SILGen/SILGenFunction.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,9 @@ DeclName SILGenModule::getMagicFunctionName(DeclContext *dc) {
100100
if (auto EED = dyn_cast<EnumElementDecl>(dc)) {
101101
return EED->getFullName();
102102
}
103+
if (auto SD = dyn_cast<SubscriptDecl>(dc)) {
104+
return SD->getFullName();
105+
}
103106
llvm_unreachable("unexpected #function context");
104107
}
105108

lib/SILGen/SILGenType.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1044,6 +1044,12 @@ class SILGenType : public TypeMemberVisitor<SILGenType> {
10441044
visitAbstractStorageDecl(vd);
10451045
}
10461046

1047+
void visitSubscriptDecl(SubscriptDecl *sd) {
1048+
SGM.emitDefaultArgGenerators(sd, sd->getIndices());
1049+
1050+
visitAbstractStorageDecl(sd);
1051+
}
1052+
10471053
void visitAbstractStorageDecl(AbstractStorageDecl *asd) {
10481054
// FIXME: Default implementations in protocols.
10491055
if (asd->isObjC() && !isa<ProtocolDecl>(asd->getDeclContext()))
@@ -1154,6 +1160,11 @@ class SILGenExtension : public TypeMemberVisitor<SILGenExtension> {
11541160
visitAbstractStorageDecl(vd);
11551161
}
11561162

1163+
void visitSubscriptDecl(SubscriptDecl *sd) {
1164+
SGM.emitDefaultArgGenerators(sd, sd->getIndices());
1165+
visitAbstractStorageDecl(sd);
1166+
}
1167+
11571168
void visitEnumCaseDecl(EnumCaseDecl *ecd) {}
11581169
void visitEnumElementDecl(EnumElementDecl *ed) {
11591170
llvm_unreachable("enum elements aren't allowed in extensions");

lib/Sema/CSApply.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5290,8 +5290,7 @@ Expr *ExprRewriter::coerceCallArguments(
52905290
findCalleeDeclRef(cs, solution, cs.getConstraintLocator(locator));
52915291

52925292
// Determine whether this application has curried self.
5293-
bool skipCurriedSelf = apply ? hasCurriedSelf(cs, callee, apply) : false;
5294-
5293+
bool skipCurriedSelf = apply ? hasCurriedSelf(cs, callee, apply) : true;
52955294
// Determine the parameter bindings.
52965295
SmallBitVector defaultMap
52975296
= computeDefaultMap(params, callee.getDecl(), skipCurriedSelf);

lib/Sema/CSDiag.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,16 @@ void constraints::simplifyLocator(Expr *&anchor,
161161
continue;
162162
}
163163

164+
if (auto subscriptExpr = dyn_cast<SubscriptExpr>(anchor)) {
165+
// The target anchor is the subscript.
166+
targetAnchor = subscriptExpr;
167+
targetPath.clear();
168+
169+
anchor = subscriptExpr->getIndex();
170+
path = path.slice(1);
171+
continue;
172+
}
173+
164174
if (auto objectLiteralExpr = dyn_cast<ObjectLiteralExpr>(anchor)) {
165175
targetAnchor = nullptr;
166176
targetPath.clear();
@@ -196,6 +206,17 @@ void constraints::simplifyLocator(Expr *&anchor,
196206
continue;
197207
}
198208

209+
// The subscript itself is the function.
210+
if (auto subscriptExpr = dyn_cast<SubscriptExpr>(anchor)) {
211+
// No additional target locator information.
212+
targetAnchor = nullptr;
213+
targetPath.clear();
214+
215+
anchor = subscriptExpr;
216+
path = path.slice(1);
217+
continue;
218+
}
219+
199220
// The unresolved member itself is the function.
200221
if (auto unresolvedMember = dyn_cast<UnresolvedMemberExpr>(anchor)) {
201222
if (unresolvedMember->getArgument()) {

lib/Sema/CSSimplify.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ bool constraints::areConservativelyCompatibleArgumentLabels(
127127
// we can get an unapplied declaration reference back.
128128
bool hasCurriedSelf;
129129
if (isa<SubscriptDecl>(decl)) {
130-
hasCurriedSelf = false;
130+
hasCurriedSelf = true;
131131
} else if (!baseType || baseType->is<ModuleType>()) {
132132
hasCurriedSelf = false;
133133
} else if (baseType->is<AnyMetatypeType>() && decl->isInstanceMember()) {
@@ -146,7 +146,6 @@ bool constraints::areConservativelyCompatibleArgumentLabels(
146146
if (auto fn = dyn_cast<AbstractFunctionDecl>(decl)) {
147147
fTy = fn->getInterfaceType()->castTo<AnyFunctionType>();
148148
} else if (auto subscript = dyn_cast<SubscriptDecl>(decl)) {
149-
assert(!hasCurriedSelf && "Subscripts never have curried 'self'");
150149
fTy = subscript->getInterfaceType()->castTo<AnyFunctionType>();
151150
} else if (auto enumElement = dyn_cast<EnumElementDecl>(decl)) {
152151
fTy = enumElement->getInterfaceType()->castTo<AnyFunctionType>();
@@ -160,7 +159,7 @@ bool constraints::areConservativelyCompatibleArgumentLabels(
160159
}
161160

162161
const AnyFunctionType *levelTy = fTy;
163-
if (hasCurriedSelf) {
162+
if (hasCurriedSelf && !isa<SubscriptDecl>(decl)) {
164163
levelTy = levelTy->getResult()->getAs<AnyFunctionType>();
165164
assert(levelTy && "Parameter list curry level does not match type");
166165
}

lib/Sema/TypeCheckDecl.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2416,6 +2416,8 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
24162416
if (SD->getAttrs().hasAttribute<DynamicReplacementAttr>()) {
24172417
TC.checkDynamicReplacementAttribute(SD);
24182418
}
2419+
2420+
TC.checkDefaultArguments(SD->getIndices(), SD);
24192421
}
24202422

24212423
void visitTypeAliasDecl(TypeAliasDecl *TAD) {
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend -emit-module -o %t/Test~partial.swiftmodule -module-name Test -primary-file %s
3+
// RUN: %target-swift-frontend -merge-modules -emit-module -o %t/Test.swiftmodule %t/Test~partial.swiftmodule
4+
// RUN: %target-swift-ide-test -print-module -module-to-print=Test -source-filename=x -I %t | %FileCheck %s
5+
6+
// RUN: %target-swift-frontend -typecheck -emit-parseable-module-interface-path %t.swiftinterface -enable-library-evolution %s
7+
// RUN: %FileCheck %s < %t.swiftinterface
8+
9+
public enum Enum {
10+
// CHECK: case pie(filling: String = "apple")
11+
case pie(filling: String = "apple")
12+
}
13+
14+
public struct HasSubscript {
15+
// CHECK: subscript(x: Int = 0) -> Int {
16+
public subscript(x: Int = 0) -> Int { return 0 }
17+
}
18+
19+
// CHECK: func hasClosureDefaultArg(_ x: () -> Void = {
20+
// CHECK-NEXT: })
21+
public func hasClosureDefaultArg(_ x: () -> Void = {
22+
}) {
23+
}
24+
25+
// CHECK: func hasMagicDefaultArgs(_ f: String = #file, _ fu: String = #function, _ l: Int = #line)
26+
public func hasMagicDefaultArgs(_ f: String = #file, _ fu: String = #function, _ l: Int = #line) {}
27+
28+
// CHECK: func hasSimpleDefaultArgs(_ x: Int = 0, b: Int = 1)
29+
public func hasSimpleDefaultArgs(_ x: Int = 0, b: Int = 1) {
30+
}

test/ParseableInterface/if-configs.swift

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,6 @@
66
// RUN: %target-swift-frontend -typecheck -emit-parseable-module-interface-path %t.swiftinterface -enable-library-evolution %s
77
// RUN: %FileCheck %s < %t.swiftinterface
88

9-
// CHECK: func hasClosureDefaultArg(_ x: () -> Void = {
10-
// CHECK-NEXT: })
11-
public func hasClosureDefaultArg(_ x: () -> Void = {
12-
}) {
13-
}
14-
159
// CHECK: func hasClosureDefaultArgWithComplexNestedPoundIfs(_ x: () -> Void = {
1610
// CHECK-NOT: #if NOT_PROVIDED
1711
// CHECK-NOT: print("should not exist")
@@ -115,7 +109,3 @@ public func hasClosureDefaultArgWithSinglePoundIf(_ x: () -> Void = {
115109
#endif
116110
}) {
117111
}
118-
119-
// CHECK: func hasSimpleDefaultArgs(_ x: Int = 0, b: Int = 1)
120-
public func hasSimpleDefaultArgs(_ x: Int = 0, b: Int = 1) {
121-
}

0 commit comments

Comments
 (0)