Skip to content

Commit dbaa619

Browse files
committed
AST: Fix accessibility checking in opaque type archetype substitution logic
We were failing to replace opaque types with their underlying type upon encountering an internal type from the current module. This could happen when the internal type appeared in generic substitutions, for example when calling a protocol extension method. Fixes <rdar://problem/60951353>.
1 parent 66ea6e6 commit dbaa619

File tree

5 files changed

+109
-30
lines changed

5 files changed

+109
-30
lines changed

lib/AST/Type.cpp

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2932,13 +2932,13 @@ substOpaqueTypesWithUnderlyingTypes(Type ty, const DeclContext *inContext,
29322932
static bool canSubstituteTypeInto(Type ty, const DeclContext *dc,
29332933
OpaqueSubstitutionKind kind,
29342934
bool isContextWholeModule) {
2935-
ValueDecl *nominal = ty->getAnyNominal();
2936-
if (!nominal) {
2935+
TypeDecl *typeDecl = ty->getAnyNominal();
2936+
if (!typeDecl) {
29372937
// We also need to check that the opaque type descriptor is accessible.
29382938
if (auto opaqueTy = ty->getAs<OpaqueTypeArchetypeType>())
2939-
nominal = opaqueTy->getDecl();
2939+
typeDecl = opaqueTy->getDecl();
29402940
}
2941-
if (!nominal) {
2941+
if (!typeDecl) {
29422942
return true;
29432943
}
29442944

@@ -2956,14 +2956,18 @@ static bool canSubstituteTypeInto(Type ty, const DeclContext *dc,
29562956

29572957
// In the same file any visibility is okay.
29582958
if (!dc->isModuleContext() &&
2959-
nominal->getDeclContext()->getParentSourceFile() ==
2959+
typeDecl->getDeclContext()->getParentSourceFile() ==
29602960
dc->getParentSourceFile())
29612961
return true;
2962-
return nominal->getEffectiveAccess() > AccessLevel::FilePrivate;
2962+
2963+
return typeDecl->getEffectiveAccess() > AccessLevel::FilePrivate;
29632964

29642965
case OpaqueSubstitutionKind::SubstituteNonResilientModule:
29652966
// Can't access types that are not public from a different module.
2966-
return nominal->getEffectiveAccess() > AccessLevel::Internal;
2967+
if (dc->getParentModule() == typeDecl->getDeclContext()->getParentModule())
2968+
return true;
2969+
2970+
return typeDecl->getEffectiveAccess() > AccessLevel::Internal;
29672971
}
29682972
}
29692973

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
public protocol View {}
2+
3+
struct InternalView : View {}
4+
struct InternalGenericView<T> : View {}
5+
6+
public struct PublicView : View {}
7+
public struct PublicGenericView<T> : View {}
8+
9+
extension View {
10+
public func passThrough() -> some View {
11+
return self
12+
}
13+
14+
public func wrapWithInternalView() -> some View {
15+
return InternalView()
16+
}
17+
18+
public func wrapWithInternalGenericView() -> some View {
19+
return InternalGenericView<Self>()
20+
}
21+
22+
public func wrapWithPublicView() -> some View {
23+
return PublicView()
24+
}
25+
26+
public func wrapWithPublicGenericView() -> some View {
27+
return PublicGenericView<Self>()
28+
}
29+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend -disable-availability-checking -emit-module %S/Inputs/opaque_result_type_fragile_other.swift -emit-module-path %t/opaque_result_type_fragile_other.swiftmodule
3+
// RUN: %target-swift-frontend -disable-availability-checking -emit-silgen -I%t %s | %FileCheck %s
4+
5+
import opaque_result_type_fragile_other
6+
7+
struct InternalView: View {}
8+
public struct PublicView: View {}
9+
10+
public func testInternalView() {
11+
let v = InternalView()
12+
13+
// CHECK: function_ref @$s32opaque_result_type_fragile_other4ViewPAAE11passThroughQryF : $@convention(method) <τ_0_0 where τ_0_0 : View> (@in_guaranteed τ_0_0) -> @out τ_0_0
14+
_ = v.passThrough()
15+
16+
// CHECK: function_ref @$s32opaque_result_type_fragile_other4ViewPAAE016wrapWithInternalF0QryF : $@convention(method) <τ_0_0 where τ_0_0 : View> (@in_guaranteed τ_0_0) -> @out @_opaqueReturnTypeOf("$s32opaque_result_type_fragile_other4ViewPAAE016wrapWithInternalF0QryF", 0) 🦸<τ_0_0>
17+
_ = v.wrapWithInternalView()
18+
19+
// CHECK: function_ref @$s32opaque_result_type_fragile_other4ViewPAAE023wrapWithInternalGenericF0QryF : $@convention(method) <τ_0_0 where τ_0_0 : View> (@in_guaranteed τ_0_0) -> @out @_opaqueReturnTypeOf("$s32opaque_result_type_fragile_other4ViewPAAE023wrapWithInternalGenericF0QryF", 0) 🦸<τ_0_0>
20+
_ = v.wrapWithInternalGenericView()
21+
22+
// CHECK: function_ref @$s32opaque_result_type_fragile_other4ViewPAAE014wrapWithPublicF0QryF : $@convention(method) <τ_0_0 where τ_0_0 : View> (@in_guaranteed τ_0_0) -> @out PublicView
23+
_ = v.wrapWithPublicView()
24+
25+
//CHECK: function_ref @$s32opaque_result_type_fragile_other4ViewPAAE021wrapWithPublicGenericF0QryF : $@convention(method) <τ_0_0 where τ_0_0 : View> (@in_guaranteed τ_0_0) -> @out PublicGenericView<τ_0_0>
26+
_ = v.wrapWithPublicGenericView()
27+
}
28+
29+
public func testPublicView() {
30+
let v = PublicView()
31+
32+
// CHECK: function_ref @$s32opaque_result_type_fragile_other4ViewPAAE11passThroughQryF : $@convention(method) <τ_0_0 where τ_0_0 : View> (@in_guaranteed τ_0_0) -> @out τ_0_0
33+
_ = v.passThrough()
34+
35+
// CHECK: function_ref @$s32opaque_result_type_fragile_other4ViewPAAE016wrapWithInternalF0QryF : $@convention(method) <τ_0_0 where τ_0_0 : View> (@in_guaranteed τ_0_0) -> @out @_opaqueReturnTypeOf("$s32opaque_result_type_fragile_other4ViewPAAE016wrapWithInternalF0QryF", 0) 🦸<τ_0_0>
36+
_ = v.wrapWithInternalView()
37+
38+
// CHECK: function_ref @$s32opaque_result_type_fragile_other4ViewPAAE023wrapWithInternalGenericF0QryF : $@convention(method) <τ_0_0 where τ_0_0 : View> (@in_guaranteed τ_0_0) -> @out @_opaqueReturnTypeOf("$s32opaque_result_type_fragile_other4ViewPAAE023wrapWithInternalGenericF0QryF", 0) 🦸<τ_0_0>
39+
_ = v.wrapWithInternalGenericView()
40+
41+
// CHECK: function_ref @$s32opaque_result_type_fragile_other4ViewPAAE014wrapWithPublicF0QryF : $@convention(method) <τ_0_0 where τ_0_0 : View> (@in_guaranteed τ_0_0) -> @out PublicView
42+
_ = v.wrapWithPublicView()
43+
44+
//CHECK: function_ref @$s32opaque_result_type_fragile_other4ViewPAAE021wrapWithPublicGenericF0QryF : $@convention(method) <τ_0_0 where τ_0_0 : View> (@in_guaranteed τ_0_0) -> @out PublicGenericView<τ_0_0>
45+
_ = v.wrapWithPublicGenericView()
46+
}

test/SILOptimizer/cast_folding.swift

Lines changed: 2 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
1-
// RUN: %target-swift-frontend -disable-availability-checking -O -emit-sil %s | %FileCheck %s
2-
// RUN: %target-swift-frontend -disable-availability-checking -Onone -emit-sil %s | %FileCheck %s --check-prefix=MANDATORY
3-
// RUN: %target-swift-frontend -Xllvm -sil-disable-pass=FunctionSignatureOpts -Xllvm -sil-disable-pass=PerfInliner -enable-ownership-stripping-after-serialization -disable-availability-checking -O -emit-sil %s | %FileCheck %s
4-
// RUN: %target-swift-frontend -enable-ownership-stripping-after-serialization -disable-availability-checking -Onone -emit-sil %s | %FileCheck %s --check-prefix=MANDATORY
1+
// RUN: %target-swift-frontend -O -emit-sil %s | %FileCheck %s
2+
// RUN: %target-swift-frontend -Xllvm -sil-disable-pass=FunctionSignatureOpts -Xllvm -sil-disable-pass=PerfInliner -enable-ownership-stripping-after-serialization -O -emit-sil %s | %FileCheck %s
53

64
// We want to check two things here:
75
// - Correctness
@@ -1069,25 +1067,6 @@ public func testCastToPForOptionalFailure() -> Bool {
10691067
return testCastToPForOptional(t)
10701068
}
10711069

1072-
struct Underlying : P {
1073-
}
1074-
1075-
public func returnOpaque() -> some P {
1076-
return Underlying()
1077-
}
1078-
1079-
// MANDATORY-LABEL: sil{{.*}} @$s12cast_folding23testCastOpaqueArchetypeyyF
1080-
// MANDATORY: [[O:%.*]] = alloc_stack $@_opaqueReturnTypeOf("$s12cast_folding12returnOpaqueQryF", 0)
1081-
// MANDATORY: [[F:%.*]] = function_ref @$s12cast_folding12returnOpaqueQryF
1082-
// MANDATORY: apply [[F]]([[O]])
1083-
// MANDATORY: [[U:%.*]] = alloc_stack $Underlying
1084-
// MANDATORY: unconditional_checked_cast_addr @_opaqueReturnTypeOf{{.*}}in [[O]] : $*@_opaqueReturnTypeOf{{.*}}to Underlying in [[U]] : $*Underlying
1085-
// MANDATORY: load [[U]] : $*Underlying
1086-
@inlinable
1087-
public func testCastOpaqueArchetype() {
1088-
let o = returnOpaque() as! Underlying
1089-
}
1090-
10911070
print("test0=\(test0())")
10921071

10931072
print("test1=\(test1())")
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// RUN: %target-swift-frontend -enable-library-evolution -disable-availability-checking -O -emit-sil %s
2+
// RUN: %target-swift-frontend -enable-library-evolution -disable-availability-checking -Onone -emit-sil %s | %FileCheck %s
3+
4+
public protocol P {}
5+
6+
public struct Underlying : P {
7+
}
8+
9+
public func returnOpaque() -> some P {
10+
return Underlying()
11+
}
12+
13+
// CHECK-LABEL: sil [serialized] @$s19cast_folding_opaque23testCastOpaqueArchetypeAA10UnderlyingVyF
14+
// CHECK: [[O:%.*]] = alloc_stack $@_opaqueReturnTypeOf("$s19cast_folding_opaque12returnOpaqueQryF", 0)
15+
// CHECK: [[F:%.*]] = function_ref @$s19cast_folding_opaque12returnOpaqueQryF
16+
// CHECK: apply [[F]]([[O]])
17+
// CHECK: unconditional_checked_cast_addr @_opaqueReturnTypeOf{{.*}}in [[O]] : $*@_opaqueReturnTypeOf{{.*}}to Underlying in %0 : $*Underlying
18+
@inlinable
19+
public func testCastOpaqueArchetype() -> Underlying {
20+
return returnOpaque() as! Underlying
21+
}

0 commit comments

Comments
 (0)