mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Runtime: Fix runtime type resolution when mangled names refer to protocol extensions with Self same type constraints.
If a type or opaque type descriptor appears inside of a protocol extension of the form:
```
extension P where Self == Nominal { ... }
```
then the runtime representation of the extension context was interpreted by the runtime
demangler as a nominal type extension, even though the parameterization is on the
`<Self>` generic signature of the protocol extension and not the generic signature of
the nominal type. This would cause spurious rejection of mangled names referencing the
extension context because we mistakenly thought that the type arguments mismatched with
the nominal type signature rather than matching them to the extension context.
Add some code to `_findExtendedTypeContextDescriptor` to detect when an extension is
a protocol extension with a `Self == SameType` constraint, and pass the extension along
rather than treating it as a nominal type extension. Fixes rdar://130168101.
This commit is contained in:
@@ -402,6 +402,38 @@ _findExtendedTypeContextDescriptor(const ContextDescriptor *maybeExtension,
|
||||
Demangle::NodePointer &node = demangledNode ? *demangledNode : localNode;
|
||||
|
||||
auto mangledName = extension->getMangledExtendedContext();
|
||||
|
||||
// A extension of the form `extension Protocol where Self == ConcreteType`
|
||||
// is formally a protocol extension, so the formal generic parameter list
|
||||
// is `<Self>`, but because of the same type constraint, the extended context
|
||||
// looks like a reference to that nominal type. We want to match the
|
||||
// extension's formal generic environment rather than the nominal type's
|
||||
// in this case, so we should skip out on this case.
|
||||
//
|
||||
// We can detect this by looking at whether the generic context of the
|
||||
// extension has a first generic parameter, which would be the Self parameter,
|
||||
// with a same type constraint matching the extended type.
|
||||
for (auto &reqt : extension->getGenericRequirements()) {
|
||||
if (reqt.getKind() != GenericRequirementKind::SameType) {
|
||||
continue;
|
||||
}
|
||||
// 'x' is the mangling of the first generic parameter
|
||||
if (!reqt.getParam().equals("x")) {
|
||||
continue;
|
||||
}
|
||||
// Is the generic parameter same-type-constrained to the same type
|
||||
// we're extending? Then this is a `Self == ExtendedType` constraint.
|
||||
// This is impossible for normal generic nominal type extensions because
|
||||
// that would mean that you had:
|
||||
// struct Foo<T> {...}
|
||||
// extension Foo where T == Foo<T> {...}
|
||||
// which would mean that the extended type is the infinite expansion
|
||||
// Foo<Foo<Foo<Foo<...>>>>, which we don't allow.
|
||||
if (reqt.getMangledTypeName().data() == mangledName.data()) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
node = demangler.demangleType(mangledName,
|
||||
ResolveAsSymbolicReference(demangler));
|
||||
if (!node)
|
||||
@@ -1254,7 +1286,8 @@ _gatherGenericParameters(const ContextDescriptor *context,
|
||||
(void)_gatherGenericParameterCounts(context,
|
||||
genericParamCounts, demangler);
|
||||
unsigned numTotalGenericParams =
|
||||
genericParamCounts.empty() ? 0 : genericParamCounts.back();
|
||||
genericParamCounts.empty() ? context->getNumGenericParams()
|
||||
: genericParamCounts.back();
|
||||
|
||||
// Check whether we have the right number of generic arguments.
|
||||
if (genericArgs.size() == getLocalGenericParams(context).size()) {
|
||||
|
||||
27
test/Runtime/protocol_self_same_type_extension.swift
Normal file
27
test/Runtime/protocol_self_same_type_extension.swift
Normal file
@@ -0,0 +1,27 @@
|
||||
// RUN: %target-run-simple-swift | %FileCheck %s
|
||||
// REQUIRES: executable_test
|
||||
// UNSUPPORTED: use_os_stdlib
|
||||
// UNSUPPORTED: back_deployment_runtime
|
||||
|
||||
// rdar://130168101: Make sure that we correctly resolve types in
|
||||
// the generic context of a protocol extension with a `Self` same
|
||||
// type constraint.
|
||||
|
||||
|
||||
protocol P { }
|
||||
|
||||
struct P2: P { }
|
||||
|
||||
extension P where Self == P2 {
|
||||
@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
|
||||
dynamic func p2() -> some P {
|
||||
return self
|
||||
}
|
||||
}
|
||||
|
||||
// CHECK: P2()
|
||||
if #available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) {
|
||||
print(P2().p2())
|
||||
} else {
|
||||
print(P2())
|
||||
}
|
||||
Reference in New Issue
Block a user