Hi compiler experts,
I'm wondering how to check (in a SIL transform) whether a conformance requirement with a DependentMemberType
lhs type is satisfied either in a given SubstitutionMap
or in a given module.
Context is the following program. 1 shows the array of Requirement
s and 2 shows the substitution map. The "given module" is the current module.
// In stdlib:
// protocol Differentiable {
// associatedtype TangentVector: Differentiable & AdditiveArithmetic
// where ...
// }
protocol MyProtocol {
associatedtype Scalar
}
extension MyProtocol where Scalar : FloatingPoint {
// 1. `@differentiable` attribute declares an array of `Requirement`s in
// a trailing where clause.
//
// Relevant to the question: the `Self.TangentVector : MyProtocol`
// requirement is a conformance requirement, where the lhs
// `Self.TangentVector` is a `DependentMemberType` type:
//
// (dependent_member_type assoc_type=Swift.(file).Differentiable.TangentVector
// (base=generic_type_param_type depth=0 index=0 decl=main.(file).MyProtocol extension.Self))
@differentiable(
where Self : Differentiable, Scalar : Differentiable,
Self.TangentVector : MyProtocol
)
static func +(lhs: Self, rhs: Self) -> Self { ... }
}
struct Dummy<Scalar> : MyProtocol {}
extension Dummy : Differentiable where Scalar : Differentiable {
typealias TangentVector = Dummy
}
let fn = { (x: Dummy<Float>) -> Dummy<Float> in
// 2. Here, I need to check that the requirements declared in the
// `@differentiable` attribute above are met.
//
// I have access to the substitution map of the `apply` instruction
// corresponding to the `+` application:
//
// (substitution_map generic_signature=<τ_0_0 where τ_0_0 : MyProtocol, τ_0_0.Scalar : FloatingPoint>
// (substitution τ_0_0 -> Dummy<Float>)
// (conformance type=τ_0_0
// (specialized_conformance type=Dummy<Float> protocol=MyProtocol
// (substitution_map generic_signature=<τ_0_0>
// (substitution τ_0_0 -> Float))
// (conditional requirements unable to be computed)
// (normal_conformance type=Dummy<Scalar> protocol=MyProtocol
// (assoc_type req=Scalar type=Scalar))))
// (conformance type=τ_0_0.Scalar
// (normal_conformance type=Float protocol=FloatingPoint lazy)))
return x + x
}
Reposting the key information: how can I check whether the Self.TangentVector : MyProtocol
conformance requirement, whose LHS is a DependentMemberType
:
(dependent_member_type assoc_type=Swift.(file).Differentiable.TangentVector
(base=generic_type_param_type depth=0 index=0 decl=main.(file).MyProtocol extension.Self))
Is satisfied given the current module and the following substitution map?
(substitution_map generic_signature=<τ_0_0 where τ_0_0 : MyProtocol, τ_0_0.Scalar : FloatingPoint>
(substitution τ_0_0 -> Dummy<Float>)
(conformance type=τ_0_0
(specialized_conformance type=Dummy<Float> protocol=MyProtocol
(substitution_map generic_signature=<τ_0_0>
(substitution τ_0_0 -> Float))
(conditional requirements unable to be computed)
(normal_conformance type=Dummy<Scalar> protocol=MyProtocol
(assoc_type req=Scalar type=Scalar))))
(conformance type=τ_0_0.Scalar
(normal_conformance type=Float protocol=FloatingPoint lazy)))
Intuitively, the requirement is satisfied: Dummy<Float>
conforms to Differentiable
and Dummy<Float>.TangentVector
is equal to Dummy<Float>
and also conforms to Differentiable
.
However, the conformance of Dummy<Float>
to Differentiable
is missing from the substitution map, and it's not clear how to remap τ_0_0
from the substitution map to Self
in the conformance requirement in a robust way.
Here's the current hacky logic for checking this requirement: it calls DependentMemberType:: substBaseType
on the first replacement type in the substitution map, if the substitution map has only one replacement type (acting as Self
). It's not robust, and the entire checkRequirementsSatisfied
function can likely be improved.
Any advice would be greatly appreciated!