mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[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:
@@ -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 *>())
|
||||||
|
|||||||
@@ -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))
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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() ?
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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 }
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
Reference in New Issue
Block a user