Skip to content

Commit cebc084

Browse files
committed
[CS] Fix locator simplification with 'Member' path element
Previously, a `Member` path element in a `ConstraintLocator` was simplified to the base on which the member was accessed. This is incorrect.
1 parent 3644d98 commit cebc084

File tree

8 files changed

+74
-32
lines changed

8 files changed

+74
-32
lines changed

include/swift/Sema/ConstraintLocator.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,11 @@ class ConstraintLocator : public llvm::FoldingSetNode {
313313
/// branch, and if so, the kind of branch.
314314
Optional<SingleValueStmtBranchKind> isForSingleValueStmtBranch() const;
315315

316+
/// Returns true if \p locator is ending with either of the following
317+
/// - Member
318+
/// - Member -> KeyPathDynamicMember
319+
bool isMemberRef() const;
320+
316321
/// Determine whether this locator points directly to a given expression.
317322
template <typename E> bool directlyAt() const {
318323
if (auto *expr = getAnchor().dyn_cast<Expr *>())

lib/Sema/CSDiagnostics.cpp

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -77,13 +77,6 @@ ASTNode FailureDiagnostic::getAnchor() const {
7777
return locator->getAnchor();
7878
}
7979

80-
// FIXME: Work around an odd locator representation that doesn't separate the
81-
// base of a subscript member from the member access.
82-
if (locator->isLastElement<LocatorPathElt::SubscriptMember>()) {
83-
if (auto subscript = getAsExpr<SubscriptExpr>(anchor))
84-
anchor = subscript->getBase();
85-
}
86-
8780
return anchor;
8881
}
8982

@@ -1345,6 +1338,15 @@ bool MissingExplicitConversionFailure::diagnoseAsError() {
13451338
return true;
13461339
}
13471340

1341+
ASTNode MemberReferenceFailure::getAnchor() const {
1342+
auto anchor = FailureDiagnostic::getAnchor();
1343+
if (auto base = getBaseExprFor(getAsExpr(anchor))) {
1344+
return base;
1345+
} else {
1346+
return anchor;
1347+
}
1348+
}
1349+
13481350
SourceRange MemberAccessOnOptionalBaseFailure::getSourceRange() const {
13491351
if (auto componentPathElt =
13501352
getLocator()->getLastElementAs<LocatorPathElt::KeyPathComponent>()) {
@@ -3680,6 +3682,15 @@ bool MissingCallFailure::diagnoseAsError() {
36803682
return true;
36813683
}
36823684

3685+
ASTNode PropertyWrapperReferenceFailure::getAnchor() const {
3686+
auto anchor = FailureDiagnostic::getAnchor();
3687+
if (getReferencedMember()) {
3688+
return getBaseExprFor(getAsExpr(anchor));
3689+
} else {
3690+
return anchor;
3691+
}
3692+
}
3693+
36833694
bool ExtraneousPropertyWrapperUnwrapFailure::diagnoseAsError() {
36843695
auto newPrefix = usingProjection() ? "$" : "_";
36853696

@@ -3751,21 +3762,12 @@ bool SubscriptMisuseFailure::diagnoseAsError() {
37513762
auto &sourceMgr = getASTContext().SourceMgr;
37523763

37533764
auto *memberExpr = castToExpr<UnresolvedDotExpr>(getRawAnchor());
3754-
3755-
auto memberRange = getSourceRange();
3756-
3757-
{
3758-
auto rawAnchor = getRawAnchor();
3759-
auto path = locator->getPath();
3760-
simplifyLocator(rawAnchor, path, memberRange);
3761-
}
3762-
3763-
auto nameLoc = DeclNameLoc(memberRange.Start);
3765+
auto *base = memberExpr->getBase();
37643766

37653767
auto diag = emitDiagnostic(diag::could_not_find_subscript_member_did_you_mean,
3766-
getType(getAnchor()));
3768+
getType(base));
37673769

3768-
diag.highlight(memberRange).highlight(nameLoc.getSourceRange());
3770+
diag.highlight(memberExpr->getNameLoc().getSourceRange());
37693771

37703772
if (auto *parentExpr = dyn_cast_or_null<ApplyExpr>(findParentExpr(memberExpr))) {
37713773
auto *args = parentExpr->getArgs();
@@ -3775,7 +3777,7 @@ bool SubscriptMisuseFailure::diagnoseAsError() {
37753777

37763778
diag.fixItReplace(SourceRange(args->getStartLoc()),
37773779
getTokenText(tok::l_square));
3778-
diag.fixItRemove(nameLoc.getSourceRange());
3780+
diag.fixItRemove(memberExpr->getNameLoc().getSourceRange());
37793781
diag.fixItRemove(SourceRange(memberExpr->getDotLoc()));
37803782

37813783
if (sourceMgr.extractText(lastArgSymbol) == getTokenText(tok::r_paren))

lib/Sema/CSDiagnostics.h

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -534,20 +534,29 @@ class LabelingFailure final : public FailureDiagnostic {
534534
bool diagnoseAsNote() override;
535535
};
536536

537+
/// A diagnostic that will be emitted on the base if its locator points to a
538+
/// member access.
539+
class MemberReferenceFailure : public FailureDiagnostic {
540+
public:
541+
MemberReferenceFailure(const Solution &solution, ConstraintLocator *locator)
542+
: FailureDiagnostic(solution, locator) {}
543+
544+
ASTNode getAnchor() const override;
545+
};
546+
537547
/// Diagnose failures related to attempting member access on optional base
538548
/// type without optional chaining or force-unwrapping it first.
539-
class MemberAccessOnOptionalBaseFailure final : public FailureDiagnostic {
549+
class MemberAccessOnOptionalBaseFailure final : public MemberReferenceFailure {
540550
DeclNameRef Member;
541551
Type MemberBaseType;
542552
bool ResultTypeIsOptional;
543553

544554
public:
545555
MemberAccessOnOptionalBaseFailure(const Solution &solution,
546556
ConstraintLocator *locator,
547-
DeclNameRef memberName,
548-
Type memberBaseType,
557+
DeclNameRef memberName, Type memberBaseType,
549558
bool resultOptional)
550-
: FailureDiagnostic(solution, locator), Member(memberName),
559+
: MemberReferenceFailure(solution, locator), Member(memberName),
551560
MemberBaseType(resolveType(memberBaseType)),
552561
ResultTypeIsOptional(resultOptional) {}
553562

@@ -1127,6 +1136,8 @@ class PropertyWrapperReferenceFailure : public ContextualFailure {
11271136
: ContextualFailure(solution, base, wrapper, locator), Property(property),
11281137
UsingProjection(usingProjection) {}
11291138

1139+
ASTNode getAnchor() const override;
1140+
11301141
VarDecl *getProperty() const { return Property; }
11311142

11321143
Identifier getPropertyName() const { return Property->getName(); }
@@ -1201,14 +1212,14 @@ class SubscriptMisuseFailure final : public FailureDiagnostic {
12011212
bool diagnoseAsNote() override;
12021213
};
12031214

1204-
class InvalidMemberRefFailure : public FailureDiagnostic {
1215+
class InvalidMemberRefFailure : public MemberReferenceFailure {
12051216
Type BaseType;
12061217
DeclNameRef Name;
12071218

12081219
public:
12091220
InvalidMemberRefFailure(const Solution &solution, Type baseType,
12101221
DeclNameRef memberName, ConstraintLocator *locator)
1211-
: FailureDiagnostic(solution, locator),
1222+
: MemberReferenceFailure(solution, locator),
12121223
BaseType(baseType->getRValueType()), Name(memberName) {}
12131224

12141225
protected:
@@ -1334,7 +1345,7 @@ class InvalidMemberRefOnExistential final : public InvalidMemberRefFailure {
13341345
///
13351346
/// }
13361347
/// ```
1337-
class AllowTypeOrInstanceMemberFailure final : public FailureDiagnostic {
1348+
class AllowTypeOrInstanceMemberFailure final : public MemberReferenceFailure {
13381349
Type BaseType;
13391350
ValueDecl *Member;
13401351
DeclNameRef Name;
@@ -1343,7 +1354,7 @@ class AllowTypeOrInstanceMemberFailure final : public FailureDiagnostic {
13431354
AllowTypeOrInstanceMemberFailure(const Solution &solution, Type baseType,
13441355
ValueDecl *member, DeclNameRef name,
13451356
ConstraintLocator *locator)
1346-
: FailureDiagnostic(solution, locator),
1357+
: MemberReferenceFailure(solution, locator),
13471358
BaseType(baseType->getRValueType()), Member(member), Name(name) {
13481359
assert(member);
13491360
}

lib/Sema/CSSimplify.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10538,7 +10538,9 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyMemberConstraint(
1053810538
// let's return, otherwise let's fall-through and report
1053910539
// this problem as a missing member.
1054010540
if (result == SolutionKind::Solved)
10541-
return recordFix(InsertExplicitCall::create(*this, locator))
10541+
return recordFix(InsertExplicitCall::create(
10542+
*this, getConstraintLocator(
10543+
locator, ConstraintLocator::MemberRefBase)))
1054210544
? SolutionKind::Error
1054310545
: SolutionKind::Solved;
1054410546
}

lib/Sema/ConstraintLocator.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -662,6 +662,19 @@ ConstraintLocator::isForSingleValueStmtBranch() const {
662662
return SingleValueStmtBranchKind::Regular;
663663
}
664664

665+
bool ConstraintLocator::isMemberRef() const {
666+
if (isLastElement<LocatorPathElt::Member>()) {
667+
return true;
668+
} else if (isLastElement<LocatorPathElt::KeyPathDynamicMember>()) {
669+
auto path = getPath();
670+
if (path.size() >= 2 &&
671+
path[path.size() - 2].is<LocatorPathElt::Member>()) {
672+
return true;
673+
}
674+
}
675+
return false;
676+
}
677+
665678
GenericTypeParamType *ConstraintLocator::getGenericParameter() const {
666679
// Check whether we have a path that terminates at a generic parameter.
667680
return isForGenericParameter() ?

lib/Sema/ConstraintSystem.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5469,6 +5469,15 @@ void constraints::simplifyLocator(ASTNode &anchor,
54695469
LLVM_FALLTHROUGH;
54705470

54715471
case ConstraintLocator::Member:
5472+
if (auto UDE = getAsExpr<UnresolvedDotExpr>(anchor)) {
5473+
path = path.slice(1);
5474+
continue;
5475+
}
5476+
if (anchor.is<Pattern *>()) {
5477+
path = path.slice(1);
5478+
continue;
5479+
}
5480+
break;
54725481
case ConstraintLocator::MemberRefBase:
54735482
if (auto UDE = getAsExpr<UnresolvedDotExpr>(anchor)) {
54745483
range = UDE->getNameLoc().getSourceRange();

test/Constraints/rdar46544601.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@ extension P {
2222
func crash(_ p: P, payload: [UInt8]) throws {
2323
p.foo(data: payload).then { _ in
2424
return Future<(D, [D])>()
25-
}.then { (id, arr) in // expected-error {{generic parameter 'U' could not be inferred}}
25+
}.then { (id, arr) in
2626
p.foo(arr: arr, data: []).and(result: (id, arr))
27-
}.then { args0 in
27+
}.then { args0 in // expected-error {{generic parameter 'U' could not be inferred}}
2828
let (parentID, args1) = args0
2929
p.bar(root: parentID, from: p).and(result: args1)
3030
}.whenFailure { _ in }

test/Misc/serialized-diagnostics-prettyprint.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
// RUN: %FileCheck --input-file=%t.deserialized_diagnostics.txt %s
77

88
var x = String.init // expected-error{{ambiguous use of 'init'}}
9-
// CHECK: {{.*[/\\]}}serialized-diagnostics-prettyprint.swift:[[@LINE-1]]:9: error: ambiguous use of 'init'
9+
// CHECK: {{.*[/\\]}}serialized-diagnostics-prettyprint.swift:[[@LINE-1]]:16: error: ambiguous use of 'init'
1010

1111
// CHECK: Swift.String:2:23: note: found this candidate
1212
// CHECK: CONTENTS OF FILE Swift.String:

0 commit comments

Comments
 (0)