Skip to content

Commit d0a9560

Browse files
committed
[Diagnostics] Move findArgumentLocations logic from fix to diagnostic
1 parent c30845f commit d0a9560

File tree

4 files changed

+153
-152
lines changed

4 files changed

+153
-152
lines changed

lib/Sema/CSDiagnostics.cpp

Lines changed: 114 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2886,18 +2886,33 @@ MissingContextualConformanceFailure::getDiagnosticFor(
28862886
return None;
28872887
}
28882888

2889-
SourceLoc MissingGenericArgumentsFailure::getLoc() const {
2890-
return BaseType ? BaseType->getLoc() : getAnchor()->getLoc();
2891-
}
2892-
28932889
bool MissingGenericArgumentsFailure::hasLoc(GenericTypeParamType *GP) const {
28942890
return GP->getDecl()->getStartLoc().isValid();
28952891
}
28962892

28972893
bool MissingGenericArgumentsFailure::diagnoseAsError() {
2894+
llvm::SmallDenseMap<TypeRepr *, SmallVector<GenericTypeParamType *, 4>>
2895+
scopedParameters;
2896+
2897+
auto isScoped =
2898+
findArgumentLocations([&](TypeRepr *base, GenericTypeParamType *GP) {
2899+
scopedParameters[base].push_back(GP);
2900+
});
2901+
2902+
if (!isScoped)
2903+
return diagnoseForAnchor(getAnchor(), Parameters);
2904+
28982905
bool diagnosed = false;
2899-
for (auto *GP : Parameters)
2900-
diagnosed |= diagnoseParameter(GP);
2906+
for (const auto &scope : scopedParameters)
2907+
diagnosed |= diagnoseForAnchor(scope.first, scope.second);
2908+
return diagnosed;
2909+
}
2910+
2911+
bool MissingGenericArgumentsFailure::diagnoseForAnchor(
2912+
Anchor anchor, ArrayRef<GenericTypeParamType *> params) const {
2913+
bool diagnosed = false;
2914+
for (auto *GP : params)
2915+
diagnosed |= diagnoseParameter(anchor, GP);
29012916

29022917
if (!diagnosed)
29032918
return false;
@@ -2915,14 +2930,17 @@ bool MissingGenericArgumentsFailure::diagnoseAsError() {
29152930
return true;
29162931
}
29172932

2918-
emitGenericSignatureNote();
2933+
emitGenericSignatureNote(anchor);
29192934
return true;
29202935
}
29212936

