Skip to content

Commit 279e147

Browse files
authored
Merge pull request #71701 from li3zhen1/my-branch
[CSDiagnostics] Add diagnostics for holes in generic parameter packs
2 parents a79ee61 + 430aa8d commit 279e147

File tree

11 files changed

+156
-1
lines changed

11 files changed

+156
-1
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4465,6 +4465,13 @@ ERROR(cannot_force_unwrap_nil_literal,none,
44654465
ERROR(could_not_infer_placeholder,none,
44664466
"could not infer type for placeholder", ())
44674467

4468+
ERROR(could_not_infer_pack_element,none,
4469+
"could not infer pack element #%0 from context", (unsigned))
4470+
4471+
NOTE(note_in_opening_pack_element,none,
4472+
"in inferring pack element #%0 of '%1'", (unsigned,StringRef))
4473+
4474+
44684475
ERROR(type_of_expression_is_ambiguous,none,
44694476
"type of expression is ambiguous without a type annotation", ())
44704477

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,
@@ -2736,6 +2740,25 @@ class SpecifyObjectLiteralTypeImport final : public ConstraintFix {
27362740
}
27372741
};
27382742

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

lib/Sema/CSBindings.cpp

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

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

lib/Sema/CSDiagnostics.cpp

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8200,6 +8200,45 @@ bool UnableToInferClosureReturnType::diagnoseAsError() {
82008200
return true;
82018201
}
82028202

8203+
bool UnableToInferGenericPackElementType::diagnoseAsError() {
8204+
auto *locator = getLocator();
8205+
auto path = locator->getPath();
8206+
8207+
auto packElementElt = locator->getLastElementAs<LocatorPathElt::PackElement>();
8208+
assert(packElementElt && "Expected path to end with a pack element locator");
8209+
8210+
if (isExpr<NilLiteralExpr>(getAnchor())) {
8211+
// `nil` appears as an element of generic pack params, let's record a
8212+
// specify contextual type for nil fix.
8213+
emitDiagnostic(diag::unresolved_nil_literal);
8214+
} else {
8215+
// unable to infer the type of an element of generic pack params
8216+
emitDiagnostic(diag::could_not_infer_pack_element,
8217+
packElementElt->getIndex());
8218+
}
8219+
8220+
if (isExpr<ApplyExpr>(locator->getAnchor())) {
8221+
// emit callee side diagnostics
8222+
if (auto *calleeLocator = getSolution().getCalleeLocator(locator)) {
8223+
if (const auto choice = getOverloadChoiceIfAvailable(calleeLocator)) {
8224+
if (auto *decl = choice->choice.getDeclOrNull()) {
8225+
if (auto applyArgToParamElt =
8226+
locator->findFirst<LocatorPathElt::ApplyArgToParam>()) {
8227+
if (auto paramDecl =
8228+
getParameterAt(decl, applyArgToParamElt->getParamIdx())) {
8229+
emitDiagnosticAt(
8230+
paramDecl->getLoc(), diag::note_in_opening_pack_element,
8231+
packElementElt->getIndex(), paramDecl->getNameStr());
8232+
}
8233+
}
8234+
}
8235+
}
8236+
}
8237+
}
8238+
8239+
return true;
8240+
}
8241+
82038242
static std::pair<StringRef, StringRef>
82048243
getImportModuleAndDefaultType(const ASTContext &ctx,
82058244
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/CSSimplify.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15108,6 +15108,7 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
1510815108
case FixKind::SpecifyContextualTypeForNil:
1510915109
case FixKind::AllowRefToInvalidDecl:
1511015110
case FixKind::SpecifyBaseTypeForOptionalUnresolvedMember:
15111+
case FixKind::SpecifyPackElementType:
1511115112
case FixKind::AllowCheckedCastCoercibleOptionalType:
1511215113
case FixKind::AllowNoopCheckedCast:
1511315114
case FixKind::AllowNoopExistentialToCFTypeCheckedCast:

lib/Sema/ConstraintSystem.cpp

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5883,9 +5883,24 @@ void constraints::simplifyLocator(ASTNode &anchor,
58835883
if (!elt)
58845884
break;
58855885

5886+
// If the 3rd element is an PackElement, add the index of pack element
5887+
// within packs to locate the correct element.
5888+
std::optional<unsigned> eltPackIdx;
5889+
if (path.size() > 2) {
5890+
if (auto eltPack = path[2].getAs<LocatorPathElt::PackElement>()) {
5891+
eltPackIdx = eltPack->getIndex();
5892+
}
5893+
}
5894+
58865895
// Extract application argument.
58875896
if (auto *args = anchorExpr->getArgs()) {
5888-
if (elt->getArgIdx() < args->size()) {
5897+
if (eltPackIdx.has_value()) {
5898+
if (elt->getArgIdx() + eltPackIdx.value() < args->size()) {
5899+
anchor = args->getExpr(elt->getArgIdx() + eltPackIdx.value());
5900+
path = path.slice(3);
5901+
continue;
5902+
}
5903+
} else if (elt->getArgIdx() < args->size()) {
58895904
anchor = args->getExpr(elt->getArgIdx());
58905905
path = path.slice(2);
58915906
continue;

test/Constraints/pack_expansion_types.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,8 +243,10 @@ func patternInstantiationConcreteValid() {
243243
func patternInstantiationConcreteInvalid() {
244244
let _: Set<Int> = patternInstantiationTupleTest1()
245245
// expected-error@-1 {{cannot convert value of type '(repeat Array<_>)' to specified type 'Set<Int>'}}
246+
// expected-error@-2 {{could not infer pack element #0 from context}}
246247

247248
let _: (Array<Int>, Set<String>) = patternInstantiationTupleTest1() // expected-error {{'(repeat Array<Int, _>)' is not convertible to '(Array<Int>, Set<String>)', tuples have a different number of elements}}
249+
// expected-error@-1 {{could not infer pack element #1 from context}}
248250
}
249251

250252
func patternInstantiationGenericValid<each T, each U>(t: repeat each T, u: repeat each U)
@@ -275,6 +277,7 @@ func patternInstantiationGenericInvalid<each T: Hashable>(t: repeat each T) {
275277
// expected-error@-1 {{generic parameter 'each T' could not be inferred}}
276278

277279
let _: (repeat Array<each T>, Set<String>) = patternInstantiationTupleTest1() // expected-error {{'(repeat Array<repeat each T, _>)' is not convertible to '(repeat Array<each T>, Set<String>)', tuples have a different number of elements}}
280+
// expected-error@-1 {{could not infer pack element #1 from context}}
278281
}
279282

280283
// rdar://107996926 - Vanishing metatype of tuple not supported

test/Constraints/variadic_generic_functions.swift

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,3 +79,29 @@ 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) {} // expected-note {{in inferring pack element #0 of 'value'}}
87+
// expected-note@-1 {{in inferring pack element #0 of 'value'}}
88+
// expected-note@-2 {{in inferring pack element #1 of 'value'}}
89+
90+
foo(nil) // expected-error {{'nil' requires a contextual type}}
91+
foo(nil, 1) // expected-error {{'nil' requires a contextual type}}
92+
foo(2, nil) // expected-error {{'nil' requires a contextual type}}
93+
94+
func bar<each T, U, each W>(_ t: repeat each T, u: U, w: repeat each W) {} // expected-note {{in inferring pack element #2 of 'w'}}
95+
// expected-note@-1 {{in inferring pack element #3 of 't'}}
96+
97+
bar(1, 2, 3, nil, "Hello", u: 3, w: 4, 8, nil) // expected-error {{'nil' requires a contextual type}}
98+
// expected-error@-1 {{'nil' requires a contextual type}}
99+
100+
101+
func fooWithOverload(_ value: Int) {}
102+
func fooWithOverload<each T>(_ value: repeat each T) {}
103+
// expected-note@-1 {{in inferring pack element #4 of 'value'}}
104+
105+
fooWithOverload(0, 1, 2, 3, nil) // expected-error {{'nil' requires a contextual type}}
106+
107+
}

test/Constraints/variadic_generic_types.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,3 +106,15 @@ do {
106106
}
107107
}
108108
}
109+
110+
// apple/swift#69432 - Passing nil to a parameter pack fails to produce diagnostic for expression
111+
do {
112+
struct Foo<each T> {
113+
init(_ value: repeat each T) {}
114+
// expected-note@-1 {{in inferring pack element #0 of 'value'}}
115+
// expected-note@-2 {{in inferring pack element #0 of 'value'}}
116+
}
117+
118+
_ = Foo(nil) // expected-error {{'nil' requires a contextual type}}
119+
_ = Foo(nil, 1) // expected-error {{'nil' requires a contextual type}}
120+
}

0 commit comments

Comments
 (0)