Skip to content

Commit 259eed9

Browse files
authored
Merge pull request #5812 from xedin/r25341015
[QoI] Improve diagnostics for type member names shadowing top-level functions
2 parents 8747cf2 + f1905e8 commit 259eed9

File tree

3 files changed

+229
-0
lines changed

3 files changed

+229
-0
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -836,6 +836,11 @@ ERROR(argument_out_of_order_unnamed_unnamed,none,
836836
"unnamed argument #%0 must precede unnamed argument #%1",
837837
(unsigned, unsigned))
838838

839+
ERROR(member_shadows_global_function,none,
840+
"use of %0 refers to %1 %2 rather than %3 %4 in %5 %6",
841+
(DeclName, DescriptiveDeclKind, DeclName, DescriptiveDeclKind, DeclName,
842+
DescriptiveDeclKind, DeclName))
843+
839844
ERROR(instance_member_use_on_type,none,
840845
"use of instance member %1 on type %0; "
841846
"did you mean to use a value of type %0 instead?", (Type, DeclName))

lib/Sema/CSDiag.cpp

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4581,6 +4581,186 @@ typeCheckArgumentChildIndependently(Expr *argExpr, Type argType,
45814581
TE->isImplicit(), TT);
45824582
}
45834583

4584+
static bool diagnoseImplicitSelfErrors(Expr *fnExpr, Expr *argExpr,
4585+
CalleeCandidateInfo &CCI,
4586+
ArrayRef<Identifier> argLabels,
4587+
ConstraintSystem *CS) {
4588+
// If candidate list is empty it means that problem is somewhere else,
4589+
// since we need to have candidates which might be shadowing other funcs.
4590+
if (CCI.empty() || !CCI[0].getDecl())
4591+
return false;
4592+
4593+
auto &TC = CS->TC;
4594+
// Call expression is formed as 'foo.bar' where 'foo' might be an
4595+
// implicit "Self" reference, such use wouldn't provide good diagnostics
4596+
// for situations where instance members have equal names to functions in
4597+
// Swift Standard Library e.g. min/max.
4598+
auto UDE = dyn_cast<UnresolvedDotExpr>(fnExpr);
4599+
if (!UDE)
4600+
return false;
4601+
4602+
auto baseExpr = dyn_cast<DeclRefExpr>(UDE->getBase());
4603+
if (!baseExpr)
4604+
return false;
4605+
4606+
auto baseDecl = baseExpr->getDecl();
4607+
if (!baseExpr->isImplicit() || baseDecl->getName() != TC.Context.Id_self)
4608+
return false;
4609+
4610+
// Our base expression is an implicit 'self.' reference e.g.
4611+
//
4612+
// extension Sequence {
4613+
// func test() -> Int {
4614+
// return max(1, 2)
4615+
// }
4616+
// }
4617+
//
4618+
// In this example the Sequence class already has two methods named 'max'
4619+
// none of which accept two arguments, but there is a function in
4620+
// Swift Standard Library called 'max' which does accept two arguments,
4621+
// so user might have called that by mistake without realizing that
4622+
// compiler would add implicit 'self.' prefix to the call of 'max'.
4623+
ExprCleaner cleanup(argExpr);
4624+
4625+
// Let's type check argument expression without any contextual information.
4626+
ConcreteDeclRef ref = nullptr;
4627+
auto typeResult = TC.getTypeOfExpressionWithoutApplying(argExpr, CS->DC, ref);
4628+
if (!typeResult.hasValue())
4629+
return false;
4630+
4631+
auto argType = typeResult.getValue();
4632+
4633+
// If argument type couldn't be properly resolved or has errors,
4634+
// we can't diagnose anything in here, it points to the different problem.
4635+
if (isUnresolvedOrTypeVarType(argType) || argType->hasError())
4636+
return false;
4637+
4638+
auto context = CS->DC;
4639+
using CandididateMap =
4640+
llvm::SmallDenseMap<ValueDecl *, llvm::SmallVector<OverloadChoice, 2>>;
4641+
4642+
auto getBaseKind = [](ValueDecl *base) -> DescriptiveDeclKind {
4643+
DescriptiveDeclKind kind = DescriptiveDeclKind::Module;
4644+
if (!base)
4645+
return kind;
4646+
4647+
auto context = base->getDeclContext();
4648+
do {
4649+
if (isa<ExtensionDecl>(context))
4650+
return DescriptiveDeclKind::Extension;
4651+
4652+
if (auto nominal = dyn_cast<NominalTypeDecl>(context)) {
4653+
kind = nominal->getDescriptiveKind();
4654+
break;
4655+
}
4656+
4657+
context = context->getParent();
4658+
} while (context);
4659+
4660+
return kind;
4661+
};
4662+
4663+
auto getBaseName = [](DeclContext *context) -> DeclName {
4664+
if (context->isTypeContext()) {
4665+
auto generic = context->getAsGenericTypeOrGenericTypeExtensionContext();
4666+
return generic->getName();
4667+
} else if (context->isModuleScopeContext())
4668+
return context->getParentModule()->getName();
4669+
else
4670+
llvm_unreachable("Unsupported base");
4671+
};
4672+
4673+
auto diagnoseShadowing = [&](ValueDecl *base,
4674+
ArrayRef<OverloadChoice> candidates) -> bool {
4675+
CalleeCandidateInfo calleeInfo(base ? base->getInterfaceType() : nullptr,
4676+
candidates, CCI.hasTrailingClosure, CS,
4677+
base);
4678+
4679+
calleeInfo.filterList(argType, argLabels);
4680+
if (calleeInfo.closeness != CC_ExactMatch)
4681+
return false;
4682+
4683+
auto choice = calleeInfo.candidates[0].getDecl();
4684+
auto baseKind = getBaseKind(base);
4685+
auto baseName = getBaseName(choice->getDeclContext());
4686+
4687+
auto origCandidate = CCI[0].getDecl();
4688+
TC.diagnose(UDE->getLoc(), diag::member_shadows_global_function,
4689+
UDE->getName(), origCandidate->getDescriptiveKind(),
4690+
origCandidate->getFullName(), choice->getDescriptiveKind(),
4691+
choice->getFullName(), baseKind, baseName);
4692+
4693+
auto topLevelDiag = diag::fix_unqualified_access_top_level;
4694+
if (baseKind == DescriptiveDeclKind::Module)
4695+
topLevelDiag = diag::fix_unqualified_access_top_level_multi;
4696+
4697+
auto name = baseName.getBaseName();
4698+
SmallString<32> namePlusDot = name.str();
4699+
namePlusDot.push_back('.');
4700+
4701+
TC.diagnose(UDE->getLoc(), topLevelDiag, namePlusDot,
4702+
choice->getDescriptiveKind(), name)
4703+
.fixItInsert(UDE->getStartLoc(), namePlusDot);
4704+
4705+
for (auto &candidate : calleeInfo.candidates) {
4706+
if (auto decl = candidate.getDecl())
4707+
TC.diagnose(decl, diag::decl_declared_here, decl->getFullName());
4708+
}
4709+
4710+
return true;
4711+
};
4712+
4713+
// For each of the parent contexts, let's try to find any candidates
4714+
// which have the same name and the same number of arguments as callee.
4715+
while (context->getParent()) {
4716+
auto result = TC.lookupUnqualified(context, UDE->getName(), UDE->getLoc());
4717+
context = context->getParent();
4718+
4719+
if (!result || result.empty())
4720+
continue;
4721+
4722+
CandididateMap candidates;
4723+
for (const auto &candidate : result) {
4724+
auto base = candidate.Base;
4725+
if ((base && base->isInvalid()) || candidate->isInvalid())
4726+
continue;
4727+
4728+
// If base is present but it doesn't represent a valid nominal,
4729+
// we can't use current candidate as one of the choices.
4730+
if (base && !base->getInterfaceType()->getNominalOrBoundGenericNominal())
4731+
continue;
4732+
4733+
auto context = candidate->getDeclContext();
4734+
// We are only interested in static or global functions, because
4735+
// there is no way to call anything else properly.
4736+
if (!candidate->isStatic() && !context->isModuleScopeContext())
4737+
continue;
4738+
4739+
OverloadChoice choice(base ? base->getInterfaceType() : nullptr,
4740+
candidate, false, UDE->getFunctionRefKind());
4741+
4742+
if (base) { // Let's group all of the candidates have a common base.
4743+
candidates[base].push_back(choice);
4744+
continue;
4745+
}
4746+
4747+
// If there is no base, it means this is one of the global functions,
4748+
// let's try to diagnose its shadowing inline.
4749+
if (diagnoseShadowing(base, choice))
4750+
return true;
4751+
}
4752+
4753+
if (candidates.empty())
4754+
continue;
4755+
4756+
for (const auto &candidate : candidates) {
4757+
if (diagnoseShadowing(candidate.getFirst(), candidate.getSecond()))
4758+
return true;
4759+
}
4760+
}
4761+
4762+
return false;
4763+
}
45844764

