Skip to content

Commit c73b144

Browse files
committed
Perform the unintended generic detection in simplifyMemberConstraint and define a ConstraintFix to produce the new note.
1 parent be4e23f commit c73b144

File tree

5 files changed

+135
-55
lines changed

5 files changed

+135
-55
lines changed

lib/Sema/CSDiagnostics.cpp

Lines changed: 24 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,6 @@
3131
#include "swift/AST/SourceFile.h"
3232
#include "swift/AST/Stmt.h"
3333
#include "swift/AST/Types.h"
34-
#include "swift/AST/GenericEnvironment.h"
35-
#include "swift/AST/NameLookupRequests.h"
3634
#include "swift/Basic/SourceLoc.h"
3735
#include "swift/Parse/Lexer.h"
3836
#include "llvm/ADT/ArrayRef.h"
@@ -3111,53 +3109,6 @@ DeclName MissingMemberFailure::findCorrectEnumCaseName(
31113109
return (candidate ? candidate->getName() : DeclName());
31123110
}
31133111

3114-
bool MissingMemberFailure::findUnintendedExtraGenericParam(Type instanceTy, FunctionRefKind functionKind) {
3115-
auto archetype = instanceTy->getAs<ArchetypeType>();
3116-
if (!archetype)
3117-
return false;
3118-
auto genericTy = archetype->mapTypeOutOfContext()->getAs<GenericTypeParamType>();
3119-
if (!genericTy)
3120-
return false;
3121-
3122-
for (auto param : archetype->getGenericEnvironment()->getGenericParams()) {
3123-
// Find a param at the same depth and one index past the type we're dealing with
3124-
if (param->getDepth() != genericTy->getDepth() || param->getIndex() != genericTy->getIndex() + 1)
3125-
continue;
3126-
3127-
auto &cs = getConstraintSystem();
3128-
auto paramDecl = param->getDecl();
3129-
auto descriptor = UnqualifiedLookupDescriptor(
3130-
DeclNameRef(param->getName()), paramDecl->getDeclContext()->getParentForLookup(), paramDecl->getStartLoc(),
3131-
UnqualifiedLookupFlags::KnownPrivate | UnqualifiedLookupFlags::TypeLookup);
3132-
auto lookup = evaluateOrDefault(cs.getASTContext().evaluator, UnqualifiedLookupRequest{descriptor}, {});
3133-
for (auto &result : lookup) {
3134-
if (auto proto = dyn_cast_or_null<ProtocolDecl>(result.getValueDecl())) {
3135-
auto memberLookup = cs.performMemberLookup(
3136-
ConstraintKind::ValueMember, getName().withoutArgumentLabels(),
3137-
proto->getDeclaredType(), functionKind, getLocator(),
3138-
/*includeInaccessibleMembers=*/true);
3139-
if (memberLookup.ViableCandidates.size() || memberLookup.UnviableCandidates.size()) {
3140-
SourceLoc loc = genericTy->getDecl()->getSourceRange().End;
3141-
StringRef replacement;
3142-
3143-
if (archetype->getConformsTo().size()) {
3144-
loc = loc.getAdvancedLoc(archetype->getConformsTo().back()->getName().getLength());
3145-
replacement = " &";
3146-
} else {
3147-
loc = loc.getAdvancedLoc(archetype->getName().getLength());
3148-
replacement = ":";
3149-
}
3150-
emitDiagnosticAt(loc, diag::did_you_mean_generic_param_as_conformance, paramDecl->getName(), archetype)
3151-
.fixItReplaceChars(loc, loc.getAdvancedLoc(1), replacement);
3152-
return true;
3153-
}
3154-
}
3155-
}
3156-
break;
3157-
}
3158-
return false;
3159-
}
3160-
31613112
bool MissingMemberFailure::diagnoseAsError() {
31623113
auto anchor = getRawAnchor();
31633114
auto memberBase = getAnchor();
@@ -3266,7 +3217,6 @@ bool MissingMemberFailure::diagnoseAsError() {
32663217
}
32673218
} else {
32683219
emitBasicError(baseType);
3269-
findUnintendedExtraGenericParam(instanceTy, FunctionRefKind::DoubleApply);
32703220
}
32713221
} else if (auto moduleTy = baseType->getAs<ModuleType>()) {
32723222
emitDiagnosticAt(::getLoc(memberBase), diag::no_member_of_module,
@@ -3328,7 +3278,6 @@ bool MissingMemberFailure::diagnoseAsError() {
33283278
correction->addFixits(diagnostic);
33293279
} else {
33303280
emitBasicError(baseType);
3331-
findUnintendedExtraGenericParam(baseType, FunctionRefKind::SingleApply);
33323281
}
33333282
}
33343283
}
@@ -3386,6 +3335,30 @@ bool MissingMemberFailure::diagnoseInLiteralCollectionContext() const {
33863335
return false;
33873336
}
33883337

