Skip to content

Commit bfe1987

Browse files
committed
[ConstraintSystem] Detect and diagnose missing generic arguments
Introduce a fix to detect and diagnose situations when omitted generic arguments couldn't be deduced by the solver based on the enclosing context. Example: ```swift struct S<T> { } _ = S() // There is not enough context to deduce `T` ``` Resolves: rdar://problem/51203824
1 parent a3e6aba commit bfe1987

31 files changed

+585
-272
lines changed

include/swift/AST/DiagnosticsSema.def

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

include/swift/AST/TypeRepr.h

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

366+
unsigned getNumGenericArgs() const {
367+
return Bits.GenericIdentTypeRepr.NumGenericArgs;
368+
}
369+
366370
ArrayRef<TypeRepr*> getGenericArgs() const {
367371
return {getTrailingObjects<TypeRepr*>(),
368372
Bits.GenericIdentTypeRepr.NumGenericArgs};

lib/Sema/CSDiag.cpp

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

7086-
static bool hasGenericParameter(const GenericTypeDecl *generic,
7087-
GenericTypeParamType *paramTy) {
7088-
auto *decl = paramTy->getDecl();
7089-
if (!decl)
7090-
return false;
7091-
7092-
return decl->getDeclContext() == generic;
7093-
}
7094-
7095-
static void noteGenericParameterSource(const TypeLoc &loc,
7096-
GenericTypeParamType *paramTy,
7097-
ConstraintSystem &cs) {
7098-
const GenericTypeDecl *FoundDecl = nullptr;
7099-
const ComponentIdentTypeRepr *FoundGenericTypeBase = nullptr;
7100-
7101-
// Walk the TypeRepr to find the type in question.
7102-
if (auto typerepr = loc.getTypeRepr()) {
7103-
struct FindGenericTypeDecl : public ASTWalker {
7104-
const GenericTypeDecl *FoundDecl = nullptr;
7105-
const ComponentIdentTypeRepr *FoundGenericTypeBase = nullptr;
7106-
GenericTypeParamType *ParamTy;
7107-
7108-
FindGenericTypeDecl(GenericTypeParamType *ParamTy)
7109-
: ParamTy(ParamTy) {}
7110-
7111-
bool walkToTypeReprPre(TypeRepr *T) override {
7112-
// If we already emitted the note, we're done.
7113-
if (FoundDecl) return false;
7114-
7115-
if (auto ident = dyn_cast<ComponentIdentTypeRepr>(T)) {
7116-
auto *generic =
7117-
dyn_cast_or_null<GenericTypeDecl>(ident->getBoundDecl());
7118-
if (generic && hasGenericParameter(generic, ParamTy)) {
7119-
FoundDecl = generic;
7120-
FoundGenericTypeBase = ident;
7121-
return false;
7122-
}
7123-
}
7124-
// Keep walking.
7125-
return true;
7126-
}
7127-
} findGenericTypeDecl(paramTy);
7128-
7129-
typerepr->walk(findGenericTypeDecl);
7130-
FoundDecl = findGenericTypeDecl.FoundDecl;
7131-
FoundGenericTypeBase = findGenericTypeDecl.FoundGenericTypeBase;
7132-
}
7133-
7134-
// If we didn't find the type in the TypeRepr, fall back to the type in the
7135-
// type checked expression.
7136-
if (!FoundDecl) {
7137-
if (const GenericTypeDecl *generic = loc.getType()->getAnyGeneric())
7138-
if (hasGenericParameter(generic, paramTy))
7139-
FoundDecl = generic;
7140-
}
7141-
7142-
auto &tc = cs.getTypeChecker();
7143-
if (FoundDecl) {
7144-
Type type;
7145-
if (auto *nominal = dyn_cast<NominalTypeDecl>(FoundDecl))
7146-
type = nominal->getDeclaredType();
7147-
else if (auto *typeAlias = dyn_cast<TypeAliasDecl>(FoundDecl))
7148-
type = typeAlias->getUnboundGenericType();
7149-
else
7150-
type = FoundDecl->getDeclaredInterfaceType();
7151-
tc.diagnose(FoundDecl, diag::archetype_declared_in_type, paramTy, type);
7152-
}
7153-
7154-
if (FoundGenericTypeBase && !isa<GenericIdentTypeRepr>(FoundGenericTypeBase)){
7155-
assert(FoundDecl);
7156-
7157-
// If we can, prefer using any types already fixed by the constraint system.
7158-
// This lets us produce fixes like `Pair<Int, Any>` instead of defaulting to
7159-
// `Pair<Any, Any>`.
7160-
// Right now we only handle this when the type that's at fault is the
7161-
// top-level type passed to this function.
7162-
auto type = loc.getType();
7163-
if (!type)
7164-
type = cs.getType(loc);
7165-
7166-
ArrayRef<Type> genericArgs;
7167-
7168-
if (auto *boundGenericTy = type->getAs<BoundGenericType>()) {
7169-
if (boundGenericTy->getDecl() == FoundDecl)
7170-
genericArgs = boundGenericTy->getGenericArgs();
7171-
}
7172-
7173-
auto getPreferredType =
7174-
[&](const GenericTypeParamDecl *genericParam) -> Type {
7175-
// If we were able to get the generic arguments (i.e. the types used at
7176-
// FoundDecl's use site), we can prefer those...
7177-
if (genericArgs.empty())
7178-
return Type();
7179-
7180-
Type preferred = genericArgs[genericParam->getIndex()];
7181-
if (!preferred || preferred->hasError())
7182-
return Type();
7183-
7184-
// ...but only if they were actually resolved by the constraint system
7185-
// despite the failure.
7186-
Type maybeFixedType = cs.getFixedTypeRecursive(preferred,
7187-
/*wantRValue*/true);
7188-
if (maybeFixedType->hasTypeVariable() ||
7189-
maybeFixedType->hasUnresolvedType()) {
7190-
return Type();
7191-
}
7192-
return maybeFixedType;
7193-
};
7194-
7195-
SmallString<64> genericParamBuf;
7196-
if (tc.getDefaultGenericArgumentsString(genericParamBuf, FoundDecl,
7197-
getPreferredType)) {
7198-
tc.diagnose(FoundGenericTypeBase->getLoc(),
7199-
diag::unbound_generic_parameter_explicit_fix)
7200-
.fixItInsertAfter(FoundGenericTypeBase->getEndLoc(), genericParamBuf);
7201-
}
7202-
}
7203-
}
7204-
72057086
std::pair<Type, ContextualTypePurpose>
72067087
FailureDiagnosis::validateContextualType(Type contextualType,
72077088
ContextualTypePurpose CTP) {
@@ -7483,19 +7364,6 @@ bool FailureDiagnosis::diagnoseAmbiguousGenericParameters() {
74837364
void FailureDiagnosis::
74847365
diagnoseAmbiguousGenericParameter(GenericTypeParamType *paramTy,
74857366
Expr *anchor) {
7486-
auto &tc = CS.getTypeChecker();
7487-
7488-
// The generic parameter may come from the explicit type in a cast expression.
7489-
if (auto *ECE = dyn_cast_or_null<ExplicitCastExpr>(anchor)) {
7490-
tc.diagnose(ECE->getLoc(), diag::unbound_generic_parameter_cast,
7491-
paramTy, ECE->getCastTypeLoc().getType())
7492-
.highlight(ECE->getCastTypeLoc().getSourceRange());
7493-
7494-
// Emit a note specifying where this came from, if we can find it.
7495-
noteGenericParameterSource(ECE->getCastTypeLoc(), paramTy, CS);
7496-
return;
7497-
}
7498-
74997367
// A very common cause of this diagnostic is a situation where a closure expr
75007368
// has no inferred type, due to being a multiline closure. Check to see if
75017369
// this is the case and (if so), speculatively diagnose that as the problem.
@@ -7513,58 +7381,15 @@ diagnoseAmbiguousGenericParameter(GenericTypeParamType *paramTy,
75137381

75147382
// Otherwise, emit an error message on the expr we have, and emit a note
75157383
// about where the generic parameter came from.
7516-
tc.diagnose(expr->getLoc(), diag::unbound_generic_parameter, paramTy);
7517-
7518-
// If we have an anchor, drill into it to emit a
7519-
// "note: generic parameter declared here".
7520-
if (!anchor) return;
7521-
7522-
7523-
if (auto TE = dyn_cast<TypeExpr>(anchor)) {
7524-
// Emit a note specifying where this came from, if we can find it.
7525-
noteGenericParameterSource(TE->getTypeLoc(), paramTy, CS);
7384+
if (!anchor) {
7385+
auto &tc = CS.getTypeChecker();
7386+
tc.diagnose(expr->getLoc(), diag::unbound_generic_parameter, paramTy);
75267387
return;
75277388
}
75287389

7529-
ConcreteDeclRef resolved;
7530-
7531-
// Simple case: direct reference to a declaration.
7532-
if (auto dre = dyn_cast<DeclRefExpr>(anchor))
7533-
resolved = dre->getDeclRef();
7534-
7535-
// Simple case: direct reference to a declaration.
7536-
if (auto MRE = dyn_cast<MemberRefExpr>(anchor))
7537-
resolved = MRE->getMember();
7538-
7539-
if (auto OCDRE = dyn_cast<OtherConstructorDeclRefExpr>(anchor))
7540-
resolved = OCDRE->getDeclRef();
7541-
7542-
7543-
// We couldn't resolve the locator to a declaration, so we're done.
7544-
if (!resolved)
7545-
return;
7546-
7547-
auto decl = resolved.getDecl();
7548-
if (auto FD = dyn_cast<FuncDecl>(decl)) {
7549-
auto name = FD->getFullName();
7550-
auto diagID = name.isOperator() ? diag::note_call_to_operator
7551-
: diag::note_call_to_func;
7552-
tc.diagnose(decl, diagID, name);
7553-
return;
7554-
}
7555-
7556-
// FIXME: Specialize for implicitly-generated constructors.
7557-
if (isa<ConstructorDecl>(decl)) {
7558-
tc.diagnose(decl, diag::note_call_to_initializer);
7559-
return;
7560-
}
7561-
7562-
if (auto PD = dyn_cast<ParamDecl>(decl)) {
7563-
tc.diagnose(decl, diag::note_init_parameter, PD->getName());
7564-
return;
7565-
}
7566-
7567-
// FIXME: Other decl types too.
7390+
MissingGenericArgumentsFailure failure(expr, CS, {paramTy},
7391+
CS.getConstraintLocator(anchor));
7392+
failure.diagnoseAsError();
75687393
}
75697394

75707395

0 commit comments

Comments
 (0)