Skip to content

Commit e26034b

Browse files
committed
Sema: New opaque return type circularity check that doesn't trigger lazy type checking of bodies
Commit b70f8a8 introduced a usage of ReplaceOpaqueTypesWithUnderlyingTypes in Sema. Previously this was only called from SILGen. The problem was that ReplaceOpaqueTypesWithUnderlyingTypes would call getUniqueUnderlyingTypeSubstitutions(), which triggers a request to type check the body of the referenced function. While this didn't result in unnecessary type checking work, because UniqueUnderlyingTypeSubstitutionsRequest::evaluate() would skip bodies in secondary files, it did change declaration checking order. The specific issue we saw was a bad interaction with associated type inference and unqualified lookup in a WMO build, and a complete test case is hard to reduce here. However, no behavior change is intended with this change, modulo bugs elsewhere related to declaration checking order, so I feel OK not adding a test case. I'll hopefully address the unqualified lookup issue exposed in the radar soon; it has a reproducer independent of opaque return types. Fixes rdar://157329046.
1 parent 3dcadf8 commit e26034b

File tree

5 files changed

+76
-72
lines changed

5 files changed

+76
-72
lines changed

lib/Sema/MiscDiagnostics.cpp

Lines changed: 0 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
#include "swift/AST/DiagnosticsSema.h"
2828
#include "swift/AST/ExistentialLayout.h"
2929
#include "swift/AST/Expr.h"
30-
#include "swift/AST/InFlightSubstitution.h"
3130
#include "swift/AST/NameLookup.h"
3231
#include "swift/AST/NameLookupRequests.h"
3332
#include "swift/AST/Pattern.h"
@@ -3666,50 +3665,6 @@ class OpaqueUnderlyingTypeChecker : public ASTWalker {
36663665
}
36673666
}
36683667