29222937
bool MissingGenericArgumentsFailure::diagnoseParameter(
2923-
GenericTypeParamType *GP) const {
2938+
Anchor anchor, GenericTypeParamType *GP) const {
29242939
auto &cs = getConstraintSystem();
29252940

2941+
auto loc = anchor.is<Expr *>() ? anchor.get<Expr *>()->getLoc()
2942+
: anchor.get<TypeRepr *>()->getLoc();
2943+
29262944
auto *locator = getLocator();
29272945
// Type variables associated with missing generic parameters are
29282946
// going to be completely cut off from the rest of constraint system,
@@ -2938,41 +2956,43 @@ bool MissingGenericArgumentsFailure::diagnoseParameter(
29382956
if (auto *CE = dyn_cast<ExplicitCastExpr>(getRawAnchor())) {
29392957
auto castTo = getType(CE->getCastTypeLoc());
29402958
auto *NTD = castTo->getAnyNominal();
2941-
emitDiagnostic(getLoc(), diag::unbound_generic_parameter_cast, GP,
2959+
emitDiagnostic(loc, diag::unbound_generic_parameter_cast, GP,
29422960
NTD ? NTD->getDeclaredType() : castTo);
29432961
} else {
2944-
emitDiagnostic(getLoc(), diag::unbound_generic_parameter, GP);
2962+
emitDiagnostic(loc, diag::unbound_generic_parameter, GP);
29452963
}
29462964

29472965
if (!hasLoc(GP))
29482966
return true;
29492967

2950-
Type baseType;
2968+
Type baseTyForNote;
29512969
auto *DC = getDeclContext();
29522970

29532971
if (auto *NTD =
29542972
dyn_cast_or_null<NominalTypeDecl>(DC->getSelfNominalTypeDecl())) {
2955-
baseType = NTD->getDeclaredType();
2973+
baseTyForNote = NTD->getDeclaredType();
29562974
} else if (auto *TAD = dyn_cast<TypeAliasDecl>(DC)) {
2957-
baseType = TAD->getUnboundGenericType();
2975+
baseTyForNote = TAD->getUnboundGenericType();
29582976
} else {
2959-
baseType = DC->getDeclaredInterfaceType();
2977+
baseTyForNote = DC->getDeclaredInterfaceType();
29602978
}
29612979

2962-
if (!baseType)
2980+
if (!baseTyForNote)
29632981
return true;
29642982

2965-
emitDiagnostic(GP->getDecl(), diag::archetype_declared_in_type, GP, baseType);
2983+
emitDiagnostic(GP->getDecl(), diag::archetype_declared_in_type, GP,
2984+
baseTyForNote);
29662985
return true;
29672986
}
29682987

2969-
void MissingGenericArgumentsFailure::emitGenericSignatureNote() const {
2988+
void MissingGenericArgumentsFailure::emitGenericSignatureNote(
2989+
Anchor anchor) const {
29702990
auto &cs = getConstraintSystem();
29712991
auto &TC = getTypeChecker();
29722992
auto *paramDC = getDeclContext();
29732993

29742994
auto *GTD = dyn_cast<GenericTypeDecl>(paramDC);
2975-
if (!GTD || !BaseType)
2995+
if (!GTD || anchor.is<Expr *>())
29762996
return;
29772997

29782998
auto getParamDecl =
@@ -3006,18 +3026,90 @@ void MissingGenericArgumentsFailure::emitGenericSignatureNote() const {
30063026
};
30073027

30083028
SmallString<64> paramsAsString;
3029+
auto baseType = anchor.get<TypeRepr *>();
30093030
if (TC.getDefaultGenericArgumentsString(paramsAsString, GTD,
30103031
getPreferredType)) {
3011-
auto diagnostic =
3012-
emitDiagnostic(getLoc(), diag::unbound_generic_parameter_explicit_fix);
3032+
auto diagnostic = emitDiagnostic(
3033+
baseType->getLoc(), diag::unbound_generic_parameter_explicit_fix);
30133034

3014-
if (auto *genericTy = dyn_cast<GenericIdentTypeRepr>(BaseType)) {
3035+
if (auto *genericTy = dyn_cast<GenericIdentTypeRepr>(baseType)) {
30153036
// If some of the eneric arguments have been specified, we need to
30163037
// replace existing signature with a new one.
30173038
diagnostic.fixItReplace(genericTy->getAngleBrackets(), paramsAsString);
30183039
} else {
30193040
// Otherwise we can simply insert new generic signature.
3020-
diagnostic.fixItInsertAfter(BaseType->getEndLoc(), paramsAsString);
3041+
diagnostic.fixItInsertAfter(baseType->getEndLoc(), paramsAsString);
30213042
}
30223043
}
30233044
}
3045+
3046+
bool MissingGenericArgumentsFailure::findArgumentLocations(
3047+
llvm::function_ref<void(TypeRepr *, GenericTypeParamType *)> callback) {
3048+
using Callback = llvm::function_ref<void(TypeRepr *, GenericTypeParamType *)>;
3049+
3050+
auto *anchor = getRawAnchor();
3051+
3052+
TypeLoc typeLoc;
3053+
if (auto *TE = dyn_cast<TypeExpr>(anchor))
3054+
typeLoc = TE->getTypeLoc();
3055+
else if (auto *ECE = dyn_cast<ExplicitCastExpr>(anchor))
3056+
typeLoc = ECE->getCastTypeLoc();
3057+
3058+
if (!typeLoc.hasLocation())
3059+
return false;
3060+
3061+
struct AssociateMissingParams : public ASTWalker {
3062+
llvm::SmallVector<GenericTypeParamType *, 4> Params;
3063+
Callback Fn;
3064+
3065+
AssociateMissingParams(ArrayRef<GenericTypeParamType *> params,
3066+
Callback callback)
3067+
: Params(params.begin(), params.end()), Fn(callback) {}
3068+
3069+
bool walkToTypeReprPre(TypeRepr *T) override {
3070+
if (Params.empty())
3071+
return false;
3072+
3073+
auto *ident = dyn_cast<ComponentIdentTypeRepr>(T);
3074+
if (!ident)
3075+
return true;
3076+
3077+
auto *decl = dyn_cast_or_null<GenericTypeDecl>(ident->getBoundDecl());
3078+
if (!decl)
3079+
return true;
3080+
3081+
auto *paramList = decl->getGenericParams();
3082+
if (!paramList)
3083+
return true;
3084+
3085+
// There could a situation like `S<S>()`, so we need to be
3086+
// careful not to point at first `S` because it has all of
3087+
// its generic parameters specified.
3088+
if (auto *generic = dyn_cast<GenericIdentTypeRepr>(ident)) {
3089+
if (paramList->size() == generic->getNumGenericArgs())
3090+
return true;
3091+
}
3092+
3093+
for (auto *candidate : paramList->getParams()) {
3094+
auto result =
3095+
llvm::find_if(Params, [&](const GenericTypeParamType *param) {
3096+
return candidate == param->getDecl();
3097+
});
3098+
3099+
if (result != Params.end()) {
3100+
Fn(ident, *result);
3101+
Params.erase(result);
3102+
}
3103+
}
3104+
3105+
// Keep walking.
3106+
return true;
3107+
}
3108+
3109+
bool allParamsAssigned() const { return Params.empty(); }
3110+
3111+
} associator(Parameters, callback);
3112+
3113+
typeLoc.getTypeRepr()->walk(associator);
3114+
return associator.allParamsAssigned();
3115+
}

lib/Sema/CSDiagnostics.h

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1238,21 +1238,19 @@ class MissingContextualConformanceFailure final : public ContextualFailure {
12381238
/// _ = S()
12391239
/// ```
12401240
class MissingGenericArgumentsFailure final : public FailureDiagnostic {
1241-
TypeRepr *BaseType;
1241+
using Anchor = llvm::PointerUnion<TypeRepr *, Expr *>;
1242+
12421243
SmallVector<GenericTypeParamType *, 4> Parameters;
12431244

12441245
public:
12451246
MissingGenericArgumentsFailure(Expr *root, ConstraintSystem &cs,
1246-
TypeRepr *baseType,
12471247
ArrayRef<GenericTypeParamType *> missingParams,
12481248
ConstraintLocator *locator)
1249-
: FailureDiagnostic(root, cs, locator), BaseType(baseType) {
1249+
: FailureDiagnostic(root, cs, locator) {
12501250
assert(!missingParams.empty());
12511251
Parameters.append(missingParams.begin(), missingParams.end());
12521252
}
12531253

1254-
SourceLoc getLoc() const;
1255-
12561254
bool hasLoc(GenericTypeParamType *GP) const;
12571255

12581256
DeclContext *getDeclContext() const {
@@ -1262,10 +1260,19 @@ class MissingGenericArgumentsFailure final : public FailureDiagnostic {
12621260

12631261
bool diagnoseAsError() override;
12641262

1265-
bool diagnoseParameter(GenericTypeParamType *GP) const;
1263+
bool diagnoseForAnchor(Anchor anchor,
1264+
ArrayRef<GenericTypeParamType *> params) const;
1265+
1266+
bool diagnoseParameter(Anchor anchor, GenericTypeParamType *GP) const;
12661267

12671268
private:
1268-
void emitGenericSignatureNote() const;
1269+
void emitGenericSignatureNote(Anchor anchor) const;
1270+
1271+
/// Retrieve representative locations for associated generic prameters.
1272+
///
1273+
/// \returns true if all of the parameters have been covered.
1274+
bool findArgumentLocations(
1275+
llvm::function_ref<void(TypeRepr *, GenericTypeParamType *)> callback);
12691276
};
12701277

12711278
} // end namespace constraints

lib/Sema/CSFix.cpp

Lines changed: 7 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -544,106 +544,16 @@ CollectionElementContextualMismatch::create(ConstraintSystem &cs, Type srcType,
544544
bool ExplicitlySpecifyGenericArguments::diagnose(Expr *root,
545545
bool asNote) const {
546546
auto &cs = getConstraintSystem();
547-
548-
bool diagnosed = false;
549-
for (const auto &paramsPerAnchor : Parameters) {
550-
auto anchor = paramsPerAnchor.first;
551-
ArrayRef<GenericTypeParamType *> missingParameters = paramsPerAnchor.second;
552-
MissingGenericArgumentsFailure failure(root, cs,
553-
anchor.dyn_cast<TypeRepr *>(),
554-
missingParameters, getLocator());
555-
diagnosed |= failure.diagnose(asNote);
556-
}
557-
558-
return diagnosed;
547+
MissingGenericArgumentsFailure failure(root, cs, getParameters(),
548+
getLocator());
549+
return failure.diagnose(asNote);
559550
}
560551

561552
ExplicitlySpecifyGenericArguments *ExplicitlySpecifyGenericArguments::create(
562553
ConstraintSystem &cs, ArrayRef<GenericTypeParamType *> params,
563554
ConstraintLocator *locator) {
564-
llvm::SmallDenseMap<TypeRepr *, llvm::SmallVector<GenericTypeParamType *, 4>>
565-
typeBasedParams;
566-
567-
if (findArgumentLocations(locator->getAnchor(), params,
568-
[&](TypeRepr *base, GenericTypeParamType *GP) {
569-
typeBasedParams[base].push_back(GP);
570-
}))
571-
return new (cs.getAllocator())
572-
ExplicitlySpecifyGenericArguments(cs, typeBasedParams, locator);
573-
574-
return new (cs.getAllocator())
575-
ExplicitlySpecifyGenericArguments(cs, params, locator);
576-
}
577-
578-
bool ExplicitlySpecifyGenericArguments::findArgumentLocations(
579-
Expr *anchor, ArrayRef<GenericTypeParamType *> genericParams,
580-
llvm::function_ref<void(TypeRepr *, GenericTypeParamType *)> callback) {
581-
using Callback = llvm::function_ref<void(TypeRepr *, GenericTypeParamType *)>;
582-
583-
if (!anchor)
584-
return false;
585-
586-
TypeLoc typeLoc;
587-
if (auto *TE = dyn_cast<TypeExpr>(anchor))
588-
typeLoc = TE->getTypeLoc();
589-
else if (auto *ECE = dyn_cast<ExplicitCastExpr>(anchor))
590-
typeLoc = ECE->getCastTypeLoc();
591-
592-
if (!typeLoc.hasLocation())
593-
return false;
594-
595-
llvm::SmallVector<GenericTypeParamType *, 4> params(genericParams.begin(),
596-
genericParams.end());
597-
598-
struct AssociateMissingParams : public ASTWalker {
599-
llvm::SmallVectorImpl<GenericTypeParamType *> &Params;
600-
Callback Fn;
601-
602-
AssociateMissingParams(SmallVectorImpl<GenericTypeParamType *> &params,
603-
Callback callback)
604-
: Params(params), Fn(callback) {}
605-
606-
bool walkToTypeReprPre(TypeRepr *T) override {
607-
if (Params.empty())
608-
return false;
609-
610-
auto *ident = dyn_cast<ComponentIdentTypeRepr>(T);
611-
if (!ident)
612-
return true;
613-
614-
auto *decl = dyn_cast_or_null<GenericTypeDecl>(ident->getBoundDecl());
615-
if (!decl)
616-
return true;
617-
618-
auto *paramList = decl->getGenericParams();
619-
if (!paramList)
620-
return true;
621-
622-
// There could a situation like `S<S>()`, so we need to be
623-
// careful not to point at first `S` because it has all of
624-
// its generic parameters specified.
625-
if (auto *generic = dyn_cast<GenericIdentTypeRepr>(ident)) {
626-
if (paramList->size() == generic->getNumGenericArgs())
627-
return true;
628-
}
629-
630-
for (auto *candidate : paramList->getParams()) {
631-
auto result =
632-
llvm::find_if(Params, [&](const GenericTypeParamType *param) {
633-
return candidate == param->getDecl();
634-
});
635-
636-
if (result != Params.end()) {
637-
Fn(ident, *result);
638-
Params.erase(result);
639-
}
640-
}
641-
642-
// Keep walking.
643-
return true;
644-
}
645-
} paramAssociator(params, callback);
646-
647-
typeLoc.getTypeRepr()->walk(paramAssociator);
648-
return params.empty();
555+
unsigned size = totalSizeToAlloc<GenericTypeParamType *>(params.size());
556+
void *mem = cs.getAllocator().Allocate(
557+
size, alignof(ExplicitlySpecifyGenericArguments));
558+
return new (mem) ExplicitlySpecifyGenericArguments(cs, params, locator);
649559
}

0 commit comments

Comments
 (0)