Skip to content

Commit 894a1e5

Browse files
committed
[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.
1 parent 30be693 commit 894a1e5

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
@@ -101,33 +101,9 @@ Expr *FailureDiagnostic::getArgumentExprFor(Expr *anchor) const {
101101
return nullptr;
102102
}
103103

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

133109
Type RequirementFailure::getOwnerType() const {
@@ -179,10 +155,6 @@ ProtocolConformance *RequirementFailure::getConformanceForConditionalReq(
179155

180156
ValueDecl *RequirementFailure::getDeclRef() const {
181157
auto &cs = getConstraintSystem();
182-
auto &TC = getTypeChecker();
183-
184-
auto *anchor = getRawAnchor();
185-
auto *locator = cs.getConstraintLocator(anchor);
186158

187159
// Get a declaration associated with given type (if any).
188160
// This is used to retrieve affected declaration when
@@ -204,38 +176,7 @@ ValueDecl *RequirementFailure::getDeclRef() const {
204176
if (isFromContextualType())
205177
return getAffectedDeclFromType(cs.getContextualType());
206178

207-
if (auto *AE = dyn_cast<CallExpr>(anchor)) {
208-
// NOTE: In valid code, the function can only be a TypeExpr
209-
assert(isa<TypeExpr>(AE->getFn()) ||
210-
isa<OverloadedDeclRefExpr>(AE->getFn()));
211-
ConstraintLocatorBuilder ctor(locator);
212-
locator = cs.getConstraintLocator(
213-
ctor.withPathElement(PathEltKind::ApplyFunction)
214-
.withPathElement(PathEltKind::ConstructorMember));
215-
} else if (auto *UDE = dyn_cast<UnresolvedDotExpr>(anchor)) {
216-
ConstraintLocatorBuilder member(locator);
217-
218-
if (TC.getSelfForInitDelegationInConstructor(getDC(), UDE)) {
219-
member = member.withPathElement(PathEltKind::ConstructorMember);
220-
} else {
221-
member = member.withPathElement(PathEltKind::Member);
222-
}
223-
224-
locator = cs.getConstraintLocator(member);
225-
} else if (auto *UME = dyn_cast<UnresolvedMemberExpr>(anchor)) {
226-
locator = cs.getConstraintLocator(locator, PathEltKind::UnresolvedMember);
227-
} else if (isa<SubscriptExpr>(anchor)) {
228-
ConstraintLocatorBuilder subscript(locator);
229-
locator = cs.getConstraintLocator(
230-
subscript.withPathElement(PathEltKind::SubscriptMember));
231-
} else if (isa<MemberRefExpr>(anchor)) {
232-
ConstraintLocatorBuilder memberRef(locator);
233-
locator =
234-
cs.getConstraintLocator(memberRef.withPathElement(PathEltKind::Member));
235-
}
236-
237-
auto overload = getOverloadChoiceIfAvailable(locator);
238-
if (overload)
179+
if (auto overload = getChoiceFor(getRawAnchor()))
239180
return overload->choice.getDecl();
240181

241182
return getAffectedDeclFromType(getOwnerType());
@@ -568,32 +509,7 @@ bool NoEscapeFuncToTypeConversionFailure::diagnoseParameterUse() const {
568509

569510
Type NoEscapeFuncToTypeConversionFailure::getParameterTypeFor(
570511
Expr *expr, unsigned paramIdx) const {
571-
auto &cs = getConstraintSystem();
572-
ConstraintLocator *locator = nullptr;
573-
574-
if (auto *call = dyn_cast<CallExpr>(expr)) {
575-
auto *fnExpr = call->getFn();
576-
if (isa<UnresolvedDotExpr>(fnExpr)) {
577-
locator = cs.getConstraintLocator(fnExpr, ConstraintLocator::Member);
578-
} else if (isa<UnresolvedMemberExpr>(fnExpr)) {
579-
locator =
580-
cs.getConstraintLocator(fnExpr, ConstraintLocator::UnresolvedMember);
581-
} else if (auto *TE = dyn_cast<TypeExpr>(fnExpr)) {
582-
locator = cs.getConstraintLocator(call,
583-
{ConstraintLocator::ApplyFunction,
584-
ConstraintLocator::ConstructorMember},
585-
/*summaryFlags=*/0);
586-
} else {
587-
locator = cs.getConstraintLocator(fnExpr);
588-
}
589-
} else if (auto *SE = dyn_cast<SubscriptExpr>(expr)) {
590-
locator = cs.getConstraintLocator(SE, ConstraintLocator::SubscriptMember);
591-
}
592-
593-
if (!locator)
594-
return Type();
595-
596-
auto choice = getOverloadChoiceIfAvailable(locator);
512+
auto choice = getChoiceFor(expr);
597513
if (!choice)
598514
return Type();
599515

lib/Sema/CSDiagnostics.h

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

158-
Optional<SelectedOverload> getChoiceFor(Expr *);
158+
Optional<SelectedOverload> getChoiceFor(Expr *) const;
159159

160160
private:
161161
/// 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
@@ -411,6 +411,44 @@ ConstraintLocator *ConstraintSystem::getConstraintLocator(
411411
return getConstraintLocator(anchor, path, builder.getSummaryFlags());
412412
}
413413

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

lib/Sema/ConstraintSystem.h

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

1919+
/// Returns a locator describing the callee for a given expression. For
1920+
/// a function application, this is a locator describing the function expr.
1921+
/// For an unresolved dot/member, this is a locator to the member.
1922+
ConstraintLocator *getCalleeLocator(Expr *expr);
1923+
19191924
public:
19201925

19211926
/// 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
@@ -687,3 +687,23 @@ func member_ref_with_explicit_init() {
687687
_ = S.init(42)
688688
// expected-error@-1 {{generic struct 'S' requires that 'Int' conform to 'P'}}
689689
}
690+
691+
protocol Q {
692+
init<T : P>(_ x: T) // expected-note 2{{where 'T' = 'T'}}
693+
}
694+
695+
struct SR10694 {
696+
init<T : P>(_ x: T) {} // expected-note 2{{where 'T' = 'T'}}
697+
func bar<T>(_ x: T, _ s: SR10694, _ q: Q) {
698+
SR10694.self(x) // expected-error {{initializer 'init(_:)' requires that 'T' conform to 'P'}}
699+
700+
type(of: s)(x) // expected-error {{initializer 'init(_:)' requires that 'T' conform to 'P'}}
701+
// expected-error@-1 {{initializing from a metatype value must reference 'init' explicitly}}
702+
703+
Q.self(x) // expected-error {{initializer 'init(_:)' requires that 'T' conform to 'P'}}
704+
// expected-error@-1 {{protocol type 'Q' cannot be instantiated}}
705+
706+
type(of: q)(x) // expected-error {{initializer 'init(_:)' requires that 'T' conform to 'P'}}
707+
// expected-error@-1 {{initializing from a metatype value must reference 'init' explicitly}}
708+
}
709+
}

0 commit comments

Comments
 (0)