Skip to content

Commit 2c6b472

Browse files
committed
IRGen: Derive the proper formal Self type for @convention(*method) methods on Optional.
Now that Optional's type parameter can be lowered, we can't make the assumption that a substituted nominal type in SIL is usable as-is as a formal type. At this moment, we can at least still rely on the fact that only nominals have methods, so we can at least go up to the original unsubstituted function type, extract the Self type from there, and do formal AST type substitution on it. This is still only a stopgap solution that wouldn't necessarily work once we start allowing conformances to be added to structural types, or even constrained extensions on Optional such as 'extension <T: class, U: class> Optional<(T) -> U>, but is good enough to fix SR-3021 for the language today. We would need something like the "substituted generic signature" concept to fully fix this.
1 parent d0581ea commit 2c6b472

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
@@ -2351,23 +2351,39 @@ void irgen::emitWitnessTableRefs(IRGenFunction &IGF,
23512351
}
23522352
}
23532353

2354-
static CanType getSubstSelfType(CanSILFunctionType substFnType) {
2354+
static CanType getSubstSelfType(CanSILFunctionType origFnType,
2355+
ArrayRef<Substitution> subs) {
23552356
// Grab the apparent 'self' type. If there isn't a 'self' type,
23562357
// we're not going to try to access this anyway.
2357-
assert(!substFnType->getParameters().empty());
2358+
assert(!origFnType->getParameters().empty());
23582359

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

23732389
namespace {
@@ -2382,7 +2398,7 @@ namespace {
23822398
WitnessMetadata *witnessMetadata, Explosion &out);
23832399

23842400
private:
2385-
void emitEarlySources(CanSILFunctionType substFnType, Explosion &out) {
2401+
void emitEarlySources(ArrayRef<Substitution> subs, Explosion &out) {
23862402
for (auto &source : getSources()) {
23872403
switch (source.getKind()) {
23882404
// Already accounted for in the parameters.
@@ -2392,7 +2408,7 @@ namespace {
23922408

23932409
// Needs a special argument.
23942410
case MetadataSource::Kind::GenericLValueMetadata: {
2395-
out.add(IGF.emitTypeMetadataRef(getSubstSelfType(substFnType)));
2411+
out.add(IGF.emitTypeMetadataRef(getSubstSelfType(FnType, subs)));
23962412
continue;
23972413
}
23982414

@@ -2424,7 +2440,7 @@ void EmitPolymorphicArguments::emit(CanSILFunctionType substFnType,
24242440
WitnessMetadata *witnessMetadata,
24252441
Explosion &out) {
24262442
// Add all the early sources.
2427-
emitEarlySources(substFnType, out);
2443+
emitEarlySources(subs, out);
24282444

24292445
// For now, treat all archetypes independently.
24302446
enumerateUnfulfilledRequirements([&](GenericRequirement requirement) {
@@ -2448,7 +2464,7 @@ void EmitPolymorphicArguments::emit(CanSILFunctionType substFnType,
24482464

24492465
case MetadataSource::Kind::SelfMetadata: {
24502466
assert(witnessMetadata && "no metadata structure for witness method");
2451-
auto self = IGF.emitTypeMetadataRef(getSubstSelfType(substFnType));
2467+
auto self = IGF.emitTypeMetadataRef(getSubstSelfType(FnType, subs));
24522468
witnessMetadata->SelfMetadata = self;
24532469
continue;
24542470
}
@@ -2508,11 +2524,11 @@ NecessaryBindings::forFunctionInvocations(IRGenModule &IGM,
25082524
continue;
25092525

25102526
case MetadataSource::Kind::GenericLValueMetadata:
2511-
bindings.addTypeMetadata(getSubstSelfType(substType));
2527+
bindings.addTypeMetadata(getSubstSelfType(origType, subs));
25122528
continue;
25132529

25142530
case MetadataSource::Kind::SelfMetadata:
2515-
bindings.addTypeMetadata(getSubstSelfType(substType));
2531+
bindings.addTypeMetadata(getSubstSelfType(origType, subs));
25162532
continue;
25172533

25182534
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)