From bfb6fc72bc230f500ec203bd206b14040fb1faaa Mon Sep 17 00:00:00 2001 From: Joe Groff Date: Mon, 22 Sep 2014 21:56:52 +0000 Subject: [PATCH] IRGen: Reabstract lowered dependent types when substituting into a generic context. Fixes rdar://problem/17218632. Swift SVN r22189 --- include/swift/AST/ArchetypeBuilder.h | 13 ++++++ lib/IRGen/GenType.cpp | 10 +++-- lib/SIL/SILFunction.cpp | 42 +++++++++++++++---- lib/SIL/TypeLowering.cpp | 3 +- test/IRGen/dependent_reabstraction.swift | 24 +++++++++++ .../Interpreter/dependent_reabstraction.swift | 25 +++++++++++ 6 files changed, 105 insertions(+), 12 deletions(-) create mode 100644 test/IRGen/dependent_reabstraction.swift create mode 100644 test/Interpreter/dependent_reabstraction.swift diff --git a/include/swift/AST/ArchetypeBuilder.h b/include/swift/AST/ArchetypeBuilder.h index 09f5aa58871..34ef660d8c1 100644 --- a/include/swift/AST/ArchetypeBuilder.h +++ b/include/swift/AST/ArchetypeBuilder.h @@ -47,6 +47,7 @@ class ProtocolConformance; class ProtocolDecl; class Requirement; class RequirementRepr; +class SILModule; class SourceLoc; class Type; class TypeRepr; @@ -282,6 +283,18 @@ public: static Type mapTypeIntoContext(Module *M, GenericParamList *genericParams, Type type); + + // In SILFunction.cpp: + + /// \brief Resolve the given dependent type using our context archetypes. + /// + /// Given an arbitrary type, this will substitute dependent type parameters + /// structurally with their corresponding archetypes and resolve dependent + /// member types to the appropriate associated types. It will reabstract + /// dependent types according to the abstraction level of their associated + /// type requirements. + SILType substDependentType(SILModule &M, + SILType type); }; class ArchetypeBuilder::PotentialArchetype { diff --git a/lib/IRGen/GenType.cpp b/lib/IRGen/GenType.cpp index 0242f491baa..43446d991d2 100644 --- a/lib/IRGen/GenType.cpp +++ b/lib/IRGen/GenType.cpp @@ -1070,9 +1070,13 @@ TypeCacheEntry TypeConverter::getTypeEntry(CanType canonicalTy) { // If the type is dependent, substitute it into our current context. auto contextTy = canonicalTy; - if (contextTy->isDependentType()) - contextTy = getArchetypes().substDependentType(contextTy) - ->getCanonicalType(); + if (contextTy->isDependentType()) { + // The type we got should be lowered, so lower it like a SILType. + contextTy = getArchetypes().substDependentType(*IGM.SILMod, + SILType::getPrimitiveAddressType(contextTy)) + .getSwiftRValueType(); + + } // Fold archetypes to unique exemplars. Any archetype with the same // constraints is equivalent for type lowering purposes. diff --git a/lib/SIL/SILFunction.cpp b/lib/SIL/SILFunction.cpp index 5781f333c4f..ccd03915904 100644 --- a/lib/SIL/SILFunction.cpp +++ b/lib/SIL/SILFunction.cpp @@ -128,19 +128,28 @@ Type SILFunction::mapTypeIntoContext(Type type) const { } namespace { -struct MapSILTypeIntoContext : CanTypeVisitor { - const SILFunction *ContextFn; +template +struct SubstDependentSILType + : CanTypeVisitor, CanType> +{ + SILModule &M; + SubstFn Subst; - MapSILTypeIntoContext(const SILFunction *ContextFn) : ContextFn(ContextFn) {} + SubstDependentSILType(SILModule &M, SubstFn Subst) + : M(M), Subst(std::move(Subst)) + {} + + using super = CanTypeVisitor, CanType>; + using super::visit; CanType visitDependentMemberType(CanDependentMemberType t) { // If a dependent member type appears in lowered position, we need to lower // its context substitution against the associated type's abstraction // pattern. - CanType astTy = ContextFn->mapTypeIntoContext(t)->getCanonicalType(); + CanType astTy = Subst(t); AbstractionPattern origTy(t->getAssocType()->getArchetype()); - return ContextFn->getModule().Types.getLoweredType(origTy, astTy) + return M.Types.getLoweredType(origTy, astTy) .getSwiftRValueType(); } @@ -179,14 +188,31 @@ struct MapSILTypeIntoContext : CanTypeVisitor { CanType visitType(CanType t) { // Other types get substituted into context normally. - return ContextFn->mapTypeIntoContext(t)->getCanonicalType(); + return Subst(t); } }; + +template +SILType doSubstDependentSILType(SILModule &M, + SubstFn Subst, + SILType t) { + CanType result = SubstDependentSILType(M, std::move(Subst)) + .visit(t.getSwiftRValueType()); + return SILType::getPrimitiveType(result, t.getCategory()); +} + } // end anonymous namespace SILType SILFunction::mapTypeIntoContext(SILType type) const { - CanType astTy = MapSILTypeIntoContext(this).visit(type.getSwiftRValueType()); - return SILType::getPrimitiveType(astTy, type.getCategory()); + return doSubstDependentSILType(getModule(), + [&](CanType t) { return mapTypeIntoContext(t)->getCanonicalType(); }, + type); +} + +SILType ArchetypeBuilder::substDependentType(SILModule &M, SILType type) { + return doSubstDependentSILType(M, + [&](CanType t) { return substDependentType(t)->getCanonicalType(); }, + type); } SILBasicBlock *SILFunction::createBasicBlock() { diff --git a/lib/SIL/TypeLowering.cpp b/lib/SIL/TypeLowering.cpp index 4b6e537d76f..56c3bb69a4d 100644 --- a/lib/SIL/TypeLowering.cpp +++ b/lib/SIL/TypeLowering.cpp @@ -1363,7 +1363,8 @@ TypeConverter::getTypeLowering(AbstractionPattern origType, SILType loweredType = getLoweredType(origObjectType, substObjectType, uncurryLevel).getAddressType(); - auto *theInfo = new (*this, key.isDependent()) TrivialTypeLowering(loweredType); + auto *theInfo = new (*this, key.isDependent()) + TrivialTypeLowering(loweredType); insert(key, theInfo); return *theInfo; } diff --git a/test/IRGen/dependent_reabstraction.swift b/test/IRGen/dependent_reabstraction.swift new file mode 100644 index 00000000000..4f5d12b6201 --- /dev/null +++ b/test/IRGen/dependent_reabstraction.swift @@ -0,0 +1,24 @@ +// RUN: %swift -emit-ir %s | FileCheck %s + +protocol A { + typealias B + func b(B) +} + +struct X : A { + // CHECK-LABEL: define void @_TTWV23dependent_reabstraction1XS_1AFS1_1bUS1__U__fRQPS1_FQS2_1BT_(%swift.type** noalias, %V23dependent_reabstraction1X* noalias, %swift.type* %Self) + func b(b: X.Type) { + let x: Any = b + println(b as X.Type) + } +} + +func foo(x: T, y: T.B) { + x.b(y) +} + +let a = X() +let b = X() + +foo(a, X.self) +foo(b, X.self) diff --git a/test/Interpreter/dependent_reabstraction.swift b/test/Interpreter/dependent_reabstraction.swift new file mode 100644 index 00000000000..ee1696449ff --- /dev/null +++ b/test/Interpreter/dependent_reabstraction.swift @@ -0,0 +1,25 @@ +// RUN: %target-run-simple-swift + +protocol A { + typealias B + func b(B) +} + +struct X : A { + func b(b: X.Type) { + let x: Any = b + println(b as X.Type) + } +} + +func foo(x: T, y: T.B) { + x.b(y) +} + +let a = X() +let b = X() + +// CHECK: (Metatype) +foo(a, X.self) +// CHECK-NEXT: (Metatype) +foo(b, X.self)