Skip to content

[Mangling] Several fixes for de/re/-mangling of generic typealiases #17509

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

Merged
merged 7 commits into from
Jun 27, 2018
Merged
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
9 changes: 9 additions & 0 deletions include/swift/AST/ASTMangler.h
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,15 @@ class ASTMangler : public Mangler {

void appendBoundGenericArgs(Type type, bool &isFirstArgList);

/// Append the bound generics arguments for the given declaration context
/// based on a complete substitution map.
///
/// \returns the number of generic parameters that were emitted
/// thus far.
unsigned appendBoundGenericArgs(DeclContext *dc,
SubstitutionMap subs,
bool &isFirstArgList);

/// Append any retroactive conformances.
void appendRetroactiveConformances(Type type);

Expand Down
82 changes: 69 additions & 13 deletions lib/AST/ASTMangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "swift/AST/Initializer.h"
#include "swift/AST/Module.h"
#include "swift/AST/ParameterList.h"
#include "swift/AST/PrettyStackTrace.h"
#include "swift/AST/ProtocolConformance.h"
#include "swift/AST/ProtocolConformanceRef.h"
#include "swift/Basic/Defer.h"
Expand Down Expand Up @@ -380,6 +381,9 @@ std::string ASTMangler::mangleReabstractionThunkHelper(

std::string ASTMangler::mangleTypeForDebugger(Type Ty, const DeclContext *DC,
GenericEnvironment *GE) {
PrettyStackTraceType prettyStackTrace(Ty->getASTContext(),
"mangling type for debugger", Ty);

GenericEnv = GE;
DWARFMangling = true;
beginMangling();
Expand Down Expand Up @@ -746,17 +750,13 @@ void ASTMangler::appendType(Type type) {
return appendType(aliasTy->getSinglyDesugaredType());
}

if (type->isSpecialized()) {
if (aliasTy->getSubstitutionMap().hasAnySubstitutableParams()) {
// Try to mangle the entire name as a substitution.
if (tryMangleSubstitution(tybase))
return;

appendAnyGenericType(decl);
bool isFirstArgList = true;
if (auto *nominalType = type->getAs<NominalType>()) {
if (nominalType->getParent())
type = nominalType->getParent();
}
appendBoundGenericArgs(type, isFirstArgList);
appendRetroactiveConformances(type);
appendOperator("G");
Expand Down Expand Up @@ -1039,16 +1039,74 @@ void ASTMangler::bindGenericParameters(const DeclContext *DC) {
bindGenericParameters(sig->getCanonicalSignature());
}

unsigned ASTMangler::appendBoundGenericArgs(DeclContext *dc,
SubstitutionMap subs,
bool &isFirstArgList) {
auto decl = dc->getInnermostDeclarationDeclContext();
if (!decl) return 0;

// For an extension declaration, use the nominal type declaration instead.
// This is important when extending a nested type, because the generic
// parameters will line up with the (semantic) nesting of the nominal type.
if (auto ext = dyn_cast<ExtensionDecl>(decl))
decl = ext->getAsNominalTypeOrNominalTypeExtensionContext();

// Handle the generic arguments of the parent.
unsigned currentGenericParamIdx =
appendBoundGenericArgs(decl->getDeclContext(), subs, isFirstArgList);

// If this is potentially a generic context, emit a generic argument list.
if (auto genericContext = decl->getAsGenericContext()) {
if (isFirstArgList) {
appendOperator("y");
isFirstArgList = false;
} else {
appendOperator("_");
}

// If we are generic at this level, emit all of the replacements at
// this level.
if (genericContext->isGeneric()) {
auto genericParams = subs.getGenericSignature()->getGenericParams();
unsigned depth = genericParams[currentGenericParamIdx]->getDepth();
assert(genericContext->getGenericParams()->getDepth() == depth &&
"Depth mismatch mangling substitution map");
auto replacements = subs.getReplacementTypes();
for (unsigned lastGenericParamIdx = genericParams.size();
(currentGenericParamIdx != lastGenericParamIdx &&
genericParams[currentGenericParamIdx]->getDepth() == depth);
++currentGenericParamIdx) {
Type replacementType = replacements[currentGenericParamIdx];
if (replacementType->hasArchetype())
replacementType = replacementType->mapTypeOutOfContext();

appendType(replacementType);
}
}
}

return currentGenericParamIdx;
}

void ASTMangler::appendBoundGenericArgs(Type type, bool &isFirstArgList) {
BoundGenericType *boundType = nullptr;
if (auto *unboundType = type->getAs<UnboundGenericType>()) {
TypeBase *typePtr = type.getPointer();
ArrayRef<Type> genericArgs;
if (auto *typeAlias = dyn_cast<NameAliasType>(typePtr)) {
appendBoundGenericArgs(typeAlias->getDecl(),
typeAlias->getSubstitutionMap(),
isFirstArgList);
return;
}

if (auto *unboundType = dyn_cast<UnboundGenericType>(typePtr)) {
if (Type parent = unboundType->getParent())
appendBoundGenericArgs(parent, isFirstArgList);
} else if (auto *nominalType = type->getAs<NominalType>()) {
} else if (auto *nominalType = dyn_cast<NominalType>(typePtr)) {
if (Type parent = nominalType->getParent())
appendBoundGenericArgs(parent, isFirstArgList);
} else {
boundType = type->castTo<BoundGenericType>();
auto boundType = cast<BoundGenericType>(typePtr);
genericArgs = boundType->getGenericArgs();
if (Type parent = boundType->getParent())
appendBoundGenericArgs(parent, isFirstArgList);
}
Expand All @@ -1058,10 +1116,8 @@ void ASTMangler::appendBoundGenericArgs(Type type, bool &isFirstArgList) {
} else {
appendOperator("_");
}
if (boundType) {
for (Type arg : boundType->getGenericArgs()) {
appendType(arg);
}
for (Type arg : genericArgs) {
appendType(arg);
}
}

Expand Down
9 changes: 4 additions & 5 deletions lib/Demangling/OldRemangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1243,11 +1243,7 @@ void Remangler::mangleBuiltinTypeName(Node *node) {
}

void Remangler::mangleTypeAlias(Node *node, EntityContext &ctx) {
SubstitutionEntry entry;
if (trySubstitution(node, entry)) return;
Out << 'a';
mangleChildNodes(node); // context, identifier
addSubstitution(entry);
mangleAnyNominalType(node, ctx);
}

void Remangler::mangleFunctionType(Node *node) {
Expand Down Expand Up @@ -1824,6 +1820,9 @@ void Remangler::mangleAnyNominalType(Node *node, EntityContext &ctx) {
case Node::Kind::Class:
mangleNominalType(node, 'C', ctx);
break;
case Node::Kind::TypeAlias:
mangleNominalType(node, 'a', ctx);
break;
default:
unreachable("bad nominal type kind");
}
Expand Down
7 changes: 5 additions & 2 deletions lib/Demangling/Remangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -248,10 +248,10 @@ class Remangler {
}

void manglePureProtocol(Node *Proto) {
Proto = skipType(Proto);
if (mangleStandardSubstitution(Proto))
return;

Proto = skipType(Proto);
mangleChildNodes(Proto);
}

Expand Down Expand Up @@ -474,6 +474,7 @@ void Remangler::mangleGenericArgs(Node *node, char &Separator) {
case Node::Kind::Structure:
case Node::Kind::Enum:
case Node::Kind::Class:
case Node::Kind::TypeAlias:
mangleGenericArgs(node->getChild(0), Separator);
Buffer << Separator;
Separator = '_';
Expand Down Expand Up @@ -1712,7 +1713,7 @@ void Remangler::mangleType(Node *node) {
}

void Remangler::mangleTypeAlias(Node *node) {
mangleAnyGenericType(node, "a");
mangleAnyNominalType(node);
}

void Remangler::mangleTypeList(Node *node) {
Expand Down Expand Up @@ -2057,6 +2058,7 @@ bool Demangle::isSpecialized(Node *node) {
case Node::Kind::Structure:
case Node::Kind::Enum:
case Node::Kind::Class:
case Node::Kind::TypeAlias:
case Node::Kind::OtherNominalType:
return isSpecialized(node->getChild(0));

Expand All @@ -2073,6 +2075,7 @@ NodePointer Demangle::getUnspecialized(Node *node, NodeFactory &Factory) {
case Node::Kind::Structure:
case Node::Kind::Enum:
case Node::Kind::Class:
case Node::Kind::TypeAlias:
case Node::Kind::OtherNominalType: {
NodePointer result = Factory.createNode(node->getKind());
NodePointer parentOrModule = node->getChild(0);
Expand Down
22 changes: 20 additions & 2 deletions lib/IDE/TypeReconstruction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -772,13 +772,31 @@ static void VisitNodeGenericTypealias(ASTContext *ast,
}

if (generic_type_result._decls.size() != 1 ||
generic_type_result._types.size() != 1 ||
template_types_result._types.empty())
generic_type_result._types.size() != 1)
return;

auto *genericTypeAlias =
cast<TypeAliasDecl>(generic_type_result._decls.front());
GenericSignature *signature = genericTypeAlias->getGenericSignature();
if (signature &&
template_types_result._types.size() !=
signature->getGenericParams().size()) {
result._error = stringWithFormat(
"wrong number of generic arguments (%d) for generic typealias %s; "
"expected %d",
template_types_result._types.size(),
genericTypeAlias->getBaseName().userFacingName(),
signature->getGenericParams().size());

return;
}

if (signature && signature->getNumConformanceRequirements() != 0) {
result._error =
"cannot handle generic typealias with conformance requirements";
return;
}

// FIXME: handle conformances.
SubstitutionMap subMap;
if (signature)
Expand Down
19 changes: 19 additions & 0 deletions test/DebugInfo/DumpDeclFromMangledName.swift
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,25 @@ class Foo<T> {

typealias Patatino<T> = Foo<T>

public struct Outer<T> {
public struct Inner { }
public struct GenericInner<U> { }

public typealias Foo<U> = Outer<U>.Inner

public func blah() {
let foo: Foo<Int> = Outer<Int>.Inner()
}
}

extension Outer.GenericInner {
public typealias Bar = Int

public func useBar() {
let bar: Bar = 7
}
}

func main() -> Int {
var p : Patatino<Int> = Patatino(23);
return 0
Expand Down
10 changes: 10 additions & 0 deletions test/DebugInfo/DumpTypeFromMangledName.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,16 @@ class Foo<T> {

typealias Patatino<T> = Foo<T>

public struct Outer<T> {
public struct Inner { }

public typealias Foo<U> = Outer<U>.Inner

public func blah() {
let foo: Foo<Int> = Outer<Int>.Inner()
}
}

func main() -> Int {
struct patatino {}
var p : Patatino<Int> = Patatino(23);
Expand Down
2 changes: 2 additions & 0 deletions test/DebugInfo/Inputs/decl-reconstr-names.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
$S12DeclReconstr8patatinoSiyF ---> func patatino() -> Int
$S12DeclReconstr1SVACycfC ---> init()
$S12DeclReconstr8PatatinoaySiGD ---> typealias Patatino<T> = Foo<T>
$S12DeclReconstr5OuterV3Fooayx_SiGD ---> Can't resolve decl of $S12DeclReconstr5OuterV3Fooayx_SiGD
$S12DeclReconstr5OuterV12GenericInnerV3Barayx_qd___GD ---> typealias Bar = Int
1 change: 1 addition & 0 deletions test/DebugInfo/Inputs/type-reconstr-names.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ $SSayypXpG ---> Array<Any.Type>
$S12EyeCandyCore11XPCListenerC14messageHandleryyAA13XPCConnectionV_AA10XPCMessageVxtcvpfiyAF_AHxtcfU_TA.4 ---> Can't resolve type of $S12EyeCandyCore11XPCListenerC14messageHandleryyAA13XPCConnectionV_AA10XPCMessageVxtcvpfiyAF_AHxtcfU_TA.4
$Ss10CollectionP7ElementQa ---> Can't resolve type of $Ss10CollectionP7ElementQa
$S12TypeReconstr8patatinoayAA5tinkyVGSgD ---> Optional<patatino>
$S12TypeReconstr5OuterV3Fooayx_SiGD ---> Can't resolve type of $S12TypeReconstr5OuterV3Fooayx_SiGD
Copy link
Contributor

Choose a reason for hiding this comment

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

Why is this invalid?

Copy link
Member Author

Choose a reason for hiding this comment

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

"This is a hack to avoid crashing; a more complete fix requires deeper changes to the type reconstruction logic."

Copy link
Member Author

Choose a reason for hiding this comment

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

We need to do the thing where we pull out all of the generic argument lists from the "parent" type and put them together.

6 changes: 4 additions & 2 deletions test/Demangle/Inputs/manglings.txt
Original file line number Diff line number Diff line change
Expand Up @@ -313,5 +313,7 @@ _$S3BBBBf0602365061_ ---> _$S3BBBBf0602365061_
_$S3BBBBi0602365061_ ---> _$S3BBBBi0602365061_
_$S3BBBBv0602365061_ ---> _$S3BBBBv0602365061_
_T0lxxxmmmTk ---> _T0lxxxmmmTk
$S4blah8PatatinoaySiGD -> blah.Patatino<Swift.Int>

$S4blah8PatatinoaySiGD ---> blah.Patatino<Swift.Int>
$SSiSHsWP ---> protocol witness table for Swift.Int : Swift.Hashable in Swift
$S7TestMod5OuterV3Fooayx_SiGD ---> TestMod.Outer<A>.Foo<Swift.Int>
$Ss17_VariantSetBufferO05CocoaC0ayx_GD ---> Swift._VariantSetBuffer<A>.CocoaBuffer
2 changes: 1 addition & 1 deletion test/SILOptimizer/array_contentof_opt.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public func testThreeInts(_ a: inout [Int]) {

// CHECK-LABEL: sil @{{.*}}testTooManyInts
// CHECK-NOT: apply
// CHECK: [[F:%[0-9]+]] = function_ref @$SSa6append10contentsOfyqd___t7ElementQyd__Rszs8SequenceRd__lFSi_SaySiGTg5
// CHECK: [[F:%[0-9]+]] = function_ref @$SSa6append10contentsOfyqd___t7ElementQyd__RszSTRd__lFSi_SaySiGTg5
// CHECK-NOT: apply
// CHECK: apply [[F]]
// CHECK-NOT: apply
Expand Down
4 changes: 2 additions & 2 deletions test/SILOptimizer/eager_specialize.sil
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ bb2:
}

// specialized divideNum<A where ...> (A, den : A) throws -> A
// CHECK-LABEL: sil shared @$S16eager_specialize9divideNum_3denxx_xtKs13SignedIntegerRzlFSi_Tg5 : $@convention(thin) (Int, Int) -> (Int, @error Error) {
// CHECK-LABEL: sil shared @$S16eager_specialize9divideNum_3denxx_xtKSZRzlFSi_Tg5 : $@convention(thin) (Int, Int) -> (Int, @error Error) {
// CHECK: bb0(%0 : $Int, %1 : $Int):
// CHECK: return %{{.*}}
// CHECK: throw %{{.*}}
Expand Down Expand Up @@ -224,7 +224,7 @@ bb2:
// CHECK: %{{.*}} = unchecked_addr_cast %2 : $*T to $*Int
// CHECK: %{{.*}} = load %{{.*}} : $*Int
// CHECK: // function_ref specialized divideNum<A>(_:den:)
// CHECK: %{{.*}} = function_ref @$S16eager_specialize9divideNum_3denxx_xtKs13SignedIntegerRzlFSi_Tg5 : $@convention(thin) (Int, Int) -> (Int, @error Error)
// CHECK: %{{.*}} = function_ref @$S16eager_specialize9divideNum_3denxx_xtKSZRzlFSi_Tg5 : $@convention(thin) (Int, Int) -> (Int, @error Error)
// CHECK: try_apply %{{.*}}(%{{.*}}, %{{.*}}) : $@convention(thin) (Int, Int) -> (Int, @error Error), normal bb8, error bb7

// CHECK: bb7(%{{.*}} : $Error):
Expand Down
7 changes: 7 additions & 0 deletions tools/lldb-moduleimport-test/lldb-moduleimport-test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,9 @@ int main(int argc, char **argv) {
llvm::cl::opt<std::string> DumpTypeFromMangled(
"type-from-mangled", llvm::cl::desc("dump type from mangled names list"));

llvm::cl::opt<std::string> ResourceDir("resource-dir",
llvm::cl::desc("The directory that holds the compiler resource files"));

llvm::cl::ParseCommandLineOptions(argc, argv);
// Unregister our options so they don't interfere with the command line
// parsing in CodeGen/BackendUtil.cpp.
Expand Down Expand Up @@ -254,6 +257,10 @@ int main(int argc, char **argv) {
Invocation.setModuleName("lldbtest");
Invocation.getClangImporterOptions().ModuleCachePath = ModuleCachePath;

if (!ResourceDir.empty()) {
Invocation.setRuntimeResourcePath(ResourceDir);
Copy link
Member

Choose a reason for hiding this comment

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

Do you need this for testing? [If so, can you add a test for this].

Copy link
Member Author

Choose a reason for hiding this comment

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

It's for debugging: I often use a Debug compiler with a standard library that was build with a Release+Asserts compiler, because the latter builds the standard library so much faster. Testing doesn't need this.

Copy link
Member

Choose a reason for hiding this comment

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

OK, makes sense, thanks!

}

if (CI.setup(Invocation))
return 1;

Expand Down