Skip to content

Commit c6631ec

Browse files
committed
[Constraint solver] Match call arguments for subscripts.
Record the argument labels provided to a subscript in the solver, and use that to filter out subscript declarations with non-matching argument labels during function application. This reduces the number of overloaded subscript declarations that will be considered in later steps in the solver, reducing the solution space. *Disable* this optimization in the normal member-lookup path, which is intended to go away in the near future. This limits the scope of the change somewhat, so we can separately tackle the diagnostics issue. The one diagnostics change here is probably an improvement, because the user explicitly stated the argument labels, and is more likely missing a conversion on the argument than having typed the wrong label.
1 parent bdc961d commit c6631ec

File tree

4 files changed

+37
-7
lines changed

4 files changed

+37
-7
lines changed

lib/Sema/CSGen.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3614,6 +3614,14 @@ namespace {
36143614
return { true, expr };
36153615
}
36163616

3617+
if (auto subscript = dyn_cast<SubscriptExpr>(expr)) {
3618+
associateArgumentLabels(subscript,
3619+
{ subscript->getArgumentLabels(),
3620+
subscript->hasTrailingClosure() },
3621+
/*labelsArePermanent=*/true);
3622+
return { true, expr };
3623+
}
3624+
36173625
// FIXME: other expressions have argument labels, but this is an
36183626
// optimization, so stage it in later.
36193627
return { true, expr };

lib/Sema/CSSimplify.cpp

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,9 @@ bool constraints::areConservativelyCompatibleArgumentLabels(
122122
// the member lookup binding the first level. But there are cases where
123123
// we can get an unapplied declaration reference back.
124124
bool hasCurriedSelf;
125-
if (!baseType || baseType->is<ModuleType>()) {
125+
if (isa<SubscriptDecl>(decl)) {
126+
hasCurriedSelf = false;
127+
} else if (!baseType || baseType->is<ModuleType>()) {
126128
hasCurriedSelf = false;
127129
} else if (baseType->is<AnyMetatypeType>() && decl->isInstanceMember()) {
128130
hasCurriedSelf = false;
@@ -139,11 +141,16 @@ areConservativelyCompatibleArgumentLabels(ValueDecl *decl,
139141
bool hasCurriedSelf,
140142
ArrayRef<Identifier> labels,
141143
bool hasTrailingClosure) {
142-
// Bail out conservatively if this isn't a function declaration.
143-
auto fn = dyn_cast<AbstractFunctionDecl>(decl);
144-
if (!fn) return true;
145-
146-
auto *fTy = fn->getInterfaceType()->castTo<AnyFunctionType>();
144+
const AnyFunctionType *fTy;
145+
146+
if (auto fn = dyn_cast<AbstractFunctionDecl>(decl)) {
147+
fTy = fn->getInterfaceType()->castTo<AnyFunctionType>();
148+
} else if (auto subscript = dyn_cast<SubscriptDecl>(decl)) {
149+
assert(!hasCurriedSelf && "Subscripts never have curried 'self'");
150+
fTy = subscript->getInterfaceType()->castTo<AnyFunctionType>();
151+
} else {
152+
return true;
153+
}
147154

148155
SmallVector<AnyFunctionType::Param, 8> argInfos;
149156
for (auto argLabel : labels) {
@@ -3573,7 +3580,10 @@ performMemberLookup(ConstraintKind constraintKind, DeclName memberName,
35733580

35743581
// If the argument labels for this result are incompatible with
35753582
// the call site, skip it.
3583+
// FIXME: The subscript check here forces the use of the
3584+
// function-application simplification logic to handle labels.
35763585
if (argumentLabels &&
3586+
(!candidate.isDecl() || !isa<SubscriptDecl>(candidate.getDecl())) &&
35773587
!areConservativelyCompatibleArgumentLabels(
35783588
candidate, argumentLabels->Labels,
35793589
argumentLabels->HasTrailingClosure)) {

test/Constraints/overload_filtering.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,15 @@ func testModuleScope(i: Int) {
1414
// CHECK: (introducing single enabled disjunction term {{.*}} (Int, Int) -> ()
1515
foo(i, i)
1616
}
17+
18+
struct X {
19+
subscript(_: Int) -> Int { return 0 }
20+
subscript(_: Int, _: Int) -> Double { return 0 }
21+
subscript(_: Int, _: Int, _: Int) -> String { return "" }
22+
}
23+
24+
func testSubscript(x: X, i: Int) {
25+
// CHECK: disabled disjunction term {{.*}}X.subscript(_:)
26+
// CHECK-NEXT: disabled disjunction term {{.*}}X.subscript(_:_:_:)
27+
_ = x[i, i]
28+
}

test/Constraints/subscript.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ struct SR718 {
9191
subscript(a a : UInt) -> Int { return 0 }
9292
}
9393

94-
SR718()[a: Int()] // expected-error {{extraneous argument label 'a:' in subscript}}
94+
SR718()[a: Int()] // expected-error {{cannot convert value of type 'Int' to expected argument type 'UInt'}}
9595

9696
// rdar://problem/25601561 - Qol: Bad diagnostic for failed assignment from Any to more specific type
9797

0 commit comments

Comments
 (0)