Skip to content

Commit d24537f

Browse files
authored
Merge pull request #29024 from xedin/diagnose-shadowing
[Diagnostics] Port name shadowing diagnostics
2 parents 3e4e078 + 15c1b4e commit d24537f

21 files changed

+205
-329
lines changed

include/swift/AST/Decl.h

+9-2
Original file line numberDiff line numberDiff line change
@@ -335,7 +335,7 @@ class alignas(1 << DeclAlignInBits) Decl {
335335
IsStatic : 1
336336
);
337337

338-
SWIFT_INLINE_BITFIELD(VarDecl, AbstractStorageDecl, 1+1+1+1+1+1+1,
338+
SWIFT_INLINE_BITFIELD(VarDecl, AbstractStorageDecl, 1+1+1+1+1+1+1+1,
339339
/// Encodes whether this is a 'let' binding.
340340
Introducer : 1,
341341

@@ -358,7 +358,10 @@ class alignas(1 << DeclAlignInBits) Decl {
358358
IsLazyStorageProperty : 1,
359359

360360
/// Whether this is the backing storage for a property wrapper.
361-
IsPropertyWrapperBackingProperty : 1
361+
IsPropertyWrapperBackingProperty : 1,
362+
363+
/// Whether this is a lazily top-level global variable from the main file.
364+
IsTopLevelGlobal : 1
362365
);
363366

364367
SWIFT_INLINE_BITFIELD(ParamDecl, VarDecl, 1+2+NumDefaultArgumentKindBits,
@@ -5084,6 +5087,10 @@ class VarDecl : public AbstractStorageDecl {
50845087
Bits.VarDecl.IsLazyStorageProperty = IsLazyStorage;
50855088
}
50865089

5090+
/// True if this is a top-level global variable from the main source file.
5091+
bool isTopLevelGlobal() const { return Bits.VarDecl.IsTopLevelGlobal; }
5092+
void setTopLevelGlobal(bool b) { Bits.VarDecl.IsTopLevelGlobal = b; }
5093+
50875094
/// Retrieve the custom attributes that attach property wrappers to this
50885095
/// property. The returned list contains all of the attached property wrapper attributes in source order,
50895096
/// which means the outermost wrapper attribute is provided first.

include/swift/AST/DiagnosticsSema.def

+5-7
Original file line numberDiff line numberDiff line change
@@ -1153,14 +1153,12 @@ NOTE(candidate_expected_different_labels,none,
11531153
"incorrect labels for candidate (have: '%0', expected: '%1')",
11541154
(StringRef, StringRef))
11551155

1156+
ERROR(member_shadows_function,none,
1157+
"use of %0 refers to %1 rather than %2 %3",
1158+
(DeclNameRef, DescriptiveDeclKind, DescriptiveDeclKind, DeclName))
11561159
ERROR(member_shadows_global_function,none,
1157-
"use of %0 refers to %1 %2 rather than %3 %4 in %5 %6",
1158-
(DeclNameRef, DescriptiveDeclKind, DeclName, DescriptiveDeclKind,
1159-
DeclName, DescriptiveDeclKind, DeclName))
1160-
ERROR(member_shadows_global_function_near_match,none,
1161-
"use of %0 nearly matches %3 %4 in %5 %6 rather than %1 %2",
1162-
(DeclNameRef, DescriptiveDeclKind, DeclName, DescriptiveDeclKind,
1163-
DeclName, DescriptiveDeclKind, DeclName))
1160+
"use of %0 refers to %1 rather than %2 %3 in module %4",
1161+
(DeclNameRef, DescriptiveDeclKind, DescriptiveDeclKind, DeclName, DeclName))
11641162

11651163
ERROR(instance_member_use_on_type,none,
11661164
"instance member %1 cannot be used on type %0; "

lib/AST/Decl.cpp

+2-5
Original file line numberDiff line numberDiff line change
@@ -5312,6 +5312,7 @@ VarDecl::VarDecl(DeclKind kind, bool isStatic, VarDecl::Introducer introducer,
53125312
Bits.VarDecl.IsLazyStorageProperty = false;
53135313
Bits.VarDecl.HasNonPatternBindingInit = false;
53145314
Bits.VarDecl.IsPropertyWrapperBackingProperty = false;
5315+
Bits.VarDecl.IsTopLevelGlobal = false;
53155316
}
53165317

53175318
Type VarDecl::getType() const {
@@ -5410,11 +5411,7 @@ bool VarDecl::isLazilyInitializedGlobal() const {
54105411

54115412
// Top-level global variables in the main source file and in the REPL are not
54125413
// lazily initialized.
5413-
auto sourceFileContext = dyn_cast<SourceFile>(getDeclContext());
5414-
if (!sourceFileContext)
5415-
return true;
5416-
5417-
return !sourceFileContext->isScriptMode();
5414+
return !isTopLevelGlobal();
54185415
}
54195416

54205417
SourceRange VarDecl::getSourceRange() const {

lib/Parse/ParseDecl.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -5840,6 +5840,7 @@ Parser::parseDeclVar(ParseDeclOptions Flags,
58405840
VD->setStatic(StaticLoc.isValid());
58415841
VD->getAttrs() = Attributes;
58425842
setLocalDiscriminator(VD);
5843+
VD->setTopLevelGlobal(topLevelDecl);
58435844

58445845
// Set original declaration in `@differentiable` attributes.
58455846
setOriginalDeclarationForDifferentiableAttributes(Attributes, VD);

lib/Sema/CSDiag.cpp

-225
Original file line numberDiff line numberDiff line change
@@ -201,10 +201,6 @@ class FailureDiagnosis :public ASTVisitor<FailureDiagnosis, /*exprresult*/bool>{
201201
ContextualTypePurpose CTP,
202202
Type suggestedType = Type());
203203

204-
bool diagnoseImplicitSelfErrors(Expr *fnExpr, Expr *argExpr,
205-
CalleeCandidateInfo &CCI,
206-
ArrayRef<Identifier> argLabels);
207-
208204
private:
209205
/// Validate potential contextual type for type-checking one of the
210206
/// sub-expressions, usually correct/valid types are the ones which
@@ -963,223 +959,6 @@ decomposeArgType(Type argType, ArrayRef<Identifier> argLabels) {
963959
return result;
964960
}
965961

966-
bool FailureDiagnosis::diagnoseImplicitSelfErrors(
967-
Expr *fnExpr, Expr *argExpr, CalleeCandidateInfo &CCI,
968-
ArrayRef<Identifier> argLabels) {
969-
// If candidate list is empty it means that problem is somewhere else,
970-
// since we need to have candidates which might be shadowing other funcs.
971-
if (CCI.empty() || !CCI[0].getDecl())
972-
return false;
973-
974-
auto &ctx = CS.getASTContext();
975-
// Call expression is formed as 'foo.bar' where 'foo' might be an
976-
// implicit "Self" reference, such use wouldn't provide good diagnostics
977-
// for situations where instance members have equal names to functions in
978-
// Swift Standard Library e.g. min/max.
979-
auto UDE = dyn_cast<UnresolvedDotExpr>(fnExpr);
980-
if (!UDE)
981-
return false;
982-
983-
auto baseExpr = dyn_cast<DeclRefExpr>(UDE->getBase());
984-
if (!baseExpr)
985-
return false;
986-
987-
auto baseDecl = baseExpr->getDecl();
988-
if (!baseExpr->isImplicit() || baseDecl->getFullName() != ctx.Id_self)
989-
return false;
990-
991-
// Our base expression is an implicit 'self.' reference e.g.
992-
//
993-
// extension Sequence {
994-
// func test() -> Int {
995-
// return max(1, 2)
996-
// }
997-
// }
998-
//
999-
// In this example the Sequence class already has two methods named 'max'
1000-
// none of which accept two arguments, but there is a function in
1001-
// Swift Standard Library called 'max' which does accept two arguments,
1002-
// so user might have called that by mistake without realizing that
1003-
// compiler would add implicit 'self.' prefix to the call of 'max'.
1004-
auto argType = CS.getType(argExpr);
1005-
// If argument wasn't properly type-checked, let's retry without changing AST.
1006-
if (!argType || argType->hasUnresolvedType() || argType->hasTypeVariable() ||
1007-
argType->hasTypeParameter()) {
1008-
auto *argTuple = dyn_cast<TupleExpr>(argExpr);
1009-
if (!argTuple) {
1010-
// Bail out if we don't have a well-formed argument list.
1011-
return false;
1012-
}
1013-
1014-
// Let's type check individual argument expressions without any
1015-
// contextual information to try to recover an argument type that
1016-
// matches what the user actually wrote instead of what the typechecker
1017-
// expects.
1018-
SmallVector<TupleTypeElt, 4> elts;
1019-
for (unsigned i = 0, e = argTuple->getNumElements(); i < e; ++i) {
1020-
ConcreteDeclRef ref = nullptr;
1021-
auto *el = argTuple->getElement(i);
1022-
auto typeResult =
1023-
TypeChecker::getTypeOfExpressionWithoutApplying(el, CS.DC, ref);
1024-
if (!typeResult)
1025-
return false;
1026-
auto flags = ParameterTypeFlags().withInOut(typeResult->is<InOutType>());
1027-
elts.push_back(TupleTypeElt(typeResult->getInOutObjectType(),
1028-
argTuple->getElementName(i),
1029-
flags));
1030-
}
1031-
1032-
argType = TupleType::get(elts, CS.getASTContext());
1033-
}
1034-
1035-
auto typeKind = argType->getKind();
1036-
if (typeKind != TypeKind::Tuple && typeKind != TypeKind::Paren)
1037-
return false;
1038-
1039-
// If argument type couldn't be properly resolved or has errors,
1040-
// we can't diagnose anything in here, it points to the different problem.
1041-
if (isUnresolvedOrTypeVarType(argType) || argType->hasError())
1042-
return false;
1043-
1044-
auto context = CS.DC;
1045-
using CandidateMap =
1046-
llvm::SmallDenseMap<ValueDecl *, llvm::SmallVector<OverloadChoice, 2>>;
1047-
1048-
auto getBaseKind = [](ValueDecl *base) -> DescriptiveDeclKind {
1049-
DescriptiveDeclKind kind = DescriptiveDeclKind::Module;
1050-
if (!base)
1051-
return kind;
1052-
1053-
auto context = base->getDeclContext();
1054-
do {
1055-
if (isa<ExtensionDecl>(context))
1056-
return DescriptiveDeclKind::Extension;
1057-
1058-
if (auto nominal = dyn_cast<NominalTypeDecl>(context)) {
1059-
kind = nominal->getDescriptiveKind();
1060-
break;
1061-
}
1062-
1063-
context = context->getParent();
1064-
} while (context);
1065-
1066-
return kind;
1067-
};
1068-
1069-
auto diagnoseShadowing = [&](ValueDecl *base,
1070-
ArrayRef<OverloadChoice> candidates) -> bool {
1071-
CalleeCandidateInfo calleeInfo(base ? base->getInterfaceType() : nullptr,
1072-
candidates, CCI.hasTrailingClosure, CS,
1073-
base);
1074-
1075-
calleeInfo.filterListArgs(decomposeArgType(argType, argLabels));
1076-
1077-
auto diagnostic = diag::member_shadows_global_function_near_match;
1078-
switch (calleeInfo.closeness) {
1079-
case CC_Unavailable:
1080-
case CC_Inaccessible:
1081-
case CC_SelfMismatch:
1082-
case CC_ArgumentLabelMismatch:
1083-
case CC_ArgumentCountMismatch:
1084-
case CC_GeneralMismatch:
1085-
return false;
1086-
1087-
case CC_NonLValueInOut:
1088-
case CC_OneArgumentNearMismatch:
1089-
case CC_OneArgumentMismatch:
1090-
case CC_OneGenericArgumentNearMismatch:
1091-
case CC_OneGenericArgumentMismatch:
1092-
case CC_ArgumentNearMismatch:
1093-
case CC_ArgumentMismatch:
1094-
case CC_GenericNonsubstitutableMismatch:
1095-
break; // Near match cases
1096-
1097-
case CC_ExactMatch:
1098-
diagnostic = diag::member_shadows_global_function;
1099-
break;
1100-
}
1101-
1102-
auto choice = calleeInfo.candidates[0].getDecl();
1103-
auto baseKind = getBaseKind(base);
1104-
auto baseName = getBaseName(choice->getDeclContext());
1105-
1106-
auto origCandidate = CCI[0].getDecl();
1107-
ctx.Diags.diagnose(UDE->getLoc(), diagnostic, UDE->getName(),
1108-
origCandidate->getDescriptiveKind(),
1109-
origCandidate->getFullName(),
1110-
choice->getDescriptiveKind(),
1111-
choice->getFullName(), baseKind, baseName);
1112-
1113-
auto topLevelDiag = diag::fix_unqualified_access_top_level;
1114-
if (baseKind == DescriptiveDeclKind::Module)
1115-
topLevelDiag = diag::fix_unqualified_access_top_level_multi;
1116-
1117-
emitFixItForExplicitlyQualifiedReference(ctx.Diags, UDE, topLevelDiag,
1118-
baseName,
1119-
choice->getDescriptiveKind());
1120-
1121-
for (auto &candidate : calleeInfo.candidates) {
1122-
if (auto decl = candidate.getDecl())
1123-
ctx.Diags.diagnose(decl, diag::decl_declared_here, decl->getFullName());
1124-
}
1125-
1126-
return true;
1127-
};
1128-
1129-
// For each of the parent contexts, let's try to find any candidates
1130-
// which have the same name and the same number of arguments as callee.
1131-
while (context->getParent()) {
1132-
auto result =
1133-
TypeChecker::lookupUnqualified(context, UDE->getName(), UDE->getLoc());
1134-
context = context->getParent();
1135-
1136-
if (!result || result.empty())
1137-
continue;
1138-
1139-
CandidateMap candidates;
1140-
for (const auto &candidate : result) {
1141-
auto base = candidate.getBaseDecl();
1142-
auto decl = candidate.getValueDecl();
1143-
if ((base && base->isInvalid()) || decl->isInvalid())
1144-
continue;
1145-
1146-
// If base is present but it doesn't represent a valid nominal,
1147-
// we can't use current candidate as one of the choices.
1148-
if (base && !base->getInterfaceType()->getNominalOrBoundGenericNominal())
1149-
continue;
1150-
1151-
auto context = decl->getDeclContext();
1152-
// We are only interested in static or global functions, because
1153-
// there is no way to call anything else properly.
1154-
if (!decl->isStatic() && !context->isModuleScopeContext())
1155-
continue;
1156-
1157-
OverloadChoice choice(base ? base->getInterfaceType() : nullptr,
1158-
decl, UDE->getFunctionRefKind());
1159-
1160-
if (base) { // Let's group all of the candidates have a common base.
1161-
candidates[base].push_back(choice);
1162-
continue;
1163-
}
1164-
1165-
// If there is no base, it means this is one of the global functions,
1166-
// let's try to diagnose its shadowing inline.
1167-
if (diagnoseShadowing(base, choice))
1168-
return true;
1169-
}
1170-
1171-
if (candidates.empty())
1172-
continue;
1173-
1174-
for (const auto &candidate : candidates) {
1175-
if (diagnoseShadowing(candidate.getFirst(), candidate.getSecond()))
1176-
return true;
1177-
}
1178-
}
1179-
1180-
return false;
1181-
}
1182-
1183962
// Extract expression for failed argument number
1184963
static Expr *getFailedArgumentExpr(CalleeCandidateInfo CCI, Expr *argExpr) {
1185964
if (auto *TE = dyn_cast<TupleExpr>(argExpr))
@@ -1201,10 +980,6 @@ static Expr *getFailedArgumentExpr(CalleeCandidateInfo CCI, Expr *argExpr) {
1201980
bool FailureDiagnosis::diagnoseParameterErrors(CalleeCandidateInfo &CCI,
1202981
Expr *fnExpr, Expr *argExpr,
1203982
ArrayRef<Identifier> argLabels) {
1204-
// Try to diagnose errors related to the use of implicit self reference.
1205-
if (diagnoseImplicitSelfErrors(fnExpr, argExpr, CCI, argLabels))
1206-
return true;
1207-
1208983
// If we have a failure where the candidate set differs on exactly one
1209984
// argument, and where we have a consistent mismatch across the candidate set
1210985
// (often because there is only one candidate in the set), then diagnose this

lib/Sema/CSDiagnostics.cpp

+42
Original file line numberDiff line numberDiff line change
@@ -6137,3 +6137,45 @@ bool UnableToInferProtocolLiteralType::diagnoseAsError() {
61376137

61386138
return true;
61396139
}
6140+
6141+
bool MissingQuialifierInMemberRefFailure::diagnoseAsError() {
6142+
auto selectedOverload = getOverloadChoiceIfAvailable(getLocator());
6143+
if (!selectedOverload)
6144+
return false;
6145+
6146+
auto *UDE = cast<UnresolvedDotExpr>(getRawAnchor());
6147+
6148+
auto baseType = getType(UDE->getBase());
6149+
6150+
auto methodKind = baseType->isAnyExistentialType()
6151+
? DescriptiveDeclKind::StaticMethod
6152+
: DescriptiveDeclKind::Method;
6153+
6154+
auto choice = selectedOverload->choice.getDeclOrNull();
6155+
if (!choice)
6156+
return false;
6157+
6158+
auto *DC = choice->getDeclContext();
6159+
if (!(DC->isModuleContext() || DC->isModuleScopeContext())) {
6160+
emitDiagnostic(UDE->getLoc(), diag::member_shadows_function, UDE->getName(),
6161+
methodKind, choice->getDescriptiveKind(),
6162+
choice->getFullName());
6163+
return true;
6164+
}
6165+
6166+
auto qualifier = DC->getParentModule()->getName();
6167+
6168+
emitDiagnostic(UDE->getLoc(), diag::member_shadows_global_function,
6169+
UDE->getName(), methodKind, choice->getDescriptiveKind(),
6170+
choice->getFullName(), qualifier);
6171+
6172+
SmallString<32> namePlusDot = qualifier.str();
6173+
namePlusDot.push_back('.');
6174+
6175+
emitDiagnostic(UDE->getLoc(), diag::fix_unqualified_access_top_level_multi,
6176+
namePlusDot, choice->getDescriptiveKind(), qualifier)
6177+
.fixItInsert(UDE->getStartLoc(), namePlusDot);
6178+
6179+
emitDiagnostic(choice, diag::decl_declared_here, choice->getFullName());
6180+
return true;
6181+
}

0 commit comments

Comments
 (0)