45854765
/// Emit a class of diagnostics that we only know how to generate when there is
45864766
/// exactly one candidate we know about. Return true if an error is emitted.
@@ -4984,6 +5164,10 @@ bool FailureDiagnosis::diagnoseParameterErrors(CalleeCandidateInfo &CCI,
49845164
}
49855165
}
49865166

5167+
// Try to diagnose errors related to the use of implicit self reference.
5168+
if (diagnoseImplicitSelfErrors(fnExpr, argExpr, CCI, argLabels, CS))
5169+
return true;
5170+
49875171
// Do all the stuff that we only have implemented when there is a single
49885172
// candidate.
49895173
if (diagnoseSingleCandidateFailures(CCI, fnExpr, argExpr, argLabels))

test/Constraints/members.swift

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -590,3 +590,43 @@ do {
590590
throw SR_2193_Error.Boom
591591
} catch let e as SR_2193_Error.Boom { // expected-error {{enum element 'Boom' is not a member type of 'SR_2193_Error'}}
592592
}
593+
594+
// rdar://problem/25341015
595+
extension Sequence {
596+
func r25341015_1() -> Int {
597+
return max(1, 2) // expected-error {{use of 'max' refers to instance method 'max(by:)' rather than global function 'max' in module 'Swift'}} expected-note {{use 'Swift.' to reference the global function in module 'Swift'}}
598+
}
599+
}
600+
601+
class C_25341015 {
602+
static func baz(_ x: Int, _ y: Int) {} // expected-note {{'baz' declared here}}
603+
func baz() {}
604+
func qux() {
605+
baz(1, 2) // expected-error {{use of 'baz' refers to instance method 'baz()' rather than static method 'baz' in class 'C_25341015'}} expected-note {{use 'C_25341015.' to reference the static method}}
606+
}
607+
}
608+
609+
struct S_25341015 {
610+
static func foo(_ x: Int, y: Int) {} // expected-note {{'foo(_:y:)' declared here}}
611+
612+
func foo(z: Int) {}
613+
func bar() {
614+
foo(1, y: 2) // expected-error {{use of 'foo' refers to instance method 'foo(z:)' rather than static method 'foo(_:y:)' in struct 'S_25341015'}} expected-note {{use 'S_25341015.' to reference the static method}}
615+
}
616+
}
617+
618+
func r25341015() {
619+
func baz(_ x: Int, _ y: Int) {}
620+
class Bar {
621+
func baz() {}
622+
func qux() {
623+
baz(1, 2) // expected-error {{argument passed to call that takes no arguments}}
624+
}
625+
}
626+
}
627+
628+
func r25341015_local(x: Int, y: Int) {}
629+
func r25341015_inner() {
630+
func r25341015_local() {}
631+
r25341015_local(x: 1, y: 2) // expected-error {{argument passed to call that takes no arguments}}
632+
}

0 commit comments

Comments
 (0)