3669-
bool isSelfReferencing(const Candidate &candidate) {
3670-
auto substitutions = std::get<1>(candidate);
3671-
3672-
// The underlying type can't be defined recursively
3673-
// in terms of the opaque type itself.
3674-
for (auto genericParam : OpaqueDecl->getOpaqueGenericParams()) {
3675-
auto underlyingType = Type(genericParam).subst(substitutions);
3676-
3677-
// Look through underlying types of other opaque archetypes known to
3678-
// us. This is not something the type checker is allowed to do in
3679-
// general, since the intent is that the underlying type is completely
3680-
// hidden from view at the type system level. However, here we're
3681-
// trying to catch recursive underlying types before we proceed to
3682-
// SIL, so we specifically want to erase opaque archetypes just
3683-
// for the purpose of this check.
3684-
ReplaceOpaqueTypesWithUnderlyingTypes replacer(
3685-
OpaqueDecl->getDeclContext(),
3686-
ResilienceExpansion::Maximal,
3687-
/*isWholeModuleContext=*/false);
3688-
InFlightSubstitution IFS(replacer, replacer,
3689-
SubstFlags::SubstituteOpaqueArchetypes |
3690-
SubstFlags::PreservePackExpansionLevel);
3691-
auto simplifiedUnderlyingType = underlyingType.subst(IFS);
3692-
3693-
auto isSelfReferencing =
3694-
(IFS.wasLimitReached() ||
3695-
simplifiedUnderlyingType.findIf([&](Type t) -> bool {
3696-
if (auto *other = t->getAs<OpaqueTypeArchetypeType>()) {
3697-
return other->getDecl() == OpaqueDecl;
3698-
}
3699-
return false;
3700-
}));
3701-
3702-
if (isSelfReferencing) {
3703-
Ctx.Diags.diagnose(std::get<0>(candidate)->getLoc(),
3704-
diag::opaque_type_self_referential_underlying_type,
3705-
underlyingType);
3706-
return true;
3707-
}
3708-
}
3709-
3710-
return false;
3711-
}
3712-
37133668
// A single unique underlying substitution.
37143669
void finalizeUnique(const Candidate &candidate) {
37153670
// If we have one successful candidate, then save it as the underlying
@@ -3808,11 +3763,6 @@ class OpaqueUnderlyingTypeChecker : public ASTWalker {
38083763
auto candidate =
38093764
std::make_tuple(underlyingToOpaque->getSubExpr(), subMap, isUnique);
38103765

3811-
if (isSelfReferencing(candidate)) {
3812-
HasInvalidReturn = true;
3813-
return Action::Stop();
3814-
}
3815-
38163766
if (subMap.getRecursiveProperties().hasDynamicSelf()) {
38173767
Ctx.Diags.diagnose(E->getLoc(),
38183768
diag::opaque_type_cannot_contain_dynamic_self);

lib/Sema/TypeCheckGeneric.cpp

Lines changed: 48 additions & 0 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/ExistentialLayout.h"
24+
#include "swift/AST/InFlightSubstitution.h"
2425
#include "swift/AST/GenericEnvironment.h"
2526
#include "swift/AST/ParameterList.h"
2627
#include "swift/AST/ProtocolConformance.h"
@@ -267,6 +268,53 @@ OpaqueResultTypeRequest::evaluate(Evaluator &evaluator,
267268
return opaqueDecl;
268269
}
269270

271+
void TypeChecker::checkCircularOpaqueReturnTypeDecl(OpaqueTypeDecl *opaqueDecl) {
272+
auto optSubs = opaqueDecl->getUniqueUnderlyingTypeSubstitutions(
273+
/*typeCheckFunctionBodies=*/false);
274+
if (!optSubs)
275+
return;
276+
277+
auto substitutions = *optSubs;
278+
279+
// The underlying type can't be defined recursively
280+
// in terms of the opaque type itself.
281+
for (auto genericParam : opaqueDecl->getOpaqueGenericParams()) {
282+
auto underlyingType = Type(genericParam).subst(substitutions);
283+
284+
// Look through underlying types of other opaque archetypes known to
285+
// us. This is not something the type checker is allowed to do in
286+
// general, since the intent is that the underlying type is completely
287+
// hidden from view at the type system level. However, here we're
288+
// trying to catch recursive underlying types before we proceed to
289+
// SIL, so we specifically want to erase opaque archetypes just
290+
// for the purpose of this check.
291+
ReplaceOpaqueTypesWithUnderlyingTypes replacer(
292+
opaqueDecl->getDeclContext(),
293+
ResilienceExpansion::Maximal,
294+
/*isWholeModuleContext=*/false,
295+
/*typeCheckFunctionBodies=*/false);
296+
InFlightSubstitution IFS(replacer, replacer,
297+
SubstFlags::SubstituteOpaqueArchetypes |
298+
SubstFlags::PreservePackExpansionLevel);
299+
auto simplifiedUnderlyingType = underlyingType.subst(IFS);
300+
301+
auto isSelfReferencing =
302+
(IFS.wasLimitReached() ||
303+
simplifiedUnderlyingType.findIf([&](Type t) -> bool {
304+
if (auto *other = t->getAs<OpaqueTypeArchetypeType>()) {
305+
return other->getDecl() == opaqueDecl;
306+
}
307+
return false;
308+
}));
309+
310+
if (isSelfReferencing) {
311+
opaqueDecl->getNamingDecl()->diagnose(
312+
diag::opaque_type_self_referential_underlying_type,
313+
underlyingType);
314+
}
315+
}
316+
}
317+
270318
static bool checkProtocolSelfRequirementsImpl(
271319
ASTContext &ctx, ProtocolDecl *proto, ValueDecl *decl,
272320
GenericSignature originalSig,

lib/Sema/TypeChecker.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,10 @@ TypeCheckPrimaryFileRequest::evaluate(Evaluator &eval, SourceFile *SF) const {
326326
}
327327
}
328328
SF->typeCheckDelayedFunctions();
329+
330+
for (auto *opaqueDecl : SF->getOpaqueReturnTypeDecls()) {
331+
TypeChecker::checkCircularOpaqueReturnTypeDecl(opaqueDecl);
332+
}
329333
}
330334

331335
// If region-based isolation is enabled, we diagnose unnecessary

lib/Sema/TypeChecker.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -506,6 +506,8 @@ void typeCheckTopLevelCodeDecl(TopLevelCodeDecl *TLCD);
506506

507507
void typeCheckDecl(Decl *D);
508508

509+
void checkCircularOpaqueReturnTypeDecl(OpaqueTypeDecl *opaqueDecl);
510+
509511
void addImplicitDynamicAttribute(Decl *D);
510512
void checkDeclAttributes(Decl *D);
511513
void checkDeclABIAttribute(Decl *apiDecl, ABIAttr *abiAttr);

test/Generics/infinite_opaque_result_type.swift

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,25 +5,25 @@ func concrete1() -> some Any {
55
return concrete1()
66
}
77

8-
func concrete2() -> some Any {
9-
return [concrete2()] // expected-error {{function opaque return type was inferred as '[some Any]', which defines the opaque type in terms of itself}}
8+
func concrete2() -> some Any { // expected-error {{function opaque return type was inferred as '[some Any]', which defines the opaque type in terms of itself}}
9+
return [concrete2()]
1010
}
1111

1212

13-
func concrete1a() -> some Any {
14-
return concrete1b() // expected-error {{function opaque return type was inferred as 'some Any', which defines the opaque type in terms of itself}}
13+
func concrete1a() -> some Any { // expected-error {{function opaque return type was inferred as 'some Any', which defines the opaque type in terms of itself}}
14+
return concrete1b()
1515
}
1616

17-
func concrete1b() -> some Any {
17+
func concrete1b() -> some Any { // expected-error {{function opaque return type was inferred as 'some Any', which defines the opaque type in terms of itself}}
1818
return concrete1a()
1919
}
2020

2121

22-
func concrete2a() -> some Any {
23-
return [concrete2b()] // expected-error {{function opaque return type was inferred as '[some Any]', which defines the opaque type in terms of itself}}
22+
func concrete2a() -> some Any { // expected-error {{function opaque return type was inferred as '[some Any]', which defines the opaque type in terms of itself}}
23+
return [concrete2b()]
2424
}
2525

26-
func concrete2b() -> some Any {
26+
func concrete2b() -> some Any { // expected-error {{function opaque return type was inferred as '[some Any]', which defines the opaque type in terms of itself}}
2727
return [concrete2a()]
2828
}
2929

@@ -33,41 +33,41 @@ func generic1<T>(_ t: T) -> some Any {
3333
return generic1(t)
3434
}
3535

36-
func generic2<T>(_ t: T) -> some Any {
37-
return [generic2(t)] // expected-error {{function opaque return type was inferred as '[some Any]', which defines the opaque type in terms of itself}}
36+
func generic2<T>(_ t: T) -> some Any { // expected-error {{function opaque return type was inferred as '[some Any]', which defines the opaque type in terms of itself}}
37+
return [generic2(t)]
3838
}
3939

4040

41-
func generic1a<T>(_ t: T) -> some Any {
42-
return generic1b(t) // expected-error {{function opaque return type was inferred as 'some Any', which defines the opaque type in terms of itself}}
41+
func generic1a<T>(_ t: T) -> some Any { // expected-error {{function opaque return type was inferred as 'some Any', which defines the opaque type in terms of itself}}
42+
return generic1b(t)
4343
}
4444

45-
func generic1b<T>(_ t: T) -> some Any {
45+
func generic1b<T>(_ t: T) -> some Any { // expected-error {{function opaque return type was inferred as 'some Any', which defines the opaque type in terms of itself}}
4646
return generic1a(t)
4747
}
4848

4949

50-
func generic2a<T>(_ t: T) -> some Any {
51-
return [generic2b(t)] // expected-error {{function opaque return type was inferred as '[some Any]', which defines the opaque type in terms of itself}}
50+
func generic2a<T>(_ t: T) -> some Any { // expected-error {{function opaque return type was inferred as '[some Any]', which defines the opaque type in terms of itself}}
51+
return [generic2b(t)]
5252
}
5353

54-
func generic2b<T>(_ t: T) -> some Any {
54+
func generic2b<T>(_ t: T) -> some Any { // expected-error {{function opaque return type was inferred as '[some Any]', which defines the opaque type in terms of itself}}
5555
return [generic2a(t)]
5656
}
5757

5858

59-
func generic3a<T>(_ t: T) -> some Any {
60-
return [generic3b(t)] // expected-error {{function opaque return type was inferred as '[some Any]', which defines the opaque type in terms of itself}}
59+
func generic3a<T>(_ t: T) -> some Any { // expected-error {{function opaque return type was inferred as '[some Any]', which defines the opaque type in terms of itself}}
60+
return [generic3b(t)]
6161
}
6262

63-
func generic3b<T>(_ t: T) -> some Any {
63+
func generic3b<T>(_ t: T) -> some Any { // expected-error {{function opaque return type was inferred as '[some Any]', which defines the opaque type in terms of itself}}
6464
return [generic3a([t])]
6565
}
6666

67-
func very_wide1() -> some Any {
68-
return (very_wide2(), very_wide2()) // expected-error {{function opaque return type was inferred as '(some Any, some Any)', which defines the opaque type in terms of itself}}
67+
func very_wide1() -> some Any { // expected-error {{function opaque return type was inferred as '(some Any, some Any)', which defines the opaque type in terms of itself}}
68+
return (very_wide2(), very_wide2())
6969
}
7070

71-
func very_wide2() -> some Any {
71+
func very_wide2() -> some Any { // expected-error {{function opaque return type was inferred as '(some Any, some Any)', which defines the opaque type in terms of itself}}
7272
return (very_wide1(), very_wide1())
7373
}

0 commit comments

Comments
 (0)