[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.
This commit is contained in:
Alex Hoppen
2023-03-15 18:43:53 -07:00
parent 3644d98d5f
commit cebc084367
8 changed files with 74 additions and 32 deletions

View File

@@ -313,6 +313,11 @@ public:
/// branch, and if so, the kind of branch. /// branch, and if so, the kind of branch.
Optional<SingleValueStmtBranchKind> isForSingleValueStmtBranch() const; Optional<SingleValueStmtBranchKind> isForSingleValueStmtBranch() const;
/// Returns true if \p locator is ending with either of the following
/// - Member
/// - Member -> KeyPathDynamicMember
bool isMemberRef() const;
/// Determine whether this locator points directly to a given expression. /// Determine whether this locator points directly to a given expression.
template <typename E> bool directlyAt() const { template <typename E> bool directlyAt() const {
if (auto *expr = getAnchor().dyn_cast<Expr *>()) if (auto *expr = getAnchor().dyn_cast<Expr *>())

View File

@@ -77,13 +77,6 @@ ASTNode FailureDiagnostic::getAnchor() const {
return locator->getAnchor(); return locator->getAnchor();
} }
// FIXME: Work around an odd locator representation that doesn't separate the
// base of a subscript member from the member access.
if (locator->isLastElement<LocatorPathElt::SubscriptMember>()) {
if (auto subscript = getAsExpr<SubscriptExpr>(anchor))
anchor = subscript->getBase();
}
return anchor; return anchor;
} }
@@ -1345,6 +1338,15 @@ bool MissingExplicitConversionFailure::diagnoseAsError() {
return true; return true;
} }
ASTNode MemberReferenceFailure::getAnchor() const {
auto anchor = FailureDiagnostic::getAnchor();
if (auto base = getBaseExprFor(getAsExpr(anchor))) {
return base;
} else {
return anchor;
}
}
SourceRange MemberAccessOnOptionalBaseFailure::getSourceRange() const { SourceRange MemberAccessOnOptionalBaseFailure::getSourceRange() const {
if (auto componentPathElt = if (auto componentPathElt =
getLocator()->getLastElementAs<LocatorPathElt::KeyPathComponent>()) { getLocator()->getLastElementAs<LocatorPathElt::KeyPathComponent>()) {
@@ -3680,6 +3682,15 @@ bool MissingCallFailure::diagnoseAsError() {
return true; return true;
} }
ASTNode PropertyWrapperReferenceFailure::getAnchor() const {
auto anchor = FailureDiagnostic::getAnchor();
if (getReferencedMember()) {
return getBaseExprFor(getAsExpr(anchor));
} else {
return anchor;
}
}
bool ExtraneousPropertyWrapperUnwrapFailure::diagnoseAsError() { bool ExtraneousPropertyWrapperUnwrapFailure::diagnoseAsError() {
auto newPrefix = usingProjection() ? "$" : "_"; auto newPrefix = usingProjection() ? "$" : "_";
@@ -3751,21 +3762,12 @@ bool SubscriptMisuseFailure::diagnoseAsError() {
auto &sourceMgr = getASTContext().SourceMgr; auto &sourceMgr = getASTContext().SourceMgr;
auto *memberExpr = castToExpr<UnresolvedDotExpr>(getRawAnchor()); auto *memberExpr = castToExpr<UnresolvedDotExpr>(getRawAnchor());
auto *base = memberExpr->getBase();
auto memberRange = getSourceRange();
{
auto rawAnchor = getRawAnchor();
auto path = locator->getPath();
simplifyLocator(rawAnchor, path, memberRange);
}
auto nameLoc = DeclNameLoc(memberRange.Start);
auto diag = emitDiagnostic(diag::could_not_find_subscript_member_did_you_mean, auto diag = emitDiagnostic(diag::could_not_find_subscript_member_did_you_mean,
getType(getAnchor())); getType(base));
diag.highlight(memberRange).highlight(nameLoc.getSourceRange()); diag.highlight(memberExpr->getNameLoc().getSourceRange());
if (auto *parentExpr = dyn_cast_or_null<ApplyExpr>(findParentExpr(memberExpr))) { if (auto *parentExpr = dyn_cast_or_null<ApplyExpr>(findParentExpr(memberExpr))) {
auto *args = parentExpr->getArgs(); auto *args = parentExpr->getArgs();
@@ -3775,7 +3777,7 @@ bool SubscriptMisuseFailure::diagnoseAsError() {
diag.fixItReplace(SourceRange(args->getStartLoc()), diag.fixItReplace(SourceRange(args->getStartLoc()),
getTokenText(tok::l_square)); getTokenText(tok::l_square));
diag.fixItRemove(nameLoc.getSourceRange()); diag.fixItRemove(memberExpr->getNameLoc().getSourceRange());
diag.fixItRemove(SourceRange(memberExpr->getDotLoc())); diag.fixItRemove(SourceRange(memberExpr->getDotLoc()));
if (sourceMgr.extractText(lastArgSymbol) == getTokenText(tok::r_paren)) if (sourceMgr.extractText(lastArgSymbol) == getTokenText(tok::r_paren))

View File

@@ -534,9 +534,19 @@ public:
bool diagnoseAsNote() override; bool diagnoseAsNote() override;
}; };
/// A diagnostic that will be emitted on the base if its locator points to a
/// member access.
class MemberReferenceFailure : public FailureDiagnostic {
public:
MemberReferenceFailure(const Solution &solution, ConstraintLocator *locator)
: FailureDiagnostic(solution, locator) {}
ASTNode getAnchor() const override;
};
/// Diagnose failures related to attempting member access on optional base /// Diagnose failures related to attempting member access on optional base
/// type without optional chaining or force-unwrapping it first. /// type without optional chaining or force-unwrapping it first.
class MemberAccessOnOptionalBaseFailure final : public FailureDiagnostic { class MemberAccessOnOptionalBaseFailure final : public MemberReferenceFailure {
DeclNameRef Member; DeclNameRef Member;
Type MemberBaseType; Type MemberBaseType;
bool ResultTypeIsOptional; bool ResultTypeIsOptional;
@@ -544,10 +554,9 @@ class MemberAccessOnOptionalBaseFailure final : public FailureDiagnostic {
public: public:
MemberAccessOnOptionalBaseFailure(const Solution &solution, MemberAccessOnOptionalBaseFailure(const Solution &solution,
ConstraintLocator *locator, ConstraintLocator *locator,
DeclNameRef memberName, DeclNameRef memberName, Type memberBaseType,
Type memberBaseType,
bool resultOptional) bool resultOptional)
: FailureDiagnostic(solution, locator), Member(memberName), : MemberReferenceFailure(solution, locator), Member(memberName),
MemberBaseType(resolveType(memberBaseType)), MemberBaseType(resolveType(memberBaseType)),
ResultTypeIsOptional(resultOptional) {} ResultTypeIsOptional(resultOptional) {}
@@ -1127,6 +1136,8 @@ public:
: ContextualFailure(solution, base, wrapper, locator), Property(property), : ContextualFailure(solution, base, wrapper, locator), Property(property),
UsingProjection(usingProjection) {} UsingProjection(usingProjection) {}
ASTNode getAnchor() const override;
VarDecl *getProperty() const { return Property; } VarDecl *getProperty() const { return Property; }
Identifier getPropertyName() const { return Property->getName(); } Identifier getPropertyName() const { return Property->getName(); }
@@ -1201,14 +1212,14 @@ public:
bool diagnoseAsNote() override; bool diagnoseAsNote() override;
}; };
class InvalidMemberRefFailure : public FailureDiagnostic { class InvalidMemberRefFailure : public MemberReferenceFailure {
Type BaseType; Type BaseType;
DeclNameRef Name; DeclNameRef Name;
public: public:
InvalidMemberRefFailure(const Solution &solution, Type baseType, InvalidMemberRefFailure(const Solution &solution, Type baseType,
DeclNameRef memberName, ConstraintLocator *locator) DeclNameRef memberName, ConstraintLocator *locator)
: FailureDiagnostic(solution, locator), : MemberReferenceFailure(solution, locator),
BaseType(baseType->getRValueType()), Name(memberName) {} BaseType(baseType->getRValueType()), Name(memberName) {}
protected: protected:
@@ -1334,7 +1345,7 @@ public:
/// ///
/// } /// }
/// ``` /// ```
class AllowTypeOrInstanceMemberFailure final : public FailureDiagnostic { class AllowTypeOrInstanceMemberFailure final : public MemberReferenceFailure {
Type BaseType; Type BaseType;
ValueDecl *Member; ValueDecl *Member;
DeclNameRef Name; DeclNameRef Name;
@@ -1343,7 +1354,7 @@ public:
AllowTypeOrInstanceMemberFailure(const Solution &solution, Type baseType, AllowTypeOrInstanceMemberFailure(const Solution &solution, Type baseType,
ValueDecl *member, DeclNameRef name, ValueDecl *member, DeclNameRef name,
ConstraintLocator *locator) ConstraintLocator *locator)
: FailureDiagnostic(solution, locator), : MemberReferenceFailure(solution, locator),
BaseType(baseType->getRValueType()), Member(member), Name(name) { BaseType(baseType->getRValueType()), Member(member), Name(name) {
assert(member); assert(member);
} }

View File

@@ -10538,7 +10538,9 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyMemberConstraint(
// let's return, otherwise let's fall-through and report // let's return, otherwise let's fall-through and report
// this problem as a missing member. // this problem as a missing member.
if (result == SolutionKind::Solved) if (result == SolutionKind::Solved)
return recordFix(InsertExplicitCall::create(*this, locator)) return recordFix(InsertExplicitCall::create(
*this, getConstraintLocator(
locator, ConstraintLocator::MemberRefBase)))
? SolutionKind::Error ? SolutionKind::Error
: SolutionKind::Solved; : SolutionKind::Solved;
} }

View File

@@ -662,6 +662,19 @@ ConstraintLocator::isForSingleValueStmtBranch() const {
return SingleValueStmtBranchKind::Regular; return SingleValueStmtBranchKind::Regular;
} }
bool ConstraintLocator::isMemberRef() const {
if (isLastElement<LocatorPathElt::Member>()) {
return true;
} else if (isLastElement<LocatorPathElt::KeyPathDynamicMember>()) {
auto path = getPath();
if (path.size() >= 2 &&
path[path.size() - 2].is<LocatorPathElt::Member>()) {
return true;
}
}
return false;
}
GenericTypeParamType *ConstraintLocator::getGenericParameter() const { GenericTypeParamType *ConstraintLocator::getGenericParameter() const {
// Check whether we have a path that terminates at a generic parameter. // Check whether we have a path that terminates at a generic parameter.
return isForGenericParameter() ? return isForGenericParameter() ?

View File

@@ -5469,6 +5469,15 @@ void constraints::simplifyLocator(ASTNode &anchor,
LLVM_FALLTHROUGH; LLVM_FALLTHROUGH;
case ConstraintLocator::Member: case ConstraintLocator::Member:
if (auto UDE = getAsExpr<UnresolvedDotExpr>(anchor)) {
path = path.slice(1);
continue;
}
if (anchor.is<Pattern *>()) {
path = path.slice(1);
continue;
}
break;
case ConstraintLocator::MemberRefBase: case ConstraintLocator::MemberRefBase:
if (auto UDE = getAsExpr<UnresolvedDotExpr>(anchor)) { if (auto UDE = getAsExpr<UnresolvedDotExpr>(anchor)) {
range = UDE->getNameLoc().getSourceRange(); range = UDE->getNameLoc().getSourceRange();

View File

@@ -22,9 +22,9 @@ extension P {
func crash(_ p: P, payload: [UInt8]) throws { func crash(_ p: P, payload: [UInt8]) throws {
p.foo(data: payload).then { _ in p.foo(data: payload).then { _ in
return Future<(D, [D])>() return Future<(D, [D])>()
}.then { (id, arr) in // expected-error {{generic parameter 'U' could not be inferred}} }.then { (id, arr) in
p.foo(arr: arr, data: []).and(result: (id, arr)) p.foo(arr: arr, data: []).and(result: (id, arr))
}.then { args0 in }.then { args0 in // expected-error {{generic parameter 'U' could not be inferred}}
let (parentID, args1) = args0 let (parentID, args1) = args0
p.bar(root: parentID, from: p).and(result: args1) p.bar(root: parentID, from: p).and(result: args1)
}.whenFailure { _ in } }.whenFailure { _ in }

View File

@@ -6,7 +6,7 @@
// RUN: %FileCheck --input-file=%t.deserialized_diagnostics.txt %s // RUN: %FileCheck --input-file=%t.deserialized_diagnostics.txt %s
var x = String.init // expected-error{{ambiguous use of 'init'}} var x = String.init // expected-error{{ambiguous use of 'init'}}
// CHECK: {{.*[/\\]}}serialized-diagnostics-prettyprint.swift:[[@LINE-1]]:9: error: ambiguous use of 'init' // CHECK: {{.*[/\\]}}serialized-diagnostics-prettyprint.swift:[[@LINE-1]]:16: error: ambiguous use of 'init'
// CHECK: Swift.String:2:23: note: found this candidate // CHECK: Swift.String:2:23: note: found this candidate
// CHECK: CONTENTS OF FILE Swift.String: // CHECK: CONTENTS OF FILE Swift.String: