Skip to content

Commit 03f88a0

Browse files
committed
[CSSimplify] Add tailored diagnostics for same-shape mismatches related to arguments
Suggest to drop tuples, synthesized or remove extraneous arguments based on pack shape mismatches.
1 parent bbe305c commit 03f88a0

File tree

4 files changed

+114
-16
lines changed

4 files changed

+114
-16
lines changed

lib/Sema/CSDiagnostics.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5232,9 +5232,6 @@ bool MissingArgumentsFailure::diagnoseInvalidTupleDestructuring() const {
52325232
if (!locator->isLastElement<LocatorPathElt::ApplyArgument>())
52335233
return false;
52345234

5235-
if (SynthesizedArgs.size() < 2)
5236-
return false;
5237-
52385235
auto *args = getArgumentListFor(locator);
52395236
if (!args)
52405237
return false;
@@ -5251,11 +5248,16 @@ bool MissingArgumentsFailure::diagnoseInvalidTupleDestructuring() const {
52515248
if (!decl)
52525249
return false;
52535250

5251+
auto *funcType =
5252+
resolveType(selectedOverload->openedType)->getAs<FunctionType>();
5253+
if (!funcType)
5254+
return false;
5255+
52545256
auto name = decl->getBaseName();
52555257
auto diagnostic =
52565258
emitDiagnostic(diag::cannot_convert_single_tuple_into_multiple_arguments,
52575259
decl->getDescriptiveKind(), name, name.isSpecial(),
5258-
SynthesizedArgs.size(), isa<TupleExpr>(argExpr));
5260+
funcType->getNumParams(), isa<TupleExpr>(argExpr));
52595261

52605262
// If argument is a literal tuple, let's suggest removal of parentheses.
52615263
if (auto *TE = dyn_cast<TupleExpr>(argExpr)) {

lib/Sema/CSSimplify.cpp

Lines changed: 103 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1793,7 +1793,13 @@ static ConstraintSystem::TypeMatchResult matchCallArguments(
17931793
auto *argPack = PackType::get(cs.getASTContext(), argTypes);
17941794
auto *argPackExpansion = PackExpansionType::get(argPack, argPack);
17951795

1796-
cs.addConstraint(subKind, argPackExpansion, paramTy, loc);
1796+
auto firstArgIdx =
1797+
argTypes.empty() ? paramIdx : parameterBindings[paramIdx].front();
1798+
1799+
cs.addConstraint(
1800+
subKind, argPackExpansion, paramTy,
1801+
locator.withPathElement(LocatorPathElt::ApplyArgToParam(
1802+
firstArgIdx, paramIdx, param.getParameterFlags())));
17971803
continue;
17981804
}
17991805
}
@@ -5673,6 +5679,18 @@ bool ConstraintSystem::repairFailures(
56735679
if (hasFixFor(loc, FixKind::RemoveExtraneousArguments))
56745680
return true;
56755681

5682+
// If parameter is a pack, let's see if we have already recorded
5683+
// either synthesized or extraneous argument fixes.
5684+
if (rhs->is<PackType>()) {
5685+
ArrayRef tmpPath(path);
5686+
5687+
// Path would end with `ApplyArgument`.
5688+
auto *argsLoc = getConstraintLocator(anchor, tmpPath.drop_back());
5689+
if (hasFixFor(argsLoc, FixKind::RemoveExtraneousArguments) ||
5690+
hasFixFor(argsLoc, FixKind::AddMissingArguments))
5691+
return true;
5692+
}
5693+
56765694
// If the argument couldn't be found, this could be a default value
56775695
// type mismatch.
56785696
if (!simplifyLocatorToAnchor(loc)) {
@@ -7271,9 +7289,16 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
72717289
case TypeKind::Pack: {
72727290
auto tmpPackLoc = locator.withPathElement(LocatorPathElt::PackType(type1));
72737291
auto packLoc = tmpPackLoc.withPathElement(LocatorPathElt::PackType(type2));
7274-
return matchPackTypes(cast<PackType>(desugar1),
7275-
cast<PackType>(desugar2),
7276-
kind, subflags, packLoc);
7292+
7293+
auto result =
7294+
matchPackTypes(cast<PackType>(desugar1), cast<PackType>(desugar2),
7295+
kind, subflags, packLoc);
7296+
7297+
// Let `repairFailures` attempt to "fix" this.
7298+
if (shouldAttemptFixes() && result.isFailure())
7299+
break;
7300+
7301+
return result;
72777302
}
72787303
case TypeKind::PackExpansion: {
72797304
auto expansion1 = cast<PackExpansionType>(desugar1);
@@ -13273,16 +13298,87 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifySameShapeConstraint(
1327313298
return SolutionKind::Solved;
1327413299

1327513300
if (shouldAttemptFixes()) {
13301+
// If there are placeholders involved shape mismatches are most
13302+
// likely just a symptom of some other issue i.e. type mismatch.
1327613303
if (type1->hasPlaceholder() || type2->hasPlaceholder())
1327713304
return SolutionKind::Solved;
1327813305

13306+
auto recordShapeFix = [&](ConstraintFix *fix,
13307+
unsigned impact) -> SolutionKind {
13308+
return recordFix(fix, impact) ? SolutionKind::Error
13309+
: SolutionKind::Solved;
13310+
};
13311+
13312+
// Let's check whether we can produce a tailored fix for argument/parameter
13313+
// mismatches.
13314+
if (locator.endsWith<LocatorPathElt::PackShape>()) {
13315+
SmallVector<LocatorPathElt> path;
13316+
auto anchor = locator.getLocatorParts(path);
13317+
13318+
// Drop `PackShape`
13319+
path.pop_back();
13320+
13321+
// Tailed diagnostics for argument/parameter mismatches - there
13322+
// are either missing or extra arguments.
13323+
if (path.size() > 0 &&
13324+
path[path.size() - 1].is<LocatorPathElt::ApplyArgToParam>()) {
13325+
auto &ctx = getASTContext();
13326+
13327+
auto *loc = getConstraintLocator(anchor, path);
13328+
auto argLoc =
13329+
loc->castLastElementTo<LocatorPathElt::ApplyArgToParam>();
13330+
13331+
auto numArgs = shape1->castTo<PackType>()->getNumElements();
13332+
auto numParams = shape2->castTo<PackType>()->getNumElements();
13333+
13334+
// Drops `ApplyArgToParam` and left with `ApplyArgument`.
13335+
path.pop_back();
13336+
13337+
auto *argListLoc = getConstraintLocator(anchor, path);
13338+
13339+
// Missing arguments.
13340+
if (numParams > numArgs) {
13341+
SmallVector<SynthesizedArg> synthesizedArgs;
13342+
for (unsigned i = 0, n = numParams - numArgs; i != n; ++i) {
13343+
auto eltTy = shape2->castTo<PackType>()->getElementType(i);
13344+
synthesizedArgs.push_back(SynthesizedArg{
13345+
argLoc.getParamIdx(), AnyFunctionType::Param(eltTy)});
13346+
}
13347+
13348+
return recordShapeFix(
13349+
AddMissingArguments::create(*this, synthesizedArgs, argListLoc),
13350+
/*impact=*/2 * synthesizedArgs.size());
13351+
} else {
13352+
auto argIdx = argLoc.getArgIdx() + numParams;
13353+
SmallVector<std::pair<unsigned, AnyFunctionType::Param>, 4>
13354+
extraneousArgs;
13355+
13356+
for (unsigned i = 0, n = numArgs - numParams; i != n; ++i) {
13357+
extraneousArgs.push_back(
13358+
{argIdx + i, AnyFunctionType::Param(ctx.TheEmptyTupleType)});
13359+
}
13360+
13361+
auto overload = findSelectedOverloadFor(getCalleeLocator(argListLoc));
13362+
if (!overload)
13363+
return SolutionKind::Error;
13364+
13365+
return recordShapeFix(
13366+
RemoveExtraneousArguments::create(
13367+
*this, overload->openedType->castTo<FunctionType>(),
13368+
extraneousArgs, argListLoc),
13369+
/*impact=*/2 * extraneousArgs.size());
13370+
}
13371+
}
13372+
}
13373+
1327913374
unsigned impact = 1;
1328013375
if (locator.endsWith<LocatorPathElt::AnyRequirement>())
1328113376
impact = assessRequirementFailureImpact(*this, shape1, locator);
1328213377

13283-
auto *fix = SkipSameShapeRequirement::create(*this, type1, type2,
13284-
getConstraintLocator(locator));
13285-
return recordFix(fix, impact) ? SolutionKind::Error : SolutionKind::Solved;
13378+
return recordShapeFix(
13379+
SkipSameShapeRequirement::create(*this, type1, type2,
13380+
getConstraintLocator(locator)),
13381+
impact);
1328613382
}
1328713383

1328813384
return SolutionKind::Error;

test/Constraints/pack-expansion-expressions.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -332,8 +332,8 @@ func test_pack_expansions_with_closures() {
332332
// rdar://107151854 - crash on invalid due to specialized pack expansion
333333
func test_pack_expansion_specialization() {
334334
struct Data<each T> {
335-
init(_: repeat each T) {} // expected-note 2 {{'init(_:)' declared here}}
336-
init(vals: repeat each T) {} // expected-note 2 {{'init(vals:)' declared here}}
335+
init(_: repeat each T) {} // expected-note 3 {{'init(_:)' declared here}}
336+
init(vals: repeat each T) {} // expected-note {{'init(vals:)' declared here}}
337337
}
338338

339339
_ = Data<Int>() // expected-error {{missing argument for parameter #1 in call}}

test/Constraints/variadic_generic_constraints.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,14 +58,14 @@ takesParallelSequences(t: Array<String>(), Set<Int>(), u: Array<Int>(), Set<Stri
5858
// Same-shape requirements
5959

6060
func zip<each T, each U>(t: repeat each T, u: repeat each U) -> (repeat (each T, each U)) {}
61+
// expected-note@-1 {{'zip(t:u:)' declared here}}
6162

6263
let _ = zip() // ok
6364
let _ = zip(t: 1, u: "hi") // ok
6465
let _ = zip(t: 1, 2, u: "hi", "hello") // ok
6566
let _ = zip(t: 1, 2, 3, u: "hi", "hello", "greetings") // ok
66-
67-
// FIXME: Bad diagnostic
68-
let _ = zip(t: 1, u: "hi", "hello", "greetings") // expected-error {{type of expression is ambiguous without more context}}
67+
let _ = zip(t: 1, u: "hi", "hello", "greetings") // expected-error {{extra arguments at positions #3, #4 in call}}
68+
// expected-error@-1 {{global function 'zip(t:u:)' requires the type packs 'Pack{Int}' and 'Pack{String, String, String}' have the same shape}}
6969

7070
func goodCallToZip<each T, each U>(t: repeat each T, u: repeat each U) where (repeat (each T, each U)): Any {
7171
_ = zip(t: repeat each t, u: repeat each u)

0 commit comments

Comments
 (0)