Skip to content

Commit f2cae86

Browse files
hamishknightxedin
authored andcommitted
[CS] Consolidate logic forming locators to callees
This commit adds `ConstraintSystem::getCalleeLocator`, which forms a locator that describes the callee of a given expression. This function is then used to replace various places where this logic is duplicated. This commit also changes the conditions under which a ConstructorMember callee locator is formed. Previously it was formed for a CallExpr with a TypeExpr function expr. However, now such a locator is formed if the function expr is of AnyMetatypeType. This allows it to be more lenient with invalid code, as well as work with DotSelfExpr. Resolves SR-10694. (cherry picked from commit 894a1e5)
1 parent c88203d commit f2cae86

File tree

6 files changed

+75
-89
lines changed

6 files changed

+75
-89
lines changed

lib/Sema/CSDiagnostics.cpp

Lines changed: 4 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -105,33 +105,9 @@ Expr *FailureDiagnostic::getArgumentExprFor(Expr *anchor) const {
105105
return nullptr;
106106
}
107107

108-
// TODO: Replace duplications of this logic with calls to this.
109-
Optional<SelectedOverload> FailureDiagnostic::getChoiceFor(Expr *expr) {
108+
Optional<SelectedOverload> FailureDiagnostic::getChoiceFor(Expr *expr) const {
110109
auto &cs = getConstraintSystem();
111-
ConstraintLocator *locator = nullptr;
112-
113-
if (auto *AE = dyn_cast<ApplyExpr>(expr)) {
114-
if (auto *TE = dyn_cast<TypeExpr>(AE->getFn())) {
115-
locator = cs.getConstraintLocator(AE,
116-
{ConstraintLocator::ApplyFunction,
117-
ConstraintLocator::ConstructorMember},
118-
/*summaryFlags=*/0);
119-
}
120-
return getChoiceFor(AE->getFn());
121-
} else if (auto *UDE = dyn_cast<UnresolvedDotExpr>(expr)) {
122-
locator = cs.getConstraintLocator(UDE, ConstraintLocator::Member);
123-
} else if (auto *UME = dyn_cast<UnresolvedMemberExpr>(expr)) {
124-
locator = cs.getConstraintLocator(UME, ConstraintLocator::UnresolvedMember);
125-
} else if (auto *SE = dyn_cast<SubscriptExpr>(expr)) {
126-
locator = cs.getConstraintLocator(SE, ConstraintLocator::SubscriptMember);
127-
} else {
128-
locator = cs.getConstraintLocator(expr);
129-
}
130-
131-
if (!locator)
132-
return None;
133-
134-
return getOverloadChoiceIfAvailable(locator);
110+
return getOverloadChoiceIfAvailable(cs.getCalleeLocator(expr));
135111
}
136112

137113
Type RequirementFailure::getOwnerType() const {
@@ -191,10 +167,6 @@ ProtocolConformance *RequirementFailure::getConformanceForConditionalReq(
191167

192168
ValueDecl *RequirementFailure::getDeclRef() const {
193169
auto &cs = getConstraintSystem();
194-
auto &TC = getTypeChecker();
195-
196-
auto *anchor = getRawAnchor();
197-
auto *locator = cs.getConstraintLocator(anchor);
198170

199171
// Get a declaration associated with given type (if any).
200172
// This is used to retrieve affected declaration when
@@ -216,38 +188,7 @@ ValueDecl *RequirementFailure::getDeclRef() const {
216188
if (isFromContextualType())
217189
return getAffectedDeclFromType(cs.getContextualType());
218190

219-
if (auto *AE = dyn_cast<CallExpr>(anchor)) {
220-
// NOTE: In valid code, the function can only be a TypeExpr
221-
assert(isa<TypeExpr>(AE->getFn()) ||
222-
isa<OverloadedDeclRefExpr>(AE->getFn()));
223-
ConstraintLocatorBuilder ctor(locator);
224-
locator = cs.getConstraintLocator(
225-
ctor.withPathElement(PathEltKind::ApplyFunction)
226-
.withPathElement(PathEltKind::ConstructorMember));
227-
} else if (auto *UDE = dyn_cast<UnresolvedDotExpr>(anchor)) {
228-
ConstraintLocatorBuilder member(locator);
229-
230-
if (TC.getSelfForInitDelegationInConstructor(getDC(), UDE)) {
231-
member = member.withPathElement(PathEltKind::ConstructorMember);
232-
} else {
233-
member = member.withPathElement(PathEltKind::Member);
234-
}
235-
236-
locator = cs.getConstraintLocator(member);
237-
} else if (auto *UME = dyn_cast<UnresolvedMemberExpr>(anchor)) {
238-
locator = cs.getConstraintLocator(locator, PathEltKind::UnresolvedMember);
239-
} else if (isa<SubscriptExpr>(anchor)) {
240-
ConstraintLocatorBuilder subscript(locator);
241-
locator = cs.getConstraintLocator(
242-
subscript.withPathElement(PathEltKind::SubscriptMember));
243-
} else if (isa<MemberRefExpr>(anchor)) {
244-
ConstraintLocatorBuilder memberRef(locator);
245-
locator =
246-
cs.getConstraintLocator(memberRef.withPathElement(PathEltKind::Member));
247-
}
248-
249-
auto overload = getOverloadChoiceIfAvailable(locator);
250-
if (overload)
191+
if (auto overload = getChoiceFor(getRawAnchor()))
251192
return overload->choice.getDecl();
252193

253194
return getAffectedDeclFromType(getOwnerType());
@@ -576,32 +517,7 @@ bool NoEscapeFuncToTypeConversionFailure::diagnoseParameterUse() const {
576517

577518
Type NoEscapeFuncToTypeConversionFailure::getParameterTypeFor(
578519
Expr *expr, unsigned paramIdx) const {
579-
auto &cs = getConstraintSystem();
580-
ConstraintLocator *locator = nullptr;
581-
582-
if (auto *call = dyn_cast<CallExpr>(expr)) {
583-
auto *fnExpr = call->getFn();
584-
if (isa<UnresolvedDotExpr>(fnExpr)) {
585-
locator = cs.getConstraintLocator(fnExpr, ConstraintLocator::Member);
586-
} else if (isa<UnresolvedMemberExpr>(fnExpr)) {
587-
locator =
588-
cs.getConstraintLocator(fnExpr, ConstraintLocator::UnresolvedMember);
589-
} else if (auto *TE = dyn_cast<TypeExpr>(fnExpr)) {
590-
locator = cs.getConstraintLocator(call,
591-
{ConstraintLocator::ApplyFunction,
592-
ConstraintLocator::ConstructorMember},
593-
/*summaryFlags=*/0);
594-
} else {
595-
locator = cs.getConstraintLocator(fnExpr);
596-
}
597-
} else if (auto *SE = dyn_cast<SubscriptExpr>(expr)) {
598-
locator = cs.getConstraintLocator(SE, ConstraintLocator::SubscriptMember);
599-
}
600-
601-
if (!locator)
602-
return Type();
603-
604-
auto choice = getOverloadChoiceIfAvailable(locator);
520+
auto choice = getChoiceFor(expr);
605521
if (!choice)
606522
return Type();
607523

lib/Sema/CSDiagnostics.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ class FailureDiagnostic {
156156
/// reference or subscript, nullptr otherwise.
157157
Expr *getArgumentExprFor(Expr *anchor) const;
158158

159-
Optional<SelectedOverload> getChoiceFor(Expr *);
159+
Optional<SelectedOverload> getChoiceFor(Expr *) const;
160160

161161
private:
162162
/// Compute anchor expression associated with current diagnostic.

lib/Sema/ConstraintSystem.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,44 @@ ConstraintLocator *ConstraintSystem::getConstraintLocator(
408408
return getConstraintLocator(anchor, path, builder.getSummaryFlags());
409409
}
410410

411+
ConstraintLocator *ConstraintSystem::getCalleeLocator(Expr *expr) {
412+
if (auto *applyExpr = dyn_cast<ApplyExpr>(expr)) {
413+
auto *fnExpr = applyExpr->getFn();
414+
// For an apply of a metatype, we have a short-form constructor. Unlike
415+
// other locators to callees, these are anchored on the apply expression
416+
// rather than the function expr.
417+
if (simplifyType(getType(fnExpr))->is<AnyMetatypeType>()) {
418+
auto *fnLocator =
419+
getConstraintLocator(applyExpr, ConstraintLocator::ApplyFunction);
420+
return getConstraintLocator(fnLocator,
421+
ConstraintLocator::ConstructorMember);
422+
}
423+
// Otherwise fall through and look for locators anchored on the fn expr.
424+
expr = fnExpr;
425+
}
426+
427+
auto *locator = getConstraintLocator(expr);
428+
if (auto *ude = dyn_cast<UnresolvedDotExpr>(expr)) {
429+
if (TC.getSelfForInitDelegationInConstructor(DC, ude)) {
430+
return getConstraintLocator(locator,
431+
ConstraintLocator::ConstructorMember);
432+
} else {
433+
return getConstraintLocator(locator, ConstraintLocator::Member);
434+
}
435+
}
436+
437+
if (isa<UnresolvedMemberExpr>(expr))
438+
return getConstraintLocator(locator, ConstraintLocator::UnresolvedMember);
439+
440+
if (isa<SubscriptExpr>(expr))
441+
return getConstraintLocator(locator, ConstraintLocator::SubscriptMember);
442+
443+
if (isa<MemberRefExpr>(expr))
444+
return getConstraintLocator(locator, ConstraintLocator::Member);
445+
446+
return locator;
447+
}
448+
411449
Type ConstraintSystem::openUnboundGenericType(UnboundGenericType *unbound,
412450
ConstraintLocatorBuilder locator,
413451
OpenedTypeMap &replacements) {

lib/Sema/ConstraintSystem.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1927,6 +1927,11 @@ class ConstraintSystem {
19271927
return e != ExprWeights.end() ? e->second.second : nullptr;
19281928
}
19291929

1930+
/// Returns a locator describing the callee for a given expression. For
1931+
/// a function application, this is a locator describing the function expr.
1932+
/// For an unresolved dot/member, this is a locator to the member.
1933+
ConstraintLocator *getCalleeLocator(Expr *expr);
1934+
19301935
public:
19311936

19321937
/// Whether we should attempt to fix problems.

test/Constraints/function.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,13 @@ func foo(block: () -> (), other: () -> Int) {
107107
takesAny(other) // expected-error {{converting non-escaping value to 'Any' may allow it to escape}}
108108
}
109109

110+
struct S {
111+
init<T>(_ x: T, _ y: T) {} // expected-note {{generic parameters are always considered '@escaping'}}
112+
init(fn: () -> Int) {
113+
self.init({ 0 }, fn) // expected-error {{converting non-escaping parameter 'fn' to generic parameter 'T' may allow it to escape}}
114+
}
115+
}
116+
110117
protocol P {
111118
associatedtype U
112119
}

test/Constraints/generics.swift

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -704,6 +704,26 @@ func member_ref_with_explicit_init() {
704704
// expected-error@-1 {{generic struct 'S' requires that 'Int' conform to 'P'}}
705705
}
706706

707+
protocol Q {
708+
init<T : P>(_ x: T) // expected-note 2{{where 'T' = 'T'}}
709+
}
710+
711+
struct SR10694 {
712+
init<T : P>(_ x: T) {} // expected-note 2{{where 'T' = 'T'}}
713+
func bar<T>(_ x: T, _ s: SR10694, _ q: Q) {
714+
SR10694.self(x) // expected-error {{initializer 'init(_:)' requires that 'T' conform to 'P'}}
715+
716+
type(of: s)(x) // expected-error {{initializer 'init(_:)' requires that 'T' conform to 'P'}}
717+
// expected-error@-1 {{initializing from a metatype value must reference 'init' explicitly}}
718+
719+
Q.self(x) // expected-error {{initializer 'init(_:)' requires that 'T' conform to 'P'}}
720+
// expected-error@-1 {{protocol type 'Q' cannot be instantiated}}
721+
722+
type(of: q)(x) // expected-error {{initializer 'init(_:)' requires that 'T' conform to 'P'}}
723+
// expected-error@-1 {{initializing from a metatype value must reference 'init' explicitly}}
724+
}
725+
}
726+
707727
func rdar_50007727() {
708728
struct A<T> { // expected-note {{'T' declared as parameter to type 'A'}}
709729
struct B<U> : ExpressibleByStringLiteral {

0 commit comments

Comments
 (0)