diff --git a/lib/IRGen/GenProto.cpp b/lib/IRGen/GenProto.cpp index 11f6d6b7f38ac..5b2da9134c529 100644 --- a/lib/IRGen/GenProto.cpp +++ b/lib/IRGen/GenProto.cpp @@ -2351,23 +2351,39 @@ void irgen::emitWitnessTableRefs(IRGenFunction &IGF, } } -static CanType getSubstSelfType(CanSILFunctionType substFnType) { +static CanType getSubstSelfType(CanSILFunctionType origFnType, + ArrayRef subs) { // Grab the apparent 'self' type. If there isn't a 'self' type, // we're not going to try to access this anyway. - assert(!substFnType->getParameters().empty()); + assert(!origFnType->getParameters().empty()); - auto selfParam = substFnType->getParameters().back(); - CanType substInputType = selfParam.getType(); + auto selfParam = origFnType->getParameters().back(); + CanType inputType = selfParam.getType(); // If the parameter is a direct metatype parameter, this is a static method // of the instance type. We can assume this because: // - metatypes cannot directly conform to protocols // - even if they could, they would conform as a value type 'self' and thus // be passed indirectly as an @in or @inout parameter. - if (auto meta = dyn_cast(substInputType)) { + if (auto meta = dyn_cast(inputType)) { if (!selfParam.isIndirect()) - substInputType = meta.getInstanceType(); + inputType = meta.getInstanceType(); } - return substInputType; + + // Substitute the `self` type. + // FIXME: This has to be done as a formal AST type substitution rather than + // a SIL function type substitution, because some nominal types (viz + // Optional) have type lowering recursively applied to their type parameters. + // Substituting into the original lowered function type like this is still + // problematic if we ever allow methods or protocol conformances on structural + // types; we'd really need to separately record the formal Self type in the + // SIL function type to make that work, which could be managed by having a + // "substituted generic signature" concept. + if (!subs.empty()) { + auto subMap = origFnType->getGenericSignature()->getSubstitutionMap(subs); + inputType = inputType.subst(subMap)->getCanonicalType(); + } + + return inputType; } namespace { @@ -2382,7 +2398,7 @@ namespace { WitnessMetadata *witnessMetadata, Explosion &out); private: - void emitEarlySources(CanSILFunctionType substFnType, Explosion &out) { + void emitEarlySources(ArrayRef subs, Explosion &out) { for (auto &source : getSources()) { switch (source.getKind()) { // Already accounted for in the parameters. @@ -2392,7 +2408,7 @@ namespace { // Needs a special argument. case MetadataSource::Kind::GenericLValueMetadata: { - out.add(IGF.emitTypeMetadataRef(getSubstSelfType(substFnType))); + out.add(IGF.emitTypeMetadataRef(getSubstSelfType(FnType, subs))); continue; } @@ -2424,7 +2440,7 @@ void EmitPolymorphicArguments::emit(CanSILFunctionType substFnType, WitnessMetadata *witnessMetadata, Explosion &out) { // Add all the early sources. - emitEarlySources(substFnType, out); + emitEarlySources(subs, out); // For now, treat all archetypes independently. enumerateUnfulfilledRequirements([&](GenericRequirement requirement) { @@ -2448,7 +2464,7 @@ void EmitPolymorphicArguments::emit(CanSILFunctionType substFnType, case MetadataSource::Kind::SelfMetadata: { assert(witnessMetadata && "no metadata structure for witness method"); - auto self = IGF.emitTypeMetadataRef(getSubstSelfType(substFnType)); + auto self = IGF.emitTypeMetadataRef(getSubstSelfType(FnType, subs)); witnessMetadata->SelfMetadata = self; continue; } @@ -2508,11 +2524,11 @@ NecessaryBindings::forFunctionInvocations(IRGenModule &IGM, continue; case MetadataSource::Kind::GenericLValueMetadata: - bindings.addTypeMetadata(getSubstSelfType(substType)); + bindings.addTypeMetadata(getSubstSelfType(origType, subs)); continue; case MetadataSource::Kind::SelfMetadata: - bindings.addTypeMetadata(getSubstSelfType(substType)); + bindings.addTypeMetadata(getSubstSelfType(origType, subs)); continue; case MetadataSource::Kind::SelfWitnessTable: diff --git a/test/IRGen/lowered_optional_self_metadata.sil b/test/IRGen/lowered_optional_self_metadata.sil new file mode 100644 index 0000000000000..c8111b8753496 --- /dev/null +++ b/test/IRGen/lowered_optional_self_metadata.sil @@ -0,0 +1,23 @@ +// RUN: %target-swift-frontend -emit-ir %s +sil_stage canonical + +import Swift + +// SR-3021: Ensure we pass the Self type metadata for Optional methods using the +// formal Optional type and not a lowered SIL type. + +// CHECK-LABEL: @_TMaGSqFT_T__ + +sil @optional_method : $@convention(method) (@in_guaranteed Optional) -> () +sil @optional_witness_method : $@convention(witness_method) (@in_guaranteed Optional) -> () + +sil @call_optional_method_with_lowered_function : $@convention(thin) (@in_guaranteed Optional<@callee_owned (@in ()) -> @out ()>) -> () { +entry(%x : $*Optional<@callee_owned (@in ()) -> @out ()>): + %f = function_ref @optional_method : $@convention(method) (@in_guaranteed Optional) -> () + apply %f<() -> ()>(%x) : $@convention(method) (@in_guaranteed Optional) -> () + %g = function_ref @optional_witness_method : $@convention(witness_method) (@in_guaranteed Optional) -> () + apply %g<() -> ()>(%x) : $@convention(witness_method) (@in_guaranteed Optional) -> () + %p = partial_apply %f<() -> ()>() : $@convention(method) (@in_guaranteed Optional) -> () + %q = partial_apply %g<() -> ()>() : $@convention(witness_method) (@in_guaranteed Optional) -> () + return undef : $() +}