Skip to content

Commit 82b955b

Browse files
committed
[CSDiagnostics] Detect and diagnose contextual mismatches with default value
1 parent aa286b7 commit 82b955b

File tree

6 files changed

+115
-1
lines changed

6 files changed

+115
-1
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ NOTE(extended_type_declared_here,none,
3838
"extended type declared here", ())
3939
NOTE(opaque_return_type_declared_here,none,
4040
"opaque return type declared here", ())
41+
NOTE(default_value_declared_here,none,
42+
"default value declared here", ())
4143

4244
//------------------------------------------------------------------------------
4345
// MARK: Constraint solver diagnostics
@@ -6262,5 +6264,9 @@ ERROR(cannot_default_generic_parameter_invalid_requirement, none,
62626264
"requirement '%1' refers to other generic parameters",
62636265
(Type, StringRef))
62646266

6267+
ERROR(cannot_convert_default_value_type_to_argument_type, none,
6268+
"cannot convert default value of type %0 to expected argument type %1 for parameter #%2",
6269+
(Type, Type, unsigned))
6270+
62656271
#define UNDEFINE_DIAGNOSTIC_MACROS
62666272
#include "DefineDiagnosticMacros.h"

include/swift/Sema/CSFix.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,10 @@ enum class FixKind : uint8_t {
382382

383383
/// Produce an error for not getting a compile-time constant
384384
NotCompileTimeConst,
385+
386+
/// Ignore a type mismatch while trying to infer generic parameter type
387+
/// from default expression.
388+
IgnoreDefaultExprTypeMismatch,
385389
};
386390

387391
class ConstraintFix {
@@ -2896,6 +2900,29 @@ class AllowSwiftToCPointerConversion final : public ConstraintFix {
28962900
ConstraintLocator *locator);
28972901
};
28982902

2903+
class IgnoreDefaultExprTypeMismatch : public AllowArgumentMismatch {
2904+
protected:
2905+
IgnoreDefaultExprTypeMismatch(ConstraintSystem &cs, Type argType,
2906+
Type paramType, ConstraintLocator *locator)
2907+
: AllowArgumentMismatch(cs, FixKind::IgnoreDefaultExprTypeMismatch,
2908+
argType, paramType, locator) {}
2909+
2910+
public:
2911+
std::string getName() const override {
2912+
return "allow default expression conversion mismatch";
2913+
}
2914+
2915+
bool diagnose(const Solution &solution, bool asNote = false) const override;
2916+
2917+
static IgnoreDefaultExprTypeMismatch *create(ConstraintSystem &cs,
2918+
Type argType, Type paramType,
2919+
ConstraintLocator *locator);
2920+
2921+
static bool classof(const ConstraintFix *fix) {
2922+
return fix->getKind() == FixKind::IgnoreDefaultExprTypeMismatch;
2923+
}
2924+
};
2925+
28992926
} // end namespace constraints
29002927
} // end namespace swift
29012928

lib/Sema/CSDiagnostics.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7966,3 +7966,27 @@ bool SwiftToCPointerConversionInInvalidContext::diagnoseAsError() {
79667966
paramType, callee->getDescriptiveKind(), callee->getName());
79677967
return true;
79687968
}
7969+
7970+
bool DefaultExprTypeMismatch::diagnoseAsError() {
7971+
auto *locator = getLocator();
7972+
7973+
unsigned paramIdx =
7974+
locator->castLastElementTo<LocatorPathElt::ApplyArgToParam>()
7975+
.getParamIdx();
7976+
7977+
emitDiagnostic(diag::cannot_convert_default_value_type_to_argument_type,
7978+
getFromType(), getToType(), paramIdx);
7979+
7980+
auto overload = getCalleeOverloadChoiceIfAvailable(locator);
7981+
assert(overload);
7982+
7983+
auto *PD = getParameterList(overload->choice.getDecl())->get(paramIdx);
7984+
7985+
auto note = emitDiagnosticAt(PD->getLoc(), diag::default_value_declared_here);
7986+
7987+
if (auto *defaultExpr = PD->getTypeCheckedDefaultExpr()) {
7988+
note.highlight(defaultExpr->getSourceRange());
7989+
}
7990+
7991+
return true;
7992+
}

lib/Sema/CSDiagnostics.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2665,6 +2665,28 @@ class SwiftToCPointerConversionInInvalidContext final
26652665
bool diagnoseAsError() override;
26662666
};
26672667

2668+
/// Diagnose situations where the type of default expression doesn't
2669+
/// match expected type of the argument i.e. generic parameter type
2670+
/// was inferred from result:
2671+
///
2672+
/// \code
2673+
/// func test<T>(_: T = 42) -> T { ... }
2674+
///
2675+
/// let _: String = test() // conflict between `String` and `Int`.
2676+
/// \endcode
2677+
class DefaultExprTypeMismatch final : public ContextualFailure {
2678+
public:
2679+
DefaultExprTypeMismatch(const Solution &solution, Type argType,
2680+
Type paramType, ConstraintLocator *locator)
2681+
: ContextualFailure(solution, argType, paramType, locator) {}
2682+
2683+
SourceLoc getLoc() const override {
2684+
return constraints::getLoc(getLocator()->getAnchor());
2685+
}
2686+
2687+
bool diagnoseAsError() override;
2688+
};
2689+
26682690
} // end namespace constraints
26692691
} // end namespace swift
26702692

lib/Sema/CSFix.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2076,3 +2076,18 @@ AllowSwiftToCPointerConversion::create(ConstraintSystem &cs,
20762076
ConstraintLocator *locator) {
20772077
return new (cs.getAllocator()) AllowSwiftToCPointerConversion(cs, locator);
20782078
}
2079+
2080+
bool IgnoreDefaultExprTypeMismatch::diagnose(const Solution &solution,
2081+
bool asNote) const {
2082+
DefaultExprTypeMismatch failure(solution, getFromType(), getToType(),
2083+
getLocator());
2084+
return failure.diagnose(asNote);
2085+
}
2086+
2087+
IgnoreDefaultExprTypeMismatch *
2088+
IgnoreDefaultExprTypeMismatch::create(ConstraintSystem &cs, Type argType,
2089+
Type paramType,
2090+
ConstraintLocator *locator) {
2091+
return new (cs.getAllocator())
2092+
IgnoreDefaultExprTypeMismatch(cs, argType, paramType, locator);
2093+
}

lib/Sema/CSSimplify.cpp

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4870,6 +4870,25 @@ bool ConstraintSystem::repairFailures(
48704870
if (hasFixFor(loc, FixKind::RemoveExtraneousArguments))
48714871
return true;
48724872

4873+
// If the argument couldn't be found, this could be a default value
4874+
// type mismatch.
4875+
if (!simplifyLocatorToAnchor(loc)) {
4876+
auto *calleeLocator = getCalleeLocator(loc);
4877+
unsigned paramIdx =
4878+
loc->castLastElementTo<LocatorPathElt::ApplyArgToParam>()
4879+
.getParamIdx();
4880+
4881+
if (auto overload = findSelectedOverloadFor(calleeLocator)) {
4882+
if (auto *decl = overload->choice.getDeclOrNull()) {
4883+
if (getParameterList(decl)->get(paramIdx)->getTypeOfDefaultExpr()) {
4884+
conversionsOrFixes.push_back(
4885+
IgnoreDefaultExprTypeMismatch::create(*this, lhs, rhs, loc));
4886+
break;
4887+
}
4888+
}
4889+
}
4890+
}
4891+
48734892
conversionsOrFixes.push_back(
48744893
AllowArgumentMismatch::create(*this, lhs, rhs, loc));
48754894
break;
@@ -12438,7 +12457,8 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
1243812457
: SolutionKind::Solved;
1243912458
}
1244012459

12441-
case FixKind::AllowArgumentTypeMismatch: {
12460+
case FixKind::AllowArgumentTypeMismatch:
12461+
case FixKind::IgnoreDefaultExprTypeMismatch: {
1244212462
auto impact = 2;
1244312463
// If there are any other argument mismatches already detected for this
1244412464
// call, we increase the score even higher so more argument fixes means

0 commit comments

Comments
 (0)