Skip to content

IRGen: We can't look through opaque archetypes if the underlying type contains a private type #27609

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 30 additions & 10 deletions lib/IRGen/MetadataRequest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -512,15 +512,28 @@ CanType IRGenModule::getRuntimeReifiedType(CanType type) {
}));
}

static bool containsPrivateType(CanType ty) {
return ty.findIf([](Type t) -> bool {
if (auto *nominal = t->getAnyNominal()) {
if (nominal->getEffectiveAccess() <= AccessLevel::FilePrivate)
return true;
}
return false;
});
}

CanType IRGenModule::substOpaqueTypesWithUnderlyingTypes(CanType type) {
// Substitute away opaque types whose underlying types we're allowed to
// assume are constant.
if (type->hasOpaqueArchetype()) {
ReplaceOpaqueTypesWithUnderlyingTypes replacer(getSwiftModule(),
ResilienceExpansion::Maximal);
type = type.subst(replacer, replacer,
SubstFlags::SubstituteOpaqueArchetypes)
->getCanonicalType();
auto underlyingTy =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since you have an IRGenModule here, I think you should instead use getTypeInfo(type).isABIAccessible()

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isABIAccessible does not give the right answer for private non resilient types:

 /// Whether this type is known to be ABI-accessible, i.e. whether it's        
  /// actually possible to do ABI operations on it from this current SILModule. 
  /// See SILModule::isTypeABIAccessible.                                       
  ///                                                                           
  /// All fixed-size types are currently ABI-accessible, although this would    
  /// not be difficult to change (e.g. if we had an archetype size constraint   
  /// that didn't say anything about triviality).                               
  IsABIAccessible_t isABIAccessible() const {    

The failure occurs when we build the associated type witness. The associated type resolves to an opaque type and the underlying type contains the private type.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, good point. In that case, I think it's still worth extracting a new predicate since it might come up elsewhere.

Is 'private' access enough though? It seems if the declaration is internal, you'll run into the same problem.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right internal access is problematic across modules (the problematic case can happen with non-inlineable functions from non resilient modules).

I will fix the code in the ReplaceOpaqueTypesWithUnderlyingTypes utility instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New PR: #27666

type.subst(replacer, replacer, SubstFlags::SubstituteOpaqueArchetypes)
->getCanonicalType();
// The underlying type could contain a private type from a different TU.
if (!containsPrivateType(underlyingTy))
return underlyingTy;
}

return type;
Expand All @@ -533,8 +546,12 @@ SILType IRGenModule::substOpaqueTypesWithUnderlyingTypes(
if (type.getASTType()->hasOpaqueArchetype()) {
ReplaceOpaqueTypesWithUnderlyingTypes replacer(getSwiftModule(),
ResilienceExpansion::Maximal);
type = type.subst(getSILModule(), replacer, replacer, genericSig,
/*substitute opaque*/ true);
auto underlyingTy =
type.subst(getSILModule(), replacer, replacer, genericSig,
/*substitute opaque*/ true);
// The underlying type could contain a private type from a different TU.
if (!containsPrivateType(underlyingTy.getASTType()))
return underlyingTy;
}

return type;
Expand All @@ -548,11 +565,14 @@ IRGenModule::substOpaqueTypesWithUnderlyingTypes(CanType type,
if (type->hasOpaqueArchetype()) {
ReplaceOpaqueTypesWithUnderlyingTypes replacer(getSwiftModule(),
ResilienceExpansion::Maximal);
conformance = conformance.subst(type, replacer, replacer,
SubstFlags::SubstituteOpaqueArchetypes);
type = type.subst(replacer, replacer,
SubstFlags::SubstituteOpaqueArchetypes)
->getCanonicalType();
auto substConformance = conformance.subst(
type, replacer, replacer, SubstFlags::SubstituteOpaqueArchetypes);
auto underlyingTy =
type.subst(replacer, replacer, SubstFlags::SubstituteOpaqueArchetypes)
->getCanonicalType();
// The underlying type could contain a private type from a different TU.
if (!containsPrivateType(underlyingTy))
return std::make_pair(underlyingTy, substConformance);
}

return std::make_pair(type, conformance);
Expand Down
17 changes: 17 additions & 0 deletions test/IRGen/Inputs/opaque_result_type_private_underlying_2.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
public protocol A {
associatedtype Assoc
func bindAssoc() -> Assoc
}

public protocol Q {}

fileprivate struct PrivateS : Q {
init() {}
}

public struct G : A {
public init() {}
public func bindAssoc() -> some Q {
return PrivateS()
}
}
8 changes: 8 additions & 0 deletions test/IRGen/opaque_result_type_private_underlying.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// RUN: %target-swift-frontend -disable-availability-checking -emit-ir -primary-file %s -primary-file %S/Inputs/opaque_result_type_private_underlying_2.swift

public struct G2 : A {
public init() {}
public func bindAssoc() -> some Q {
return G().bindAssoc()
}
}