Skip to content

Commit 5e35c3e

Browse files
committed
[Diagnostics] Replace CSDiag logic for diagnosing missing generic arguments with new diagnostic
1 parent d0a9560 commit 5e35c3e

File tree

4 files changed

+27
-198
lines changed

4 files changed

+27
-198
lines changed

lib/Sema/CSDiag.cpp

Lines changed: 6 additions & 181 deletions
Original file line numberDiff line numberDiff line change
@@ -7034,125 +7034,6 @@ void ConstraintSystem::diagnoseFailureForExpr(Expr *expr) {
70347034
diagnosis.diagnoseAmbiguity(expr);
70357035
}
70367036

7037-
static bool hasGenericParameter(const GenericTypeDecl *generic,
7038-
GenericTypeParamType *paramTy) {
7039-
auto *decl = paramTy->getDecl();
7040-
if (!decl)
7041-
return false;
7042-
7043-
return decl->getDeclContext() == generic;
7044-
}
7045-
7046-
static void noteGenericParameterSource(const TypeLoc &loc,
7047-
GenericTypeParamType *paramTy,
7048-
ConstraintSystem &cs) {
7049-
const GenericTypeDecl *FoundDecl = nullptr;
7050-
const ComponentIdentTypeRepr *FoundGenericTypeBase = nullptr;
7051-
7052-
// Walk the TypeRepr to find the type in question.
7053-
if (auto typerepr = loc.getTypeRepr()) {
7054-
struct FindGenericTypeDecl : public ASTWalker {
7055-
const GenericTypeDecl *FoundDecl = nullptr;
7056-
const ComponentIdentTypeRepr *FoundGenericTypeBase = nullptr;
7057-
GenericTypeParamType *ParamTy;
7058-
7059-
FindGenericTypeDecl(GenericTypeParamType *ParamTy)
7060-
: ParamTy(ParamTy) {}
7061-
7062-
bool walkToTypeReprPre(TypeRepr *T) override {
7063-
// If we already emitted the note, we're done.
7064-
if (FoundDecl) return false;
7065-
7066-
if (auto ident = dyn_cast<ComponentIdentTypeRepr>(T)) {
7067-
auto *generic =
7068-
dyn_cast_or_null<GenericTypeDecl>(ident->getBoundDecl());
7069-
if (generic && hasGenericParameter(generic, ParamTy)) {
7070-
FoundDecl = generic;
7071-
FoundGenericTypeBase = ident;
7072-
return false;
7073-
}
7074-
}
7075-
// Keep walking.
7076-
return true;
7077-
}
7078-
} findGenericTypeDecl(paramTy);
7079-
7080-
typerepr->walk(findGenericTypeDecl);
7081-
FoundDecl = findGenericTypeDecl.FoundDecl;
7082-
FoundGenericTypeBase = findGenericTypeDecl.FoundGenericTypeBase;
7083-
}
7084-
7085-
// If we didn't find the type in the TypeRepr, fall back to the type in the
7086-
// type checked expression.
7087-
if (!FoundDecl) {
7088-
if (const GenericTypeDecl *generic = loc.getType()->getAnyGeneric())
7089-
if (hasGenericParameter(generic, paramTy))
7090-
FoundDecl = generic;
7091-
}
7092-
7093-
auto &tc = cs.getTypeChecker();
7094-
if (FoundDecl) {
7095-
Type type;
7096-
if (auto *nominal = dyn_cast<NominalTypeDecl>(FoundDecl))
7097-
type = nominal->getDeclaredType();
7098-
else if (auto *typeAlias = dyn_cast<TypeAliasDecl>(FoundDecl))
7099-
type = typeAlias->getUnboundGenericType();
7100-
else
7101-
type = FoundDecl->getDeclaredInterfaceType();
7102-
tc.diagnose(FoundDecl, diag::archetype_declared_in_type, paramTy, type);
7103-
}
7104-
7105-
if (FoundGenericTypeBase && !isa<GenericIdentTypeRepr>(FoundGenericTypeBase)){
7106-
assert(FoundDecl);
7107-
7108-
// If we can, prefer using any types already fixed by the constraint system.
7109-
// This lets us produce fixes like `Pair<Int, Any>` instead of defaulting to
7110-
// `Pair<Any, Any>`.
7111-
// Right now we only handle this when the type that's at fault is the
7112-
// top-level type passed to this function.
7113-
auto type = loc.getType();
7114-
if (!type)
7115-
type = cs.getType(loc);
7116-
7117-
ArrayRef<Type> genericArgs;
7118-
7119-
if (auto *boundGenericTy = type->getAs<BoundGenericType>()) {
7120-
if (boundGenericTy->getDecl() == FoundDecl)
7121-
genericArgs = boundGenericTy->getGenericArgs();
7122-
}
7123-
7124-
auto getPreferredType =
7125-
[&](const GenericTypeParamDecl *genericParam) -> Type {
7126-
// If we were able to get the generic arguments (i.e. the types used at
7127-
// FoundDecl's use site), we can prefer those...
7128-
if (genericArgs.empty())
7129-
return Type();
7130-
7131-
Type preferred = genericArgs[genericParam->getIndex()];
7132-
if (!preferred || preferred->hasError())
7133-
return Type();
7134-
7135-
// ...but only if they were actually resolved by the constraint system
7136-
// despite the failure.
7137-
Type maybeFixedType = cs.getFixedTypeRecursive(preferred,
7138-
/*wantRValue*/true);
7139-
if (maybeFixedType->hasTypeVariable() ||
7140-
maybeFixedType->hasUnresolvedType()) {
7141-
return Type();
7142-
}
7143-
return maybeFixedType;
7144-
};
7145-
7146-
SmallString<64> genericParamBuf;
7147-
if (tc.getDefaultGenericArgumentsString(genericParamBuf, FoundDecl,
7148-
getPreferredType)) {
7149-
tc.diagnose(FoundGenericTypeBase->getLoc(),
7150-
diag::unbound_generic_parameter_explicit_fix)
7151-
.fixItInsertAfter(FoundGenericTypeBase->getEndLoc(), genericParamBuf);
7152-
}
7153-
}
7154-
}
7155-
71567037
std::pair<Type, ContextualTypePurpose>
71577038
FailureDiagnosis::validateContextualType(Type contextualType,
71587039
ContextualTypePurpose CTP) {
@@ -7434,19 +7315,6 @@ bool FailureDiagnosis::diagnoseAmbiguousGenericParameters() {
74347315
void FailureDiagnosis::
74357316
diagnoseAmbiguousGenericParameter(GenericTypeParamType *paramTy,
74367317
Expr *anchor) {
7437-
auto &tc = CS.getTypeChecker();
7438-
7439-
// The generic parameter may come from the explicit type in a cast expression.
7440-
if (auto *ECE = dyn_cast_or_null<ExplicitCastExpr>(anchor)) {
7441-
tc.diagnose(ECE->getLoc(), diag::unbound_generic_parameter_cast,
7442-
paramTy, ECE->getCastTypeLoc().getType())
7443-
.highlight(ECE->getCastTypeLoc().getSourceRange());
7444-
7445-
// Emit a note specifying where this came from, if we can find it.
7446-
noteGenericParameterSource(ECE->getCastTypeLoc(), paramTy, CS);
7447-
return;
7448-
}
7449-
74507318
// A very common cause of this diagnostic is a situation where a closure expr
74517319
// has no inferred type, due to being a multiline closure. Check to see if
74527320
// this is the case and (if so), speculatively diagnose that as the problem.
@@ -7464,58 +7332,15 @@ diagnoseAmbiguousGenericParameter(GenericTypeParamType *paramTy,
74647332

74657333
// Otherwise, emit an error message on the expr we have, and emit a note
74667334
// about where the generic parameter came from.
7467-
tc.diagnose(expr->getLoc(), diag::unbound_generic_parameter, paramTy);
7468-
7469-
// If we have an anchor, drill into it to emit a
7470-
// "note: generic parameter declared here".
7471-
if (!anchor) return;
7472-
7473-
7474-
if (auto TE = dyn_cast<TypeExpr>(anchor)) {
7475-
// Emit a note specifying where this came from, if we can find it.
7476-
noteGenericParameterSource(TE->getTypeLoc(), paramTy, CS);
7335+
if (!anchor) {
7336+
auto &tc = CS.getTypeChecker();
7337+
tc.diagnose(expr->getLoc(), diag::unbound_generic_parameter, paramTy);
74777338
return;
74787339
}
74797340

7480-
ConcreteDeclRef resolved;
7481-
7482-
// Simple case: direct reference to a declaration.
7483-
if (auto dre = dyn_cast<DeclRefExpr>(anchor))
7484-
resolved = dre->getDeclRef();
7485-
7486-
// Simple case: direct reference to a declaration.
7487-
if (auto MRE = dyn_cast<MemberRefExpr>(anchor))
7488-
resolved = MRE->getMember();
7489-
7490-
if (auto OCDRE = dyn_cast<OtherConstructorDeclRefExpr>(anchor))
7491-
resolved = OCDRE->getDeclRef();
7492-
7493-
7494-
// We couldn't resolve the locator to a declaration, so we're done.
7495-
if (!resolved)
7496-
return;
7497-
7498-
auto decl = resolved.getDecl();
7499-
if (auto FD = dyn_cast<FuncDecl>(decl)) {
7500-
auto name = FD->getFullName();
7501-
auto diagID = name.isOperator() ? diag::note_call_to_operator
7502-
: diag::note_call_to_func;
7503-
tc.diagnose(decl, diagID, name);
7504-
return;
7505-
}
7506-
7507-
// FIXME: Specialize for implicitly-generated constructors.
7508-
if (isa<ConstructorDecl>(decl)) {
7509-
tc.diagnose(decl, diag::note_call_to_initializer);
7510-
return;
7511-
}
7512-
7513-
if (auto PD = dyn_cast<ParamDecl>(decl)) {
7514-
tc.diagnose(decl, diag::note_init_parameter, PD->getName());
7515-
return;
7516-
}
7517-
7518-
// FIXME: Other decl types too.
7341+
MissingGenericArgumentsFailure failure(expr, CS, {paramTy},
7342+
CS.getConstraintLocator(anchor));
7343+
failure.diagnoseAsError();
75197344
}
75207345

75217346

lib/Sema/CSDiagnostics.cpp

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3004,25 +3004,29 @@ void MissingGenericArgumentsFailure::emitGenericSignatureNote(
30043004

30053005
llvm::SmallDenseMap<GenericTypeParamDecl *, Type> params;
30063006
for (auto *typeVar : cs.getTypeVariables()) {
3007-
if (auto *GP = typeVar->getImpl().getGenericParameter()) {
3008-
params[GP->getDecl()] = resolveType(typeVar);
3009-
}
3010-
}
3007+
auto *GP = typeVar->getImpl().getGenericParameter();
3008+
if (!GP)
3009+
continue;
30113010

3012-
auto getPreferredType = [&](const GenericTypeParamDecl *GP) -> Type {
3013-
auto type = params.find(GP);
3014-
assert(type != params.end());
3011+
auto type = resolveType(typeVar);
3012+
// This could happen if the diagnostic is used by CSDiag.
3013+
if (type->is<TypeVariableType>())
3014+
continue;
30153015

30163016
// If this is one of the defaulted parameter types, attempt
30173017
// to emit placeholder for it instead of `Any`.
3018-
if (std::any_of(cs.DefaultedConstraints.begin(),
3019-
cs.DefaultedConstraints.end(),
3020-
[&](const ConstraintLocator *locator) {
3021-
return GP == getParamDecl(locator);
3022-
}))
3023-
return Type();
3024-
3025-
return type->second;
3018+
if (llvm::any_of(cs.DefaultedConstraints,
3019+
[&](const ConstraintLocator *locator) {
3020+
return GP->getDecl() == getParamDecl(locator);
3021+
}))
3022+
continue;
3023+
3024+
params[GP->getDecl()] = type;
3025+
}
3026+
3027+
auto getPreferredType = [&](const GenericTypeParamDecl *GP) -> Type {
3028+
auto type = params.find(GP);
3029+
return (type == params.end()) ? Type() : type->second;
30263030
};
30273031

30283032
SmallString<64> paramsAsString;

test/Sema/diag_ambiguous_overloads.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ fg({x in x}) // expected-error {{generic parameter 'T' could not be inferred}}
2020

2121

2222
struct S {
23-
func f<T>(_ i: (T) -> T, _ j: Int) -> Void {}
23+
func f<T>(_ i: (T) -> T, _ j: Int) -> Void {} // expected-note {{in call to function 'f'}}
2424
func f(_ d: (Double) -> Double) -> Void {}
2525
func test() -> Void {
2626
f({x in x}, 2) // expected-error {{generic parameter 'T' could not be inferred}}

test/expr/unary/keypath/salvage-with-other-type-errors.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ extension A: K {
3434

3535
struct B {
3636
let v: String
37-
func f1<T, E>(block: (T) -> E) -> B {
37+
func f1<T, E>(block: (T) -> E) -> B { // expected-note {{in call to function 'f1(block:)'}}
3838
return self
3939
}
4040

0 commit comments

Comments
 (0)