Skip to content

SILGen: Properly calculate substitutions to invoke _bridgeToObjectiveC. #4990

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 1 commit into from
Sep 26, 2016
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
48 changes: 45 additions & 3 deletions lib/SILGen/SILGenBridging.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "swift/AST/AST.h"
#include "swift/AST/DiagnosticsSIL.h"
#include "swift/AST/ForeignErrorConvention.h"
#include "swift/AST/GenericEnvironment.h"
#include "swift/AST/ParameterList.h"
#include "swift/Basic/Fallthrough.h"
#include "swift/SIL/SILArgument.h"
Expand Down Expand Up @@ -61,9 +62,50 @@ emitBridgeNativeToObjectiveC(SILGenFunction &gen,
auto witnessFnTy = witnessRef->getType();

// Compute the substitutions.
ArrayRef<Substitution> substitutions =
swiftValueType->gatherAllSubstitutions(
gen.SGM.SwiftModule, nullptr);
ArrayRef<Substitution> witnessSubstitutions = witness.getSubstitutions();
Copy link
Contributor

Choose a reason for hiding this comment

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

This is pretty epic -- I wanted to clean up witness substitutions at some point since I've got a few changes that are blocked on representation issues, and this provides even more motivation.

ArrayRef<Substitution> typeSubstitutions =
swiftValueType->gatherAllSubstitutions(gen.SGM.SwiftModule, nullptr);

// FIXME: Methods of generic types don't have substitutions in their
// ConcreteDeclRefs for some reason. Furthermore,
// SubsitutedProtocolConformances don't substitute their witness
// ConcreteDeclRefs, so we need to do it ourselves.
ArrayRef<Substitution> substitutions;
SmallVector<Substitution, 4> substitutionsBuf;
if (typeSubstitutions.empty()) {
substitutions = witnessSubstitutions;
} else if (witnessSubstitutions.empty()) {
substitutions = typeSubstitutions;
} else {
// FIXME: The substitutions in a witness ConcreteDeclRef really ought to
// be interface types. Instead, we get archetypes from a generic environment
// that's either the extension method's generic environment, for a witness
// from a nominal extension, or the conforming type's original declaration
// generic environment, for a witness from a protocol extension.
auto swiftValueTypeDecl = swiftValueType->getAnyNominal();
GenericEnvironment *witnessEnv;
GenericSignature *witnessSig;

if (witness.getDecl()->getDeclContext()->getDeclaredTypeOfContext()
Copy link
Contributor

Choose a reason for hiding this comment

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

getMemberSubstitutions() does the right thing for a member of a protocol vs member of a concrete type (it takes a base and a DC for the member), but this is fine for now.

->isExistentialType()) {
witnessEnv = swiftValueTypeDecl->getGenericEnvironment();
witnessSig = swiftValueTypeDecl->getGenericSignature();
} else {
witnessEnv = witness.getDecl()->getDeclContext()
->getGenericEnvironmentOfContext();
witnessSig = witness.getDecl()->getDeclContext()
->getGenericSignatureOfContext();
}

SubstitutionMap typeSubMap = witnessEnv
->getSubstitutionMap(gen.SGM.SwiftModule,
witnessSig,
typeSubstitutions);
for (auto sub : witnessSubstitutions) {
substitutionsBuf.push_back(sub.subst(gen.SGM.SwiftModule, typeSubMap));
}
substitutions = substitutionsBuf;
}

if (!substitutions.empty()) {
// Substitute into the witness function type.
Expand Down
56 changes: 56 additions & 0 deletions test/SILGen/objc_bridged_using_protocol_extension_impl.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -emit-silgen %s | %FileCheck %s
// REQUIRES: objc_interop

import Foundation

protocol Fooable {}

extension Fooable where Self: _ObjectiveCBridgeable {
func _bridgeToObjectiveC() -> _ObjectiveCType {
fatalError()
}

static func _forceBridgeFromObjectiveC(
_ source: _ObjectiveCType,
result: inout Self?
) {
fatalError()
}

static func _conditionallyBridgeFromObjectiveC(
_ source: _ObjectiveCType,
result: inout Self?
) -> Bool {
fatalError()
}

static func _unconditionallyBridgeFromObjectiveC(_ source: _ObjectiveCType?)
-> Self {
fatalError()
}
}

struct Foo: Fooable, _ObjectiveCBridgeable {
typealias _ObjectiveCType = NSObject
}
struct Gen<T, U>: Fooable, _ObjectiveCBridgeable {
typealias _ObjectiveCType = NSObject
}

class Bar: NSObject {
dynamic func bar(_: Any) {}
}

// CHECK-LABEL: sil hidden @_TF42objc_bridged_using_protocol_extension_impl7callBarFT3barCS_3Bar3fooVS_3Foo_T_
func callBar(bar: Bar, foo: Foo) {
// CHECK: [[BRIDGE:%.*]] = function_ref @_TFe42objc_bridged_using_protocol_extension_implRxs21_ObjectiveCBridgeablexS_7FooablerS1_19_bridgeToObjectiveCfT_wxPS0_15_ObjectiveCType
// CHECK: apply [[BRIDGE]]<Foo, NSObject>
bar.bar(foo)
}

// CHECK-LABEL:sil hidden @_TF42objc_bridged_using_protocol_extension_impl7callBarFT3barCS_3Bar3genGVS_3GenSiSS__T_
func callBar(bar: Bar, gen: Gen<Int, String>) {
// CHECK: [[BRIDGE:%.*]] = function_ref @_TFe42objc_bridged_using_protocol_extension_implRxs21_ObjectiveCBridgeablexS_7FooablerS1_19_bridgeToObjectiveCfT_wxPS0_15_ObjectiveCType
// CHECK: apply [[BRIDGE]]<Gen<Int, String>, NSObject>
bar.bar(gen)
}