Skip to content

Commit fa885d7

Browse files
authored
Merge pull request #5492 from jckarter/lowered-optional-metadata
2 parents ed2105c + 2c6b472 commit fa885d7

File tree

2 files changed

+52
-13
lines changed

2 files changed

+52
-13
lines changed

lib/IRGen/GenProto.cpp

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2356,23 +2356,39 @@ void irgen::emitWitnessTableRefs(IRGenFunction &IGF,
23562356
}
23572357
}
23582358

2359-
static CanType getSubstSelfType(CanSILFunctionType substFnType) {
2359+
static CanType getSubstSelfType(CanSILFunctionType origFnType,
2360+
ArrayRef<Substitution> subs) {
23602361
// Grab the apparent 'self' type. If there isn't a 'self' type,
23612362
// we're not going to try to access this anyway.
2362-
assert(!substFnType->getParameters().empty());
2363+
assert(!origFnType->getParameters().empty());
23632364

2364-
auto selfParam = substFnType->getParameters().back();
2365-
CanType substInputType = selfParam.getType();
2365+
auto selfParam = origFnType->getParameters().back();
2366+
CanType inputType = selfParam.getType();
23662367
// If the parameter is a direct metatype parameter, this is a static method
23672368
// of the instance type. We can assume this because:
23682369
// - metatypes cannot directly conform to protocols
23692370
// - even if they could, they would conform as a value type 'self' and thus
23702371
// be passed indirectly as an @in or @inout parameter.
2371-
if (auto meta = dyn_cast<MetatypeType>(substInputType)) {
2372+
if (auto meta = dyn_cast<MetatypeType>(inputType)) {
23722373
if (!selfParam.isIndirect())
2373-
substInputType = meta.getInstanceType();
2374+
inputType = meta.getInstanceType();
23742375
}
2375-
return substInputType;
2376+
2377+
// Substitute the `self` type.
2378+
// FIXME: This has to be done as a formal AST type substitution rather than
2379+
// a SIL function type substitution, because some nominal types (viz
2380+
// Optional) have type lowering recursively applied to their type parameters.
2381+
// Substituting into the original lowered function type like this is still
2382+
// problematic if we ever allow methods or protocol conformances on structural
2383+
// types; we'd really need to separately record the formal Self type in the
2384+
// SIL function type to make that work, which could be managed by having a
2385+
// "substituted generic signature" concept.
2386+
if (!subs.empty()) {
2387+
auto subMap = origFnType->getGenericSignature()->getSubstitutionMap(subs);
2388+
inputType = inputType.subst(subMap)->getCanonicalType();
2389+
}
2390+
2391+
return inputType;
23762392
}
23772393

23782394
namespace {
@@ -2387,7 +2403,7 @@ namespace {
23872403
WitnessMetadata *witnessMetadata, Explosion &out);
23882404

23892405
private:
2390-
void emitEarlySources(CanSILFunctionType substFnType, Explosion &out) {
2406+
void emitEarlySources(ArrayRef<Substitution> subs, Explosion &out) {
23912407
for (auto &source : getSources()) {
23922408
switch (source.getKind()) {
23932409
// Already accounted for in the parameters.
@@ -2397,7 +2413,7 @@ namespace {
23972413

23982414
// Needs a special argument.
23992415
case MetadataSource::Kind::GenericLValueMetadata: {
2400-
out.add(IGF.emitTypeMetadataRef(getSubstSelfType(substFnType)));
2416+
out.add(IGF.emitTypeMetadataRef(getSubstSelfType(FnType, subs)));
24012417
continue;
24022418
}
24032419

@@ -2429,7 +2445,7 @@ void EmitPolymorphicArguments::emit(CanSILFunctionType substFnType,
24292445
WitnessMetadata *witnessMetadata,
24302446
Explosion &out) {
24312447
// Add all the early sources.
2432-
emitEarlySources(substFnType, out);
2448+
emitEarlySources(subs, out);
24332449

24342450
// For now, treat all archetypes independently.
24352451
enumerateUnfulfilledRequirements([&](GenericRequirement requirement) {
@@ -2453,7 +2469,7 @@ void EmitPolymorphicArguments::emit(CanSILFunctionType substFnType,
24532469

24542470
case MetadataSource::Kind::SelfMetadata: {
24552471
assert(witnessMetadata && "no metadata structure for witness method");
2456-
auto self = IGF.emitTypeMetadataRef(getSubstSelfType(substFnType));
2472+
auto self = IGF.emitTypeMetadataRef(getSubstSelfType(FnType, subs));
24572473
witnessMetadata->SelfMetadata = self;
24582474
continue;
24592475
}
@@ -2513,11 +2529,11 @@ NecessaryBindings::forFunctionInvocations(IRGenModule &IGM,
25132529
continue;
25142530

25152531
case MetadataSource::Kind::GenericLValueMetadata:
2516-
bindings.addTypeMetadata(getSubstSelfType(substType));
2532+
bindings.addTypeMetadata(getSubstSelfType(origType, subs));
25172533
continue;
25182534

25192535
case MetadataSource::Kind::SelfMetadata:
2520-
bindings.addTypeMetadata(getSubstSelfType(substType));
2536+
bindings.addTypeMetadata(getSubstSelfType(origType, subs));
25212537
continue;
25222538

25232539
case MetadataSource::Kind::SelfWitnessTable:
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// RUN: %target-swift-frontend -emit-ir %s
2+
sil_stage canonical
3+
4+
import Swift
5+
6+
// SR-3021: Ensure we pass the Self type metadata for Optional methods using the
7+
// formal Optional type and not a lowered SIL type.
8+
9+
// CHECK-LABEL: @_TMaGSqFT_T__
10+
11+
sil @optional_method : $@convention(method) <T> (@in_guaranteed Optional<T>) -> ()
12+
sil @optional_witness_method : $@convention(witness_method) <T> (@in_guaranteed Optional<T>) -> ()
13+
14+
sil @call_optional_method_with_lowered_function : $@convention(thin) (@in_guaranteed Optional<@callee_owned (@in ()) -> @out ()>) -> () {
15+
entry(%x : $*Optional<@callee_owned (@in ()) -> @out ()>):
16+
%f = function_ref @optional_method : $@convention(method) <T> (@in_guaranteed Optional<T>) -> ()
17+
apply %f<() -> ()>(%x) : $@convention(method) <T> (@in_guaranteed Optional<T>) -> ()
18+
%g = function_ref @optional_witness_method : $@convention(witness_method) <T> (@in_guaranteed Optional<T>) -> ()
19+
apply %g<() -> ()>(%x) : $@convention(witness_method) <T> (@in_guaranteed Optional<T>) -> ()
20+
%p = partial_apply %f<() -> ()>() : $@convention(method) <T> (@in_guaranteed Optional<T>) -> ()
21+
%q = partial_apply %g<() -> ()>() : $@convention(witness_method) <T> (@in_guaranteed Optional<T>) -> ()
22+
return undef : $()
23+
}

0 commit comments

Comments
 (0)