3338+
bool UnintendedExtraGenericParamMemberFailure::diagnoseAsError() {
3339+
MissingMemberFailure::diagnoseAsError();
3340+
3341+
auto baseType = resolveType(getBaseType())->getWithoutSpecifierType();
3342+
auto archetype = baseType->getMetatypeInstanceType()->castTo<ArchetypeType>();
3343+
auto genericTy =
3344+
archetype->mapTypeOutOfContext()->castTo<GenericTypeParamType>();
3345+
SourceLoc loc = genericTy->getDecl()->getSourceRange().End;
3346+
StringRef replacement;
3347+
3348+
if (archetype->getConformsTo().size()) {
3349+
loc = loc.getAdvancedLoc(
3350+
archetype->getConformsTo().back()->getName().getLength());
3351+
replacement = " &";
3352+
} else {
3353+
loc = loc.getAdvancedLoc(archetype->getName().getLength());
3354+
replacement = ":";
3355+
}
3356+
emitDiagnosticAt(loc, diag::did_you_mean_generic_param_as_conformance,
3357+
ParamName, archetype)
3358+
.fixItReplaceChars(loc, loc.getAdvancedLoc(1), replacement);
3359+
return true;
3360+
}
3361+
33893362
bool InvalidMemberRefOnExistential::diagnoseAsError() {
33903363
auto anchor = getRawAnchor();
33913364

lib/Sema/CSDiagnostics.h

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1039,7 +1039,7 @@ class InvalidMemberRefFailure : public FailureDiagnostic {
10391039
/// let _: Int = s.foo(1, 2) // expected type is `(Int, Int) -> Int`
10401040
/// }
10411041
/// ```
1042-
class MissingMemberFailure final : public InvalidMemberRefFailure {
1042+
class MissingMemberFailure : public InvalidMemberRefFailure {
10431043
public:
10441044
MissingMemberFailure(const Solution &solution, Type baseType,
10451045
DeclNameRef memberName, ConstraintLocator *locator)
@@ -1066,8 +1066,22 @@ class MissingMemberFailure final : public InvalidMemberRefFailure {
10661066
static DeclName findCorrectEnumCaseName(Type Ty,
10671067
TypoCorrectionResults &corrections,
10681068
DeclNameRef memberName);
1069-
1070-
bool findUnintendedExtraGenericParam(Type instanceTy, FunctionRefKind functionKind);
1069+
};
1070+
1071+
class UnintendedExtraGenericParamMemberFailure final
1072+
: public MissingMemberFailure {
1073+
Identifier ParamName;
1074+
1075+
public:
1076+
UnintendedExtraGenericParamMemberFailure(const Solution &solution,
1077+
Type baseType,
1078+
DeclNameRef memberName,
1079+
Identifier paramName,
1080+
ConstraintLocator *locator)
1081+
: MissingMemberFailure(solution, baseType, memberName, locator),
1082+
ParamName(paramName) {}
1083+
1084+
bool diagnoseAsError() override;
10711085
};
10721086

10731087
/// Diagnose cases where a member only accessible on generic constraints

lib/Sema/CSFix.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -531,6 +531,23 @@ DefineMemberBasedOnUse::create(ConstraintSystem &cs, Type baseType,
531531
DefineMemberBasedOnUse(cs, baseType, member, alreadyDiagnosed, locator);
532532
}
533533

534+
bool DefineMemberBasedOnUnintendedGenericParam::diagnose(
535+
const Solution &solution, bool asNote) const {
536+
UnintendedExtraGenericParamMemberFailure failure(solution, BaseType, Name,
537+
ParamName, getLocator());
538+
return failure.diagnose(asNote);
539+
}
540+
541+
DefineMemberBasedOnUnintendedGenericParam *
542+
DefineMemberBasedOnUnintendedGenericParam::create(ConstraintSystem &cs,
543+
Type baseType,
544+
DeclNameRef member,
545+
Identifier paramName,
546+
ConstraintLocator *locator) {
547+
return new (cs.getAllocator()) DefineMemberBasedOnUnintendedGenericParam(
548+
cs, baseType, member, paramName, locator);
549+
}
550+
534551
AllowMemberRefOnExistential *
535552
AllowMemberRefOnExistential::create(ConstraintSystem &cs, Type baseType,
536553
ValueDecl *member, DeclNameRef memberName,

lib/Sema/CSFix.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -884,6 +884,33 @@ class DefineMemberBasedOnUse final : public ConstraintFix {
884884
}
885885
};
886886

887+
class DefineMemberBasedOnUnintendedGenericParam final : public ConstraintFix {
888+
Type BaseType;
889+
DeclNameRef Name;
890+
Identifier ParamName;
891+
892+
DefineMemberBasedOnUnintendedGenericParam(ConstraintSystem &cs, Type baseType,
893+
DeclNameRef member,
894+
Identifier paramName,
895+
ConstraintLocator *locator)
896+
: ConstraintFix(cs, FixKind::DefineMemberBasedOnUse, locator),
897+
BaseType(baseType), Name(member), ParamName(paramName) {}
898+
899+
public:
900+
std::string getName() const override {
901+
llvm::SmallVector<char, 16> scratch;
902+
auto memberName = Name.getString(scratch);
903+
return "allow access to invalid member '" + memberName.str() +
904+
"' on archetype presumed intended to conform to protocol";
905+
}
906+
907+
bool diagnose(const Solution &solution, bool asNote = false) const override;
908+
909+
static DefineMemberBasedOnUnintendedGenericParam *
910+
create(ConstraintSystem &cs, Type baseType, DeclNameRef member,
911+
Identifier paramName, ConstraintLocator *locator);
912+
};
913+
887914
class AllowInvalidMemberRef : public ConstraintFix {
888915
Type BaseType;
889916
ValueDecl *Member;

lib/Sema/CSSimplify.cpp

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,14 @@
1515
//
1616
//===----------------------------------------------------------------------===//
1717

18-
#include "CSFix.h"
1918
#include "CSDiagnostics.h"
19+
#include "CSFix.h"
2020
#include "ConstraintSystem.h"
2121
#include "swift/AST/ExistentialLayout.h"
2222
#include "swift/AST/GenericEnvironment.h"
2323
#include "swift/AST/GenericSignature.h"
2424
#include "swift/AST/Initializer.h"
25+
#include "swift/AST/NameLookupRequests.h"
2526
#include "swift/AST/ParameterList.h"
2627
#include "swift/AST/PropertyWrappers.h"
2728
#include "swift/AST/ProtocolConformance.h"
@@ -6928,6 +6929,54 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyMemberConstraint(
69286929
return recordFix(fix) ? SolutionKind::Error : SolutionKind::Solved;
69296930
}
69306931

6932+
// If base is an archetype or metatype of archetype, check for an unintended
6933+
// extra generic parameter.
6934+
if (auto archetype =
6935+
baseTy->getMetatypeInstanceType()->getAs<ArchetypeType>()) {
6936+
if (auto genericTy =
6937+
archetype->mapTypeOutOfContext()->getAs<GenericTypeParamType>()) {
6938+
for (auto param :
6939+
archetype->getGenericEnvironment()->getGenericParams()) {
6940+
// Find a param at the same depth and one index past the type we're
6941+
// dealing with
6942+
if (param->getDepth() != genericTy->getDepth() ||
6943+
param->getIndex() != genericTy->getIndex() + 1)
6944+
continue;
6945+
auto paramDecl = param->getDecl();
6946+
if (!paramDecl)
6947+
continue;
6948+
6949+
auto descriptor = UnqualifiedLookupDescriptor(
6950+
DeclNameRef(param->getName()),
6951+
paramDecl->getDeclContext()->getParentForLookup(),
6952+
paramDecl->getStartLoc(),
6953+
UnqualifiedLookupFlags::KnownPrivate |
6954+
UnqualifiedLookupFlags::TypeLookup);
6955+
auto lookup = evaluateOrDefault(
6956+
Context.evaluator, UnqualifiedLookupRequest{descriptor}, {});
6957+
for (auto &result : lookup) {
6958+
if (auto proto =
6959+
dyn_cast_or_null<ProtocolDecl>(result.getValueDecl())) {
6960+
auto result =
6961+
baseTy->is<MetatypeType>()
6962+
? solveWithNewBaseOrName(ExistentialMetatypeType::get(
6963+
proto->getDeclaredType()),
6964+
member)
6965+
: solveWithNewBaseOrName(proto->getDeclaredType(),
6966+
member);
6967+
if (result == SolutionKind::Solved)
6968+
return recordFix(
6969+
DefineMemberBasedOnUnintendedGenericParam::create(
6970+
*this, baseTy, member, param->getName(),
6971+
locator))
6972+
? SolutionKind::Error
6973+
: SolutionKind::Solved;
6974+
}
6975+
}
6976+
}
6977+
}
6978+
}
6979+
69316980
if (auto *funcType = baseTy->getAs<FunctionType>()) {
69326981
// We can't really suggest anything useful unless
69336982
// function takes no arguments, otherwise it

0 commit comments

Comments
 (0)