Skip to content

Commit e9ff8ad

Browse files
committed
Sema: Allow closure parameter lists to reference opaque parameter declarations
A function declaration cannot have an opaque parameter type appearing in consuming position: func f(_: (some P) -> ()) {} However, we should skip this check for a closure, because if the closure's parameter list references an opaque parameter declaration, it means something else: namely, the inferred type of the closure refers to an opaque parameter from an outer scope. That's allowed. This unnecessary prohibition has been there ever since the check was added, but only for multi-statement closures, so nobody seemed to notice. When swiftlang#76473 made it so we always call TypeChecker::checkParameterList(), this exposed the problem in a single-expression closure in an existing project. Fixes rdar://139237671.
1 parent 8f66bf1 commit e9ff8ad

File tree

2 files changed

+47
-30
lines changed

2 files changed

+47
-30
lines changed

lib/Sema/TypeCheckDeclPrimary.cpp

Lines changed: 32 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -4287,48 +4287,50 @@ void TypeChecker::checkParameterList(ParameterList *params,
42874287
}
42884288

42894289
// Opaque types cannot occur in parameter position.
4290-
Type interfaceType = param->getInterfaceType();
4291-
if (interfaceType->hasTypeParameter()) {
4292-
interfaceType.findIf([&](Type type) {
4293-
if (auto fnType = type->getAs<FunctionType>()) {
4294-
for (auto innerParam : fnType->getParams()) {
4295-
auto paramType = innerParam.getPlainType();
4296-
if (!paramType->hasTypeParameter())
4297-
continue;
4298-
4299-
bool hadError = paramType.findIf([&](Type innerType) {
4300-
auto genericParam = innerType->getAs<GenericTypeParamType>();
4301-
if (!genericParam)
4302-
return false;
4303-
4304-
auto genericParamDecl = genericParam->getOpaqueDecl();
4305-
if (!genericParamDecl)
4306-
return false;
4307-
4308-
param->diagnose(
4309-
diag::opaque_type_in_parameter, true, interfaceType);
4310-
return true;
4311-
});
4290+
if (!isa<ClosureExpr>(owner)) {
4291+
Type interfaceType = param->getInterfaceType();
4292+
if (interfaceType->hasTypeParameter()) {
4293+
interfaceType.findIf([&](Type type) {
4294+
if (auto fnType = type->getAs<FunctionType>()) {
4295+
for (auto innerParam : fnType->getParams()) {
4296+
auto paramType = innerParam.getPlainType();
4297+
if (!paramType->hasTypeParameter())
4298+
continue;
4299+
4300+
bool hadError = paramType.findIf([&](Type innerType) {
4301+
auto genericParam = innerType->getAs<GenericTypeParamType>();
4302+
if (!genericParam)
4303+
return false;
4304+
4305+
auto genericParamDecl = genericParam->getOpaqueDecl();
4306+
if (!genericParamDecl)
4307+
return false;
4308+
4309+
param->diagnose(
4310+
diag::opaque_type_in_parameter, true, interfaceType);
4311+
return true;
4312+
});
4313+
4314+
if (hadError)
4315+
return true;
4316+
}
43124317

4313-
if (hadError)
4314-
return true;
4318+
return false;
43154319
}
43164320

43174321
return false;
4318-
}
4319-
4320-
return false;
4321-
});
4322+
});
4323+
}
43224324
}
43234325

43244326
if (param->hasAttachedPropertyWrapper())
43254327
(void) param->getPropertyWrapperInitializerInfo();
43264328

4327-
auto *SF = param->getDeclContext()->getParentSourceFile();
43284329
if (!param->isInvalid()) {
4330+
auto *SF = owner->getParentSourceFile();
43294331
param->visitAuxiliaryDecls([&](VarDecl *auxiliaryDecl) {
43304332
if (!isa<ParamDecl>(auxiliaryDecl))
4331-
DeclChecker(param->getASTContext(), SF).visitBoundVariable(auxiliaryDecl);
4333+
DeclChecker(SF->getASTContext(), SF).visitBoundVariable(auxiliaryDecl);
43324334
});
43334335
}
43344336

test/type/opaque_parameters.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,3 +131,18 @@ struct I61387_1 {
131131
}
132132
}
133133
}
134+
135+
// However, it's fine if the inferred type of a closure refers to opaque parameters from the outer scope.
136+
public func combinator<T>(_: T, _: ((T) -> ()) -> ()) {}
137+
138+
public func closureWithOpaqueParameterInConsumingPosition(p: some Any) {
139+
// Single-expression
140+
combinator(p) { $0(p) }
141+
142+
// Multi-expression
143+
combinator(p) { fn in
144+
let result: () = fn(p)
145+
return result
146+
}
147+
}
148+

0 commit comments

Comments
 (0)