Skip to content

Commit 2f3809c

Browse files
authored
Merge pull request #25149 from xedin/diag-missing-generic-args
[ConstraintSystem] Detect and diagnose missing generic arguments
2 parents 95efeda + da799eb commit 2f3809c

32 files changed

+586
-273
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -927,6 +927,8 @@ NOTE(note_call_to_operator,none,
927927
"in call to operator %0", (DeclName))
928928
NOTE(note_call_to_func,none,
929929
"in call to function %0", (DeclName))
930+
NOTE(note_call_to_subscript,none,
931+
"in call to %0", (DeclName))
930932
NOTE(note_call_to_initializer,none,
931933
"in call to initializer", ())
932934
NOTE(note_init_parameter,none,

include/swift/AST/TypeRepr.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,10 @@ class GenericIdentTypeRepr final : public ComponentIdentTypeRepr,
365365
ArrayRef<TypeRepr*> GenericArgs,
366366
SourceRange AngleBrackets);
367367

368+
unsigned getNumGenericArgs() const {
369+
return Bits.GenericIdentTypeRepr.NumGenericArgs;
370+
}
371+
368372
ArrayRef<TypeRepr*> getGenericArgs() const {
369373
return {getTrailingObjects<TypeRepr*>(),
370374
Bits.GenericIdentTypeRepr.NumGenericArgs};

lib/Sema/CSDiag.cpp

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

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

74687336
// Otherwise, emit an error message on the expr we have, and emit a note
74697337
// about where the generic parameter came from.
7470-
tc.diagnose(expr->getLoc(), diag::unbound_generic_parameter, paramTy);
7471-
7472-
// If we have an anchor, drill into it to emit a
7473-
// "note: generic parameter declared here".
7474-
if (!anchor) return;
7475-
7476-
7477-
if (auto TE = dyn_cast<TypeExpr>(anchor)) {
7478-
// Emit a note specifying where this came from, if we can find it.
7479-
noteGenericParameterSource(TE->getTypeLoc(), paramTy, CS);
7338+
if (!anchor) {
7339+
auto &tc = CS.getTypeChecker();
7340+
tc.diagnose(expr->getLoc(), diag::unbound_generic_parameter, paramTy);
74807341
return;
74817342
}
74827343

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

75247349

0 commit comments

Comments
 (0)