Check for use of implementation-only conformances in inlinable code

This includes both the types and the values (generic functions, etc)
used in the inlinable code. We get some effectively duplicate
diagnostics at this point because of this, but we can deal with that
at a future date.

Last part of rdar://problem/48991061
This commit is contained in:
Jordan Rose
2019-04-09 16:06:02 -07:00
parent 590551781a
commit 7006aa0b9f
5 changed files with 392 additions and 27 deletions

View File

@@ -15,10 +15,13 @@
//===----------------------------------------------------------------------===//
#include "TypeChecker.h"
#include "TypeCheckAvailability.h"
#include "swift/AST/AccessScopeChecker.h"
#include "swift/AST/Attr.h"
#include "swift/AST/Decl.h"
#include "swift/AST/Initializer.h"
#include "swift/AST/DeclContext.h"
#include "swift/AST/Initializer.h"
#include "swift/AST/ProtocolConformance.h"
using namespace swift;
using FragileFunctionKind = TypeChecker::FragileFunctionKind;
@@ -106,10 +109,6 @@ bool TypeChecker::diagnoseInlinableDeclRef(SourceLoc loc,
const ValueDecl *D = declRef.getDecl();
// Do some important fast-path checks that apply to all cases.
// Local declarations are OK.
if (D->getDeclContext()->isLocalContext())
return false;
// Type parameters are OK.
if (isa<AbstractTypeParamDecl>(D))
return false;
@@ -120,7 +119,7 @@ bool TypeChecker::diagnoseInlinableDeclRef(SourceLoc loc,
return true;
// Check whether the declaration comes from a publically-imported module.
if (diagnoseDeclRefExportability(loc, D, DC))
if (diagnoseDeclRefExportability(loc, declRef, DC))
return true;
return false;
@@ -131,6 +130,10 @@ bool TypeChecker::diagnoseInlinableDeclRefAccess(SourceLoc loc,
const DeclContext *DC,
FragileFunctionKind Kind,
bool TreatUsableFromInlineAsPublic) {
// Local declarations are OK.
if (D->getDeclContext()->isLocalContext())
return false;
// Public declarations are OK.
if (D->getFormalAccessScope(/*useDC=*/nullptr,
TreatUsableFromInlineAsPublic).isPublic())
@@ -204,8 +207,89 @@ bool TypeChecker::diagnoseInlinableDeclRefAccess(SourceLoc loc,
return (downgradeToWarning == DowngradeToWarning::No);
}
static bool diagnoseDeclExportability(SourceLoc loc, const ValueDecl *D,
const SourceFile &userSF) {
auto definingModule = D->getModuleContext();
if (!userSF.isImportedImplementationOnly(definingModule))
return false;
// TODO: different diagnostics
ASTContext &ctx = definingModule->getASTContext();
ctx.Diags.diagnose(loc, diag::inlinable_decl_ref_implementation_only,
D->getDescriptiveKind(), D->getFullName());
return true;
}
static bool
diagnoseGenericArgumentsExportability(SourceLoc loc,
const SubstitutionMap &subs,
const SourceFile &userSF) {
bool hadAnyIssues = false;
for (ProtocolConformanceRef conformance : subs.getConformances()) {
if (!conformance.isConcrete())
continue;
const ProtocolConformance *concreteConf = conformance.getConcrete();
SubstitutionMap subConformanceSubs =
concreteConf->getSubstitutions(userSF.getParentModule());
diagnoseGenericArgumentsExportability(loc, subConformanceSubs, userSF);
const RootProtocolConformance *rootConf =
concreteConf->getRootConformance();
ModuleDecl *M = rootConf->getDeclContext()->getParentModule();
if (!userSF.isImportedImplementationOnly(M))
continue;
ASTContext &ctx = M->getASTContext();
ctx.Diags.diagnose(loc, diag::conformance_from_implementation_only_module,
rootConf->getType(),
rootConf->getProtocol()->getFullName(), M->getName());
hadAnyIssues = true;
}
return hadAnyIssues;
}
void TypeChecker::diagnoseGenericTypeExportability(const TypeLoc &TL,
const DeclContext *DC) {
class GenericTypeFinder : public TypeDeclFinder {
using Callback = llvm::function_ref<void(SubstitutionMap)>;
const SourceFile &SF;
Callback callback;
public:
GenericTypeFinder(const SourceFile &SF, Callback callback)
: SF(SF), callback(callback) {}
Action visitBoundGenericType(BoundGenericType *ty) override {
ModuleDecl *useModule = SF.getParentModule();
SubstitutionMap subs = ty->getContextSubstitutionMap(useModule,
ty->getDecl());
callback(subs);
return Action::Continue;
}
Action visitTypeAliasType(TypeAliasType *ty) override {
callback(ty->getSubstitutionMap());
return Action::Continue;
}
};
assert(TL.getType() && "type not validated yet");
const SourceFile *SF = DC->getParentSourceFile();
if (!SF)
return;
TL.getType().walk(GenericTypeFinder(*SF, [&](SubstitutionMap subs) {
// FIXME: It would be nice to highlight just the part of the type that's
// problematic, but unfortunately the TypeRepr doesn't have the
// information we need and the Type doesn't easily map back to it.
(void)diagnoseGenericArgumentsExportability(TL.getLoc(), subs, *SF);
}));
}
bool TypeChecker::diagnoseDeclRefExportability(SourceLoc loc,
const ValueDecl *D,
ConcreteDeclRef declRef,
const DeclContext *DC) {
// We're only interested in diagnosing uses from source files.
auto userSF = DC->getParentSourceFile();
@@ -220,22 +304,12 @@ bool TypeChecker::diagnoseDeclRefExportability(SourceLoc loc,
if (!userSF->hasImplementationOnlyImports())
return false;
auto userModule = userSF->getParentModule();
auto definingModule = D->getModuleContext();
// Nothing to diagnose in the very common case of the same module.
if (userModule == definingModule)
return false;
// Nothing to diagnose in the very common case that the module is
// imported for use in signatures.
if (!userSF->isImportedImplementationOnly(definingModule))
return false;
// TODO: different diagnostics
diagnose(loc, diag::inlinable_decl_ref_implementation_only,
D->getDescriptiveKind(), D->getFullName());
// TODO: notes explaining why
return true;
const ValueDecl *D = declRef.getDecl();
if (diagnoseDeclExportability(loc, D, *userSF))
return true;
if (diagnoseGenericArgumentsExportability(loc, declRef.getSubstitutions(),
*userSF)) {
return true;
}
return false;
}

View File

@@ -1742,6 +1742,13 @@ bool TypeChecker::validateType(TypeLoc &Loc, TypeResolution resolution,
}
Loc.setType(type);
if (!type->hasError()) {
const DeclContext *DC = resolution.getDeclContext();
if (options.isAnyExpr() || DC->getParent()->isLocalContext())
if (DC->getResilienceExpansion() == ResilienceExpansion::Minimal)
diagnoseGenericTypeExportability(Loc, DC);
}
return type->hasError();
}

View File

@@ -1887,13 +1887,23 @@ private:
FragileFunctionKind Kind,
bool TreatUsableFromInlineAsPublic);
public:
/// Given that a declaration is used from a particular context which
/// exposes it in the interface of the current module, diagnose if it cannot
/// reasonably be shared.
bool diagnoseDeclRefExportability(SourceLoc loc, const ValueDecl *D,
bool diagnoseDeclRefExportability(SourceLoc loc, ConcreteDeclRef declRef,
const DeclContext *DC);
public:
/// Given that a type is used from a particular context which
/// exposes it in the interface of the current module, diagnose if its
/// generic arguments require the use of conformances that cannot reasonably
/// be shared.
///
/// This method \e only checks how generic arguments are used; it is assumed
/// that the declarations involved have already been checked elsewhere.
void diagnoseGenericTypeExportability(const TypeLoc &TL,
const DeclContext *DC);
/// Given that \p DC is within a fragile context for some reason, describe
/// why.
///

View File

@@ -64,6 +64,7 @@ public protocol TestAssocTypeWhereClause {
public enum TestRawType: IntLike { // expected-error {{cannot use 'IntLike' here; 'BADLibrary' has been imported as '@_implementationOnly'}}
case x = 1
// FIXME: expected-error@-1 {{cannot use conformance of 'IntLike' to 'Equatable' here; 'BADLibrary' has been imported as '@_implementationOnly'}}
}
public class TestSubclass: BadClass { // expected-error {{cannot use 'BadClass' here; 'BADLibrary' has been imported as '@_implementationOnly'}}
@@ -245,3 +246,13 @@ public struct RequirementsHandleSpecializationsToo: SlightlyMoreComplicatedRequi
public struct ClassConstrainedGenericArg<T: NormalClass>: PublicInferredAssociatedType { // expected-error {{cannot use conformance of 'NormalClass' to 'NormalProto' in associated type 'Self.Assoc' (inferred as 'T'); 'BADLibrary' has been imported as '@_implementationOnly'}}
public func takesAssoc(_: T) {}
}
public protocol RecursiveRequirements {
associatedtype Other: RecursiveRequirements
}
extension GenericStruct: RecursiveRequirements {
public typealias Other = GenericStruct<T>
}
public struct RecursiveRequirementsHolder<T: RecursiveRequirements> {}
public func makeSureRecursiveRequirementsDontBreakEverything(_: RecursiveRequirementsHolder<GenericStruct<Int>>) {}

View File

@@ -0,0 +1,263 @@
// RUN: %empty-directory(%t)
// RUN: %target-swift-frontend -emit-module -o %t/NormalLibrary.swiftmodule %S/Inputs/implementation-only-import-in-decls-public-helper.swift
// RUN: %target-swift-frontend -emit-module -o %t/BADLibrary.swiftmodule %S/Inputs/implementation-only-import-in-decls-helper.swift -I %t
// RUN: %target-typecheck-verify-swift -I %t
@_implementationOnly import BADLibrary
import NormalLibrary
@available(*, unavailable)
public typealias X = Int
public typealias NormalProtoAssoc<T: NormalProto> = T.Assoc
@inlinable func testConformanceInTypealias() {
let x: NormalProtoAssoc<NormalStruct>? = nil // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary' has been imported as '@_implementationOnly'}}
_ = x
_ = NormalProtoAssoc<NormalStruct>() // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary' has been imported as '@_implementationOnly'}}
}
func internalConformanceInTypealias() {
let x: NormalProtoAssoc<NormalStruct>? = nil // okay
_ = x
_ = NormalProtoAssoc<NormalStruct>() // okay
}
public struct NormalProtoAssocHolder<T: NormalProto> {
public var value: T.Assoc?
public init() {}
public init(_ value: T?) {}
}
@inlinable func testConformanceInBoundGeneric() {
let x: NormalProtoAssocHolder<NormalStruct>? = nil // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary' has been imported as '@_implementationOnly'}}
_ = x
// FIXME: We get this error twice: once for the TypeExpr and once for the implicit init.
_ = NormalProtoAssocHolder<NormalStruct>() // expected-error 2 {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary' has been imported as '@_implementationOnly'}}
_ = NormalProtoAssocHolder(nil as NormalStruct?) // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary' has been imported as '@_implementationOnly'}}
}
func internalConformanceInBoundGeneric() {
let x: NormalProtoAssocHolder<NormalStruct>? = nil // okay
_ = x
_ = NormalProtoAssocHolder<NormalStruct>() // okay
_ = NormalProtoAssocHolder(nil as NormalStruct?) // okay
}
@inlinable func testDowncast(_ x: Any) -> Bool {
let normal = x is NormalProtoAssocHolder<NormalStruct> // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary' has been imported as '@_implementationOnly'}}
let alias = x is NormalProtoAssoc<NormalStruct> // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary' has been imported as '@_implementationOnly'}}
return normal || alias
}
func internalDowncast(_ x: Any) -> Bool {
let normal = x is NormalProtoAssocHolder<NormalStruct> // okay
let alias = x is NormalProtoAssoc<NormalStruct> // okay
return normal || alias
}
@inlinable func testSwitch(_ x: Any) {
switch x {
case let holder as NormalProtoAssocHolder<NormalStruct>: // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary' has been imported as '@_implementationOnly'}}
_ = holder
break
case is NormalProtoAssoc<NormalStruct>: // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary' has been imported as '@_implementationOnly'}}
break
default:
break
}
}
func internalSwitch(_ x: Any) {
switch x {
case let holder as NormalProtoAssocHolder<NormalStruct>: // okay
_ = holder
break
case is NormalProtoAssoc<NormalStruct>: // okay
break
default:
break
}
}
public enum NormalProtoEnumUser<T: NormalProto> {
case a
}
@inlinable func testEnum() {
// FIXME: We get this error twice: once for the pattern and once for the implicit TypeExpr.
let x: NormalProtoEnumUser<NormalStruct> = .a // expected-error 2 {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary' has been imported as '@_implementationOnly'}}
_ = x
// FIXME: We get this error twice: once for the TypeExpr and once for the case.
_ = NormalProtoEnumUser<NormalStruct>.a // expected-error 2 {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary' has been imported as '@_implementationOnly'}}
}
func internalEnum() {
let x: NormalProtoEnumUser<NormalStruct> = .a // okay
_ = x
_ = NormalProtoEnumUser<NormalStruct>.a // okay
}
@usableFromInline func testFuncImpl<T: NormalProto>(_: T.Type) {}
@inlinable func testFunc() {
testFuncImpl(NormalStruct.self) // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary' has been imported as '@_implementationOnly'}}
}
func internalFunc() {
testFuncImpl(NormalStruct.self) // okay
}
public struct ForTestingMembers {
public init() {}
public init<T: NormalProto>(_: T.Type) {}
public subscript<T: NormalProto>(_: T.Type) -> Int {
get { return 0 }
set {}
}
public func method<T: NormalProto>(_: T.Type) {}
}
@inlinable func testMembers() {
_ = ForTestingMembers(NormalStruct.self) // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary' has been imported as '@_implementationOnly'}}
_ = ForTestingMembers.init(NormalStruct.self) // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary' has been imported as '@_implementationOnly'}}
_ = ForTestingMembers()[NormalStruct.self] // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary' has been imported as '@_implementationOnly'}}
var instance = ForTestingMembers()
instance[NormalStruct.self] = 1 // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary' has been imported as '@_implementationOnly'}}
ForTestingMembers().method(NormalStruct.self) // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary' has been imported as '@_implementationOnly'}}
}
extension NormalProtoAssocHolder {
public static func testAnotherConformance<U: NormalProto>(_: U.Type) {}
}
@inlinable func testMultipleConformances() {
_ = NormalProtoAssocHolder<NormalStruct>.testAnotherConformance(NormalClass.self)
// expected-error@-1 2 {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary' has been imported as '@_implementationOnly'}}
// expected-error@-2 {{cannot use conformance of 'NormalClass' to 'NormalProto' here; 'BADLibrary' has been imported as '@_implementationOnly'}}
}
@inlinable func localTypeAlias() {
typealias LocalUser = NormalProtoAssocHolder<NormalStruct> // expected-error{{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary' has been imported as '@_implementationOnly'}}
typealias LocalGenericUser<T> = (T, NormalProtoAssocHolder<NormalStruct>) // expected-error{{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary' has been imported as '@_implementationOnly'}}
typealias LocalProtoAssoc<T: NormalProto> = T.Assoc
_ = LocalProtoAssoc<NormalStruct>() // expected-error{{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary' has been imported as '@_implementationOnly'}}
}
@inlinable func localFunctions() {
func local(_: NormalProtoAssocHolder<NormalStruct>) {} // expected-error{{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary' has been imported as '@_implementationOnly'}}
func localReturn() -> NormalProtoAssocHolder<NormalStruct> { fatalError() } // expected-error{{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary' has been imported as '@_implementationOnly'}}
let _ = { (_: NormalProtoAssocHolder<NormalStruct>) in return } // expected-error{{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary' has been imported as '@_implementationOnly'}}
let _ = { () -> NormalProtoAssocHolder<NormalStruct> in fatalError() } // expected-error{{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary' has been imported as '@_implementationOnly'}}
}
@inlinable public func signatureOfInlinable(_: NormalProtoAssocHolder<NormalStruct>) {} // expected-error{{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary' has been imported as '@_implementationOnly'}}
public func testDefaultArgument(_: Int = NormalProtoAssoc<NormalStruct>()) {} // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary' has been imported as '@_implementationOnly'}}
public class SubclassOfNormalClass: NormalClass {}
public func testInheritedConformance(_: NormalProtoAssocHolder<SubclassOfNormalClass>) {} // expected-error {{cannot use conformance of 'NormalClass' to 'NormalProto' here; 'BADLibrary' has been imported as '@_implementationOnly'}}
public func testSpecializedConformance(_: NormalProtoAssocHolder<GenericStruct<Int>>) {} // expected-error {{cannot use conformance of 'GenericStruct<T>' to 'NormalProto' here; 'BADLibrary' has been imported as '@_implementationOnly'}}
extension Array where Element == NormalProtoAssocHolder<NormalStruct> { // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary' has been imported as '@_implementationOnly'}}
public func testConstrainedExtensionUsingBadConformance() {}
}
public struct ConditionalGenericStruct<T> {}
extension ConditionalGenericStruct: NormalProto where T: NormalProto {
public typealias Assoc = Int
}
public func testConditionalGeneric(_: NormalProtoAssocHolder<ConditionalGenericStruct<NormalStruct>>) {} // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary' has been imported as '@_implementationOnly'}}
public protocol PublicInferredAssociatedType {
associatedtype Assoc: NormalProto
func takesAssoc(_: Assoc)
}
@usableFromInline protocol UFIInferredAssociatedType {
associatedtype Assoc: NormalProto
func takesAssoc(_: Assoc)
}
protocol InternalInferredAssociatedType {
associatedtype Assoc: NormalProto
func takesAssoc(_: Assoc)
}
public struct PublicInferredAssociatedTypeImpl {
public func takesAssoc(_: NormalStruct) {}
}
extension PublicInferredAssociatedTypeImpl: PublicInferredAssociatedType {} // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' in associated type 'Self.Assoc' (inferred as 'NormalStruct'); 'BADLibrary' has been imported as '@_implementationOnly'}}
extension PublicInferredAssociatedTypeImpl: UFIInferredAssociatedType {} // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' in associated type 'Self.Assoc' (inferred as 'NormalStruct'); 'BADLibrary' has been imported as '@_implementationOnly'}}
extension PublicInferredAssociatedTypeImpl: InternalInferredAssociatedType {} // okay
@usableFromInline struct UFIInferredAssociatedTypeImpl {
public func takesAssoc(_: NormalStruct) {}
}
extension UFIInferredAssociatedTypeImpl: PublicInferredAssociatedType {} // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' in associated type 'Self.Assoc' (inferred as 'NormalStruct'); 'BADLibrary' has been imported as '@_implementationOnly'}}
extension UFIInferredAssociatedTypeImpl: UFIInferredAssociatedType {} // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' in associated type 'Self.Assoc' (inferred as 'NormalStruct'); 'BADLibrary' has been imported as '@_implementationOnly'}}
extension UFIInferredAssociatedTypeImpl: InternalInferredAssociatedType {} // okay
struct InternalInferredAssociatedTypeImpl {
public func takesAssoc(_: NormalStruct) {}
}
extension InternalInferredAssociatedTypeImpl: PublicInferredAssociatedType {} // okay
extension InternalInferredAssociatedTypeImpl: UFIInferredAssociatedType {} // okay
extension InternalInferredAssociatedTypeImpl: InternalInferredAssociatedType {} // okay
public protocol BaseProtoWithNoRequirement {
associatedtype Assoc
func takesAssoc(_: Assoc)
}
public protocol RefinedProto: BaseProtoWithNoRequirement where Assoc: NormalProto {
}
public struct RefinedProtoImpl: RefinedProto { // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' in associated type 'Self.Assoc' (inferred as 'NormalStruct'); 'BADLibrary' has been imported as '@_implementationOnly'}}
public func takesAssoc(_: NormalStruct) {}
}
public protocol RefinedSelfProto where Self: NormalProto {}
extension NormalStruct: RefinedSelfProto {} // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary' has been imported as '@_implementationOnly'}}
public protocol RefinedSelfProtoInheritance: NormalProto {}
extension NormalStruct: RefinedSelfProtoInheritance {} // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary' has been imported as '@_implementationOnly'}}
public protocol SlightlyMoreComplicatedRequirement {
associatedtype Assoc: Collection where Assoc.Element: NormalProto
func takesAssoc(_: Assoc)
}
public struct SlightlyMoreComplicatedRequirementImpl: SlightlyMoreComplicatedRequirement { // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' in associated type 'Self.Assoc.Element' (inferred as 'NormalStruct'); 'BADLibrary' has been imported as '@_implementationOnly'}}
public func takesAssoc(_: [NormalStruct]) {}
}
public struct RequirementsHandleSubclassesToo: SlightlyMoreComplicatedRequirement { // expected-error {{cannot use conformance of 'NormalClass' to 'NormalProto' in associated type 'Self.Assoc.Element' (inferred as 'SubclassOfNormalClass'); 'BADLibrary' has been imported as '@_implementationOnly'}}
public func takesAssoc(_: [SubclassOfNormalClass]) {}
}
public struct RequirementsHandleSpecializationsToo: SlightlyMoreComplicatedRequirement { // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' in associated type 'Self.Assoc.Element' (inferred as 'ConditionalGenericStruct<NormalStruct>'); 'BADLibrary' has been imported as '@_implementationOnly'}}
public func takesAssoc(_: [ConditionalGenericStruct<NormalStruct>]) {}
}
public struct ClassConstrainedGenericArg<T: NormalClass>: PublicInferredAssociatedType { // expected-error {{cannot use conformance of 'NormalClass' to 'NormalProto' in associated type 'Self.Assoc' (inferred as 'T'); 'BADLibrary' has been imported as '@_implementationOnly'}}
public func takesAssoc(_: T) {}
}
public protocol RecursiveRequirements {
associatedtype Other: RecursiveRequirements
}
extension GenericStruct: RecursiveRequirements {
public typealias Other = GenericStruct<T>
}
public struct RecursiveRequirementsHolder<T: RecursiveRequirements> {}
public func makeSureRecursiveRequirementsDontBreakEverything(_: RecursiveRequirementsHolder<GenericStruct<Int>>) {}
@inlinable func testFunctionBody() {
}