Skip to content

Commit 46f3ba6

Browse files
committed
[Effects] Ensure that we use the original parameter type when determining rethrows
Rethrows checking is based on the interface type of the parameter, with substitutions applied only when we need to figure out the thrown error type. Fixes a regression caused by my attempt at dealing with parameter packs in rethrows functions.
1 parent 5ed4411 commit 46f3ba6

File tree

2 files changed

+56
-18
lines changed

2 files changed

+56
-18
lines changed

lib/Sema/TypeCheckEffects.cpp

Lines changed: 49 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "swift/AST/ASTWalker.h"
2222
#include "swift/AST/DiagnosticsSema.h"
2323
#include "swift/AST/Effects.h"
24+
#include "swift/AST/GenericEnvironment.h"
2425
#include "swift/AST/Initializer.h"
2526
#include "swift/AST/ParameterList.h"
2627
#include "swift/AST/Pattern.h"
@@ -279,9 +280,10 @@ class AbstractFunction {
279280
TheClosure = closure;
280281
}
281282

282-
explicit AbstractFunction(ParamDecl *parameter)
283-
: TheKind(Kind::Parameter) {
283+
explicit AbstractFunction(ParamDecl *parameter, SubstitutionMap subs)
284+
: TheKind(Kind::Parameter), Substitutions(subs) {
284285
TheParameter = parameter;
286+
285287
}
286288

287289
Kind getKind() const { return TheKind; }
@@ -309,6 +311,24 @@ class AbstractFunction {
309311
llvm_unreachable("bad kind");
310312
}
311313

314+
/// Retrieve the interface type for a parameter based on an index into the
315+
/// substituted parameter type. This
316+
Type getOrigParamInterfaceType(unsigned substIndex) const {
317+
switch (getKind()) {
318+
case Kind::Opaque:
319+
case Kind::Closure:
320+
case Kind::Parameter:
321+
return getType()->castTo<AnyFunctionType>()->getParams()[substIndex]
322+
.getParameterType();
323+
324+
case Kind::Function: {
325+
auto params = getParameterList(static_cast<ValueDecl *>(getFunction()));
326+
auto origIndex = params->getOrigParamIndex(getSubstitutions(), substIndex);
327+
return params->get(origIndex)->getInterfaceType();
328+
}
329+
}
330+
}
331+
312332
bool isAutoClosure() const {
313333
if (getKind() == Kind::Closure)
314334
return isa<AutoClosureExpr>(getClosure());
@@ -386,7 +406,10 @@ class AbstractFunction {
386406
if (auto fn = dyn_cast<AbstractFunctionDecl>(decl)) {
387407
return AbstractFunction(fn, DRE->getDeclRef().getSubstitutions());
388408
} else if (auto param = dyn_cast<ParamDecl>(decl)) {
389-
return AbstractFunction(param);
409+
SubstitutionMap subs;
410+
if (auto genericEnv = param->getDeclContext()->getGenericEnvironmentOfContext())
411+
subs = genericEnv->getForwardingSubstitutionMap();
412+
return AbstractFunction(param, subs);
390413
}
391414

392415
// Closures.
@@ -813,6 +836,8 @@ class Classification {
813836
if (!thrownError || isNeverThrownError(thrownError))
814837
return result;
815838

839+
assert(!thrownError->hasError());
840+
816841
result.ThrowKind = conditionalKind;
817842
result.ThrowReason = reason;
818843
result.ThrownError = thrownError;
@@ -1187,15 +1212,15 @@ class ApplyClassifier {
11871212
return;
11881213
}
11891214

1190-
auto params = fnSubstType->getParams();
1191-
if (params.size() != args->size()) {
1215+
if (fnSubstType->getParams().size() != args->size()) {
11921216
result.merge(Classification::forInvalidCode());
11931217
return;
11941218
}
11951219

1196-
for (unsigned i = 0, e = params.size(); i < e; ++i) {
1220+
for (unsigned i = 0, e = args->size(); i < e; ++i) {
1221+
Type origParamType = fnRef.getOrigParamInterfaceType(i);
11971222
auto argClassification = classifyArgument(
1198-
args->getExpr(i), params[i].getParameterType(), kind);
1223+
args->getExpr(i), origParamType, fnRef.getSubstitutions(), kind);
11991224

12001225
// Rethrows is untyped, so adjust the thrown error type.
12011226
if (kind == EffectKind::Throws &&
@@ -1291,7 +1316,7 @@ class ApplyClassifier {
12911316
EffectKind kind) {
12921317
switch (fn.getKind()) {
12931318
case AbstractFunction::Opaque: {
1294-
return classifyArgumentByType(fn.getType(),
1319+
return classifyArgumentByType(fn.getType(), fn.getSubstitutions(),
12951320
ConditionalEffectKind::Always, reason,
12961321
kind);
12971322
}
@@ -1330,8 +1355,8 @@ class ApplyClassifier {
13301355
else // otherwise, it throws unconditionally.
13311356
conditional = ConditionalEffectKind::Always;
13321357

1333-
return classifyArgumentByType(param->getTypeInContext(),
1334-
conditional, reason, kind);
1358+
return classifyArgumentByType(
1359+
param->getInterfaceType(), subs, conditional, reason, kind);
13351360
}
13361361

13371362
bool isLocallyDefinedInPolymorphicEffectDeclContext(DeclContext *DC,
@@ -1660,7 +1685,8 @@ class ApplyClassifier {
16601685
}
16611686

16621687
/// Classify an argument being passed to a rethrows/reasync function.
1663-
Classification classifyArgument(Expr *arg, Type paramType, EffectKind kind) {
1688+
Classification classifyArgument(
1689+
Expr *arg, Type paramType, SubstitutionMap subs, EffectKind kind) {
16641690
arg = arg->getValueProvidingExpr();
16651691

16661692
if (auto *defaultArg = dyn_cast<DefaultArgumentExpr>(arg)) {
@@ -1673,7 +1699,7 @@ class ApplyClassifier {
16731699
}
16741700
}
16751701

1676-
return classifyArgumentByType(arg->getType(),
1702+
return classifyArgumentByType(arg->getType(), subs,
16771703
ConditionalEffectKind::Always,
16781704
PotentialEffectReason::forDefaultClosure(),
16791705
kind);
@@ -1698,7 +1724,7 @@ class ApplyClassifier {
16981724
// various tuple operations.
16991725
if (auto paramTupleType = dyn_cast<TupleType>(paramType.getPointer())) {
17001726
if (auto tuple = dyn_cast<TupleExpr>(arg)) {
1701-
return classifyTupleArgument(tuple, paramTupleType, kind);
1727+
return classifyTupleArgument(tuple, paramTupleType, subs, kind);
17021728
}
17031729

17041730
if (paramTupleType->getNumElements() != 1) {
@@ -1707,6 +1733,7 @@ class ApplyClassifier {
17071733
// parameter type included a throwing function type.
17081734
return classifyArgumentByType(
17091735
paramType,
1736+
subs,
17101737
ConditionalEffectKind::Always,
17111738
PotentialEffectReason::forClosure(arg),
17121739
kind);
@@ -1751,6 +1778,7 @@ class ApplyClassifier {
17511778
/// Classify an argument to a rethrows/reasync function that's a tuple literal.
17521779
Classification classifyTupleArgument(TupleExpr *tuple,
17531780
TupleType *paramTupleType,
1781+
SubstitutionMap subs,
17541782
EffectKind kind) {
17551783
if (paramTupleType->getNumElements() != tuple->getNumElements())
17561784
return Classification::forInvalidCode();
@@ -1759,7 +1787,7 @@ class ApplyClassifier {
17591787
for (unsigned i : indices(tuple->getElements())) {
17601788
result.merge(classifyArgument(tuple->getElement(i),
17611789
paramTupleType->getElementType(i),
1762-
kind));
1790+
subs, kind));
17631791
}
17641792
return result;
17651793
}
@@ -1768,7 +1796,8 @@ class ApplyClassifier {
17681796
/// a throws/async function in a way that is permitted to cause a
17691797
/// rethrows/reasync function to throw/async.
17701798
static Classification
1771-
classifyArgumentByType(Type paramType, ConditionalEffectKind conditional,
1799+
classifyArgumentByType(Type paramType, SubstitutionMap subs,
1800+
ConditionalEffectKind conditional,
17721801
PotentialEffectReason reason, EffectKind kind) {
17731802
if (!paramType || paramType->hasError())
17741803
return Classification::forInvalidCode();
@@ -1786,8 +1815,10 @@ class ApplyClassifier {
17861815
return Classification();
17871816

17881817
case EffectKind::Throws:
1789-
if (auto thrownError = fnType->getEffectiveThrownErrorType())
1790-
return Classification::forThrows(*thrownError, conditional, reason);
1818+
if (auto thrownError = fnType->getEffectiveThrownErrorType()) {
1819+
return Classification::forThrows(
1820+
thrownError->subst(subs), conditional, reason);
1821+
}
17911822

17921823
return Classification();
17931824
}
@@ -1799,7 +1830,7 @@ class ApplyClassifier {
17991830

18001831
for (auto eltType : tuple->getElementTypes()) {
18011832
result.merge(
1802-
classifyArgumentByType(eltType, conditional, reason, kind));
1833+
classifyArgumentByType(eltType, subs, conditional, reason, kind));
18031834
}
18041835

18051836
return result;

test/decl/func/rethrows.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -681,3 +681,10 @@ func testRethrowsWithParameterPacks() throws {
681681
// expected-error@-1{{call can throw but is not marked with 'try'}}
682682
// expected-note@-2{{call is to 'rethrows' function, but argument function can throw}}
683683
}
684+
685+
// Rethrows checking with the original parameter type providing the cues.
686+
func takesArbitraryAndRethrows<T>(_ value: T, body: () throws -> Void) rethrows { }
687+
688+
func testArbitraryAndRethrows() {
689+
takesArbitraryAndRethrows(throwingFunc) { }
690+
}

0 commit comments

Comments
 (0)