From 9971422cf800c8a6e1d1dfe92ccb06ccf3e55aab Mon Sep 17 00:00:00 2001 From: Anthony Latsis Date: Fri, 20 Mar 2020 02:12:59 +0300 Subject: [PATCH 1/2] Clean up TypeConverter::getConstantOverrideInfo --- lib/SIL/SILFunctionType.cpp | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/lib/SIL/SILFunctionType.cpp b/lib/SIL/SILFunctionType.cpp index 22796e15e2924..204eb2d473bb6 100644 --- a/lib/SIL/SILFunctionType.cpp +++ b/lib/SIL/SILFunctionType.cpp @@ -3029,13 +3029,13 @@ TypeConverter::getConstantOverrideInfo(TypeExpansionContext context, // convention appropriately before calling the derived method. bool hasGenericRequirementDifference = false; - auto derivedSig = derived.getDecl()->getAsGenericContext() + const auto derivedSig = derived.getDecl()->getAsGenericContext() ->getGenericSignature(); - auto genericSig = Context.getOverrideGenericSignature(base.getDecl(), - derived.getDecl()); - if (genericSig) { + const auto overrideSig = Context.getOverrideGenericSignature( + base.getDecl(), derived.getDecl()); + if (overrideSig) { hasGenericRequirementDifference = - !genericSig->requirementsNotSatisfiedBy(derivedSig).empty(); + !overrideSig->requirementsNotSatisfiedBy(derivedSig).empty(); } auto baseInfo = getConstantInfo(context, base); @@ -3068,10 +3068,10 @@ TypeConverter::getConstantOverrideInfo(TypeExpansionContext context, overrideInterfaceTy = derivedInfo.FormalType; } - if (genericSig && !genericSig->areAllParamsConcrete()) { + if (overrideSig) { overrideInterfaceTy = cast( - GenericFunctionType::get(genericSig, + GenericFunctionType::get(overrideSig, overrideInterfaceTy->getParams(), overrideInterfaceTy->getResult(), overrideInterfaceTy->getExtInfo()) @@ -3079,11 +3079,12 @@ TypeConverter::getConstantOverrideInfo(TypeExpansionContext context, } // Build the lowered AST function type for the class method call. - auto bridgedTypes = getLoweredFormalTypes(derived, overrideInterfaceTy); + auto bridgedUncurriedTy = + getLoweredFormalTypes(derived, overrideInterfaceTy).Uncurried; // Build the SILFunctionType for the class method call. CanSILFunctionType fnTy = getNativeSILFunctionType( - *this, context, basePattern, bridgedTypes.Uncurried, base, derived, + *this, context, basePattern, bridgedUncurriedTy, base, derived, /*reqt subs*/ None, ProtocolConformanceRef()); // Build the SILConstantInfo and cache it. @@ -3092,7 +3093,7 @@ TypeConverter::getConstantOverrideInfo(TypeExpansionContext context, auto result = ::new (resultBuf) SILConstantInfo{ overrideInterfaceTy, basePattern, - bridgedTypes.Uncurried, + bridgedUncurriedTy, fnTy}; auto inserted = ConstantOverrideTypes.insert({{derived, base}, result}); From 4848aaa8839c624f11e3b029ffe561a456f55097 Mon Sep 17 00:00:00 2001 From: Anthony Latsis Date: Fri, 20 Mar 2020 02:20:05 +0300 Subject: [PATCH 2/2] [SILGen] Fall back to module lookup on invalid conformance when building subst. maps for vtable thunks --- include/swift/AST/SubstitutionMap.h | 24 ++++++++++++- lib/AST/SubstitutionMap.cpp | 34 +++++++++++++++++-- lib/SILGen/SILGenPoly.cpp | 3 +- test/SILGen/vtable_thunks_reabstraction.swift | 18 ++++++++++ 4 files changed, 75 insertions(+), 4 deletions(-) diff --git a/include/swift/AST/SubstitutionMap.h b/include/swift/AST/SubstitutionMap.h index deb897f5053bb..68402cea0bfcd 100644 --- a/include/swift/AST/SubstitutionMap.h +++ b/include/swift/AST/SubstitutionMap.h @@ -111,8 +111,30 @@ class SubstitutionMap { /// Build an interface type substitution map for the given generic /// signature using the mapping in the given substitutions. + /// + /// \Note + /// Currently, \p fallBackToModuleConformanceLookup is only necessary + /// when we emit a reabstraction thunk for an override, because we might + /// not have enough information in the substitution map alone. + /// + /// For example, combining the override substitutions with the invocation + /// generic signature for the following override requires recovering + /// the implied conformance Foo : P. + /// + /// \code + /// class Base { + /// func foo(u: U) where T == Foo {} + /// } + /// class Derived: Base { + /// override func foo(u: U) where T: P {} + /// } + /// \endcode + /// + /// \param fallBackToModuleConformanceLookup Fall back to module lookup + /// if a conformance could not be found otherwise. static SubstitutionMap get(GenericSignature genericSig, - SubstitutionMap substitutions); + SubstitutionMap substitutions, + bool fallBackToModuleConformanceLookup = false); /// Build an interface type substitution map for the given generic signature /// from a type substitution function and conformance lookup function. diff --git a/lib/AST/SubstitutionMap.cpp b/lib/AST/SubstitutionMap.cpp index 026111141f832..f569ebc52f0a4 100644 --- a/lib/AST/SubstitutionMap.cpp +++ b/lib/AST/SubstitutionMap.cpp @@ -178,19 +178,49 @@ SubstitutionMap SubstitutionMap::getCanonical() const { SubstitutionMap SubstitutionMap::get(GenericSignature genericSig, - SubstitutionMap substitutions) { + SubstitutionMap substitutions, + bool fallBackToModuleConformanceLookup) { if (!genericSig) { assert(!substitutions.hasAnySubstitutableParams() && "Shouldn't have substitutions here"); return SubstitutionMap(); } + LookupConformanceFn lookupConformanceFn; + if (fallBackToModuleConformanceLookup) { + /// Like \c LookUpConformanceInSubstitutionMap , but falls back to module + /// lookup if the conformance could not be found. + class LookUpConformanceInSubstitutionMapOrModule { + SubstitutionMap Subs; + public: + LookUpConformanceInSubstitutionMapOrModule(SubstitutionMap Subs) + : Subs(Subs) {} + + ProtocolConformanceRef operator()(CanType dependentType, + Type conformingReplacementType, + ProtocolDecl *conformedProtocol) const { + auto conformance = LookUpConformanceInSubstitutionMap(Subs) + (dependentType, conformingReplacementType, conformedProtocol); + + if (conformance.isInvalid()) + return conformedProtocol->getParentModule()->lookupConformance( + conformingReplacementType, conformedProtocol); + return conformance; + }; + }; + + lookupConformanceFn = + LookUpConformanceInSubstitutionMapOrModule(substitutions); + } else { + lookupConformanceFn = LookUpConformanceInSubstitutionMap(substitutions); + } + return SubstitutionMap::get(genericSig, [&](SubstitutableType *type) -> Type { return substitutions.lookupSubstitution( CanSubstitutableType(type)); }, - LookUpConformanceInSubstitutionMap(substitutions)); + lookupConformanceFn); } /// Build an interface type substitution map for the given generic signature diff --git a/lib/SILGen/SILGenPoly.cpp b/lib/SILGen/SILGenPoly.cpp index 827338185ff65..15c38876b968b 100644 --- a/lib/SILGen/SILGenPoly.cpp +++ b/lib/SILGen/SILGenPoly.cpp @@ -3744,7 +3744,8 @@ SILGenFunction::emitVTableThunk(SILDeclRef base, auto subs = getForwardingSubstitutionMap(); if (auto genericSig = derivedFTy->getInvocationGenericSignature()) { - subs = SubstitutionMap::get(genericSig, subs); + subs = SubstitutionMap::get(genericSig, subs, + /*fallBackToModuleConformanceLookup*/true); derivedFTy = derivedFTy->substGenericArgs(SGM.M, subs, getTypeExpansionContext()); diff --git a/test/SILGen/vtable_thunks_reabstraction.swift b/test/SILGen/vtable_thunks_reabstraction.swift index 5d029373b1561..17167456e19b2 100644 --- a/test/SILGen/vtable_thunks_reabstraction.swift +++ b/test/SILGen/vtable_thunks_reabstraction.swift @@ -484,11 +484,14 @@ class ConcreteOptional: Opaque { class GenericBase { func doStuff(t: T, u: U) {} init(t: T, u: U) {} + + func doStuff2(u: U) where T == Int {} } // CHECK-LABEL: sil_vtable GenericBase { // CHECK-NEXT: #GenericBase.doStuff!1: (GenericBase) -> (T, U) -> () : @$s27vtable_thunks_reabstraction11GenericBaseC7doStuff1t1uyx_qd__tlF // GenericBase.doStuff(t:u:) // CHECK-NEXT: #GenericBase.init!allocator.1: (GenericBase.Type) -> (T, U) -> GenericBase : @$s27vtable_thunks_reabstraction11GenericBaseC1t1uACyxGx_qd__tclufC +// CHECK-NEXT: #GenericBase.doStuff2!1: (GenericBase) -> (U) -> () : @$s27vtable_thunks_reabstraction11GenericBaseC8doStuff21uyqd___tSiRszlF // CHECK-NEXT: #GenericBase.deinit!deallocator.1: @$s27vtable_thunks_reabstraction11GenericBaseCfD // GenericBase.__deallocating_deinit // CHECK-NEXT: } @@ -504,6 +507,7 @@ class ConcreteSub : GenericBase { // CHECK-LABEL: sil_vtable ConcreteSub { // CHECK-NEXT: #GenericBase.doStuff!1: (GenericBase) -> (T, U) -> () : @$s27vtable_thunks_reabstraction11ConcreteSubC7doStuff1t1uySi_xtlFAA11GenericBaseCAdeFyx_qd__tlFTV [override] // vtable thunk for GenericBase.doStuff(t:u:) dispatching to ConcreteSub.doStuff(t:u:) // CHECK-NEXT: #GenericBase.init!allocator.1: (GenericBase.Type) -> (T, U) -> GenericBase : @$s27vtable_thunks_reabstraction11ConcreteSubC1t1uACSi_xtclufCAA11GenericBaseCAdeGyxGx_qd__tclufCTV [override] +// CHECK-NEXT: #GenericBase.doStuff2!1: {{.*}}F [inherited] // CHECK-NEXT: #ConcreteSub.deinit!deallocator.1: @$s27vtable_thunks_reabstraction11ConcreteSubCfD // ConcreteSub.__deallocating_deinit // CHECK-NEXT: } @@ -543,6 +547,7 @@ class MoreGenericSub1 : GenericBase { // CHECK-LABEL: sil_vtable MoreGenericSub1 { // CHECK-NEXT: #GenericBase.doStuff!1: (GenericBase) -> (T, U) -> () : @$s27vtable_thunks_reabstraction15MoreGenericSub1C7doStuff1t1uyx_qd__tlF [override] // MoreGenericSub1.doStuff(t:u:) // CHECK-NEXT: #GenericBase.init!allocator.1: (GenericBase.Type) -> (T, U) -> GenericBase : @$s27vtable_thunks_reabstraction15MoreGenericSub1C1t1uACyxq_Gx_qd__tclufC [override] +// CHECK-NEXT: #GenericBase.doStuff2!1: {{.*}}F [inherited] // CHECK-NEXT: #MoreGenericSub1.deinit!deallocator.1: @$s27vtable_thunks_reabstraction15MoreGenericSub1CfD // MoreGenericSub1.__deallocating_deinit // CHECK-NEXT: } @@ -555,5 +560,18 @@ class MoreGenericSub2 : GenericBase { // CHECK-LABEL: sil_vtable MoreGenericSub2 { // CHECK-NEXT: #GenericBase.doStuff!1: (GenericBase) -> (T, U) -> () : @$s27vtable_thunks_reabstraction15MoreGenericSub2C7doStuff1t1uyq__qd__tlF [override] // MoreGenericSub2.doStuff(t:u:) // CHECK-NEXT: #GenericBase.init!allocator.1: (GenericBase.Type) -> (T, U) -> GenericBase : @$s27vtable_thunks_reabstraction15MoreGenericSub2C1t1uACyxq_Gq__qd__tclufC [override] +// CHECK-NEXT: #GenericBase.doStuff2!1: {{.*}}F [inherited] // CHECK-NEXT: #MoreGenericSub2.deinit!deallocator.1: @$s27vtable_thunks_reabstraction15MoreGenericSub2CfD // MoreGenericSub2.__deallocating_deinit // CHECK-NEXT: } + +class GenericSub2: GenericBase { + override func doStuff2(u: U) where T: FixedWidthInteger {} +} + +// CHECK-LABEL: sil_vtable GenericSub2 { +// CHECK-NEXT: #GenericBase.doStuff!1: {{.*}}F [inherited] +// CHECK-NEXT: #GenericBase.init +// CHECK-NEXT: #GenericBase.doStuff2!1: (GenericBase) -> (U) -> () : @$s27vtable_thunks_reabstraction11GenericSub2C8doStuff21uyqd___ts17FixedWidthIntegerRzlFAA0D4BaseCAdEyqd___tSiRszlFTV [override] +// CHECK-NEXT: #GenericSub2.doStuff2!1: (GenericSub2) -> (U) -> () : @$s27vtable_thunks_reabstraction11GenericSub2C8doStuff21uyqd___ts17FixedWidthIntegerRzlF +// CHECK-NEXT: #GenericSub2.deinit +// CHECK-NEXT: }