Skip to content

Commit b44fbf6

Browse files
committed
[CSDiagnostics] Add diags for holes in generic parameter pack
1 parent e6ca3a6 commit b44fbf6

File tree

8 files changed

+126
-1
lines changed

8 files changed

+126
-1
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4460,6 +4460,9 @@ ERROR(cannot_force_unwrap_nil_literal,none,
44604460
ERROR(could_not_infer_placeholder,none,
44614461
"could not infer type for placeholder", ())
44624462

4463+
ERROR(could_not_infer_pack_element,none,
4464+
"could not infer pack element #%0 from context", (unsigned))
4465+
44634466
ERROR(type_of_expression_is_ambiguous,none,
44644467
"type of expression is ambiguous without a type annotation", ())
44654468

include/swift/Sema/CSFix.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,10 @@ enum class FixKind : uint8_t {
262262
/// is declared was not imported.
263263
SpecifyObjectLiteralTypeImport,
264264

265+
/// Type of the element in generic pack couldn't be inferred and has to be
266+
/// specified explicitly.
267+
SpecifyPackElementType,
268+
265269
/// Allow any type (and not just class or class-constrained type) to
266270
/// be convertible to AnyObject.
267271
AllowNonClassTypeToConvertToAnyObject,
@@ -2737,6 +2741,25 @@ class SpecifyObjectLiteralTypeImport final : public ConstraintFix {
27372741
}
27382742
};
27392743

2744+
class SpecifyPackElementType final : public ConstraintFix {
2745+
SpecifyPackElementType(ConstraintSystem &cs, ConstraintLocator *locator)
2746+
: ConstraintFix(cs, FixKind::SpecifyPackElementType, locator) {}
2747+
public:
2748+
std::string getName() const override {
2749+
return "specify pack element type";
2750+
}
2751+
2752+
bool diagnose(const Solution &solution, bool asNote) const override;
2753+
2754+
static SpecifyPackElementType *create(ConstraintSystem &cs,
2755+
ConstraintLocator *locator);
2756+
2757+
static bool classof(const ConstraintFix *fix) {
2758+
return fix->getKind() == FixKind::SpecifyPackElementType;
2759+
}
2760+
};
2761+
2762+
27402763
class AddQualifierToAccessTopLevelName final : public ConstraintFix {
27412764
AddQualifierToAccessTopLevelName(ConstraintSystem &cs,
27422765
ConstraintLocator *locator)

lib/Sema/CSBindings.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2549,6 +2549,14 @@ TypeVariableBinding::fixForHole(ConstraintSystem &cs) const {
25492549
return std::make_pair(fix, defaultImpact);
25502550
}
25512551

2552+
if (dstLocator->isLastElement<LocatorPathElt::PackElement>()) {
2553+
2554+
// A hole appears as an element of generic pack params
2555+
ConstraintFix *Fix = SpecifyPackElementType::create(cs, dstLocator);
2556+
return std::make_pair(Fix, defaultImpact);
2557+
}
2558+
2559+
return std::nullopt;
25522560
return std::nullopt;
25532561
}
25542562

lib/Sema/CSDiagnostics.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8187,6 +8187,37 @@ bool UnableToInferClosureReturnType::diagnoseAsError() {
81878187
return true;
81888188
}
81898189

8190+
bool UnableToInferGenericPackElementType::diagnoseAsError() {
8191+
8192+
const auto* locator = getLocator();
8193+
auto path = locator->getPath();
8194+
8195+
if (path.size() > 1) {
8196+
const auto applyArgToParamElt = (path.end() - 2)->getAs<LocatorPathElt::ApplyArgToParam>();
8197+
8198+
if (!applyArgToParamElt)
8199+
return false;
8200+
8201+
unsigned eltIdx = applyArgToParamElt->getArgIdx();
8202+
auto anchor = getAnchor();
8203+
8204+
8205+
// `nil` appears as an element of generic pack params, let's record a
8206+
// specify contextual type for nil fix.
8207+
if (isExpr<NilLiteralExpr>(anchor)) {
8208+
emitDiagnostic(diag::unresolved_nil_literal);
8209+
return true;
8210+
}
8211+
8212+
// unable to infer the type of an element of generic pack params
8213+
emitDiagnostic(diag::could_not_infer_pack_element, eltIdx);
8214+
return true;
8215+
}
8216+
8217+
return false;
8218+
}
8219+
8220+
81908221
static std::pair<StringRef, StringRef>
81918222
getImportModuleAndDefaultType(const ASTContext &ctx,
81928223
const ObjectLiteralExpr *expr) {

lib/Sema/CSDiagnostics.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2343,6 +2343,15 @@ class UnableToInferClosureReturnType final : public FailureDiagnostic {
23432343
bool diagnoseAsError() override;
23442344
};
23452345

2346+
class UnableToInferGenericPackElementType final : public FailureDiagnostic {
2347+
public:
2348+
UnableToInferGenericPackElementType(const Solution &solution,
2349+
ConstraintLocator *locator)
2350+
: FailureDiagnostic(solution, locator) {}
2351+
2352+
bool diagnoseAsError() override;
2353+
};
2354+
23462355
class UnableToInferProtocolLiteralType final : public FailureDiagnostic {
23472356
public:
23482357
UnableToInferProtocolLiteralType(const Solution &solution,

lib/Sema/CSFix.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1972,6 +1972,20 @@ AllowNonClassTypeToConvertToAnyObject::create(ConstraintSystem &cs, Type type,
19721972
AllowNonClassTypeToConvertToAnyObject(cs, type, locator);
19731973
}
19741974

1975+
1976+
bool SpecifyPackElementType::diagnose(const Solution &solution,
1977+
bool asNote) const {
1978+
UnableToInferGenericPackElementType failure(solution, getLocator());
1979+
return failure.diagnose(asNote);
1980+
}
1981+
1982+
SpecifyPackElementType *
1983+
SpecifyPackElementType::create(ConstraintSystem &cs,
1984+
ConstraintLocator *locator) {
1985+
return new (cs.getAllocator()) SpecifyPackElementType(cs, locator);
1986+
}
1987+
1988+
19751989
bool AddQualifierToAccessTopLevelName::diagnose(const Solution &solution,
19761990
bool asNote) const {
19771991
MissingQualifierInMemberRefFailure failure(solution, getLocator());

lib/Sema/ConstraintSystem.cpp

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5881,9 +5881,28 @@ void constraints::simplifyLocator(ASTNode &anchor,
58815881
if (!elt)
58825882
break;
58835883

5884+
// If the 3rd element is an PackElement, add the index of pack element within
5885+
// packs to locate the correct element.
5886+
bool hasEltPack = false;
5887+
unsigned eltPackIdx = 0;
5888+
if (path.size() > 2) {
5889+
auto eltPack = path[2].getAs<LocatorPathElt::PackElement>();
5890+
if (eltPack) {
5891+
hasEltPack = true;
5892+
eltPackIdx = eltPack->getIndex();
5893+
}
5894+
}
5895+
58845896
// Extract application argument.
58855897
if (auto *args = anchorExpr->getArgs()) {
5886-
if (elt->getArgIdx() < args->size()) {
5898+
if (hasEltPack) {
5899+
if (elt->getArgIdx() + eltPackIdx < args->size()) {
5900+
anchor = args->getExpr(elt->getArgIdx() + eltPackIdx);
5901+
path = path.slice(3);
5902+
continue;
5903+
}
5904+
}
5905+
else if (elt->getArgIdx() < args->size()) {
58875906
anchor = args->getExpr(elt->getArgIdx());
58885907
path = path.slice(2);
58895908
continue;

test/Constraints/variadic_generic_functions.swift

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,3 +79,21 @@ do {
7979

8080
func bar<each T>() -> (repeat each T) {}
8181
}
82+
83+
84+
// apple/swift#69432 - Passing nil to a parameter pack fails to produce diagnostic for expression
85+
do {
86+
func foo<each T>(_ value: repeat each T) {}
87+
88+
foo(nil) // expected-error {{'nil' requires a contextual type}}
89+
foo(1, nil) // expected-error {{'nil' requires a contextual type}}
90+
foo(nil, 1) // expected-error {{'nil' requires a contextual type}}
91+
92+
func bar<each T, U, each W>(_ t: repeat each T, u: U, w: repeat each W) {}
93+
94+
bar(1, nil, "Hello", nil, u: 3, w: 4, 8, nil)
95+
// expected-error@-1 {{'nil' requires a contextual type}}
96+
// expected-error@-2 {{'nil' requires a contextual type}}
97+
// expected-error@-3 {{'nil' requires a contextual type}}
98+
99+
}

0 commit comments

Comments
 (0)