@@ -7,7 +7,7 @@ use crate::{Db, FxOrderSet};
77
88impl < ' db > Type < ' db > {
99 pub ( crate ) fn instance ( db : & ' db dyn Db , class : ClassType < ' db > ) -> Self {
10- if class. is_protocol ( db) {
10+ if class. class_literal ( db ) . 0 . is_protocol ( db) {
1111 Self :: ProtocolInstance ( ProtocolInstanceType ( Protocol :: FromClass ( class) ) )
1212 } else {
1313 Self :: NominalInstance ( NominalInstanceType { class } )
@@ -20,6 +20,21 @@ impl<'db> Type<'db> {
2020 _ => None ,
2121 }
2222 }
23+
24+ /// Return `true` if `self` conforms to the interface described by `protocol`.
25+ pub ( super ) fn satisfies_protocol (
26+ self ,
27+ db : & ' db dyn Db ,
28+ protocol : ProtocolInstanceType < ' db > ,
29+ ) -> bool {
30+ // TODO: this should consider the types of the protocol members
31+ // as well as whether each member *exists* on `self`.
32+ protocol
33+ . 0
34+ . protocol_members ( db)
35+ . iter ( )
36+ . all ( |member| !self . member ( db, member) . symbol . is_unbound ( ) )
37+ }
2338}
2439
2540/// A type representing the set of runtime objects which are instances of a certain nominal class.
@@ -99,6 +114,8 @@ impl<'db> From<NominalInstanceType<'db>> for Type<'db> {
99114 }
100115}
101116
117+ /// A `ProtocolInstanceType` represents the set of all possible runtime objects
118+ /// that conform to the interface described by a certain protocol.
102119#[ derive( Copy , Clone , Debug , Eq , PartialEq , Hash , PartialOrd , Ord , salsa:: Update ) ]
103120pub struct ProtocolInstanceType < ' db > (
104121 // Keep the inner field here private,
@@ -108,14 +125,11 @@ pub struct ProtocolInstanceType<'db>(
108125) ;
109126
110127impl < ' db > ProtocolInstanceType < ' db > {
111- pub ( super ) fn protocol_members ( self , db : & ' db dyn Db ) -> & ' db FxOrderSet < Name > {
112- self . 0 . protocol_members ( db)
113- }
114-
115128 pub ( super ) fn inner ( self ) -> Protocol < ' db > {
116129 self . 0
117130 }
118131
132+ /// Return the meta-type of this protocol-instance type.
119133 pub ( super ) fn to_meta_type ( self , db : & ' db dyn Db ) -> Type < ' db > {
120134 match self . 0 {
121135 Protocol :: FromClass ( class) => SubclassOfType :: from ( db, class) ,
@@ -137,53 +151,68 @@ impl<'db> ProtocolInstanceType<'db> {
137151 }
138152 }
139153
154+ /// Return a "normalized" version of this `Protocol` type.
155+ ///
156+ /// See [`Type::normalized`] for more details.
140157 pub ( super ) fn normalized ( self , db : & ' db dyn Db ) -> Type < ' db > {
141158 let object = KnownClass :: Object . to_instance ( db) ;
142159 if object. satisfies_protocol ( db, self ) {
143160 return object;
144161 }
145162 match self . 0 {
146163 Protocol :: FromClass ( _) => Type :: ProtocolInstance ( Self ( Protocol :: Synthesized (
147- SynthesizedProtocolType :: new ( db, self . protocol_members ( db) ) ,
164+ SynthesizedProtocolType :: new ( db, self . 0 . protocol_members ( db) ) ,
148165 ) ) ) ,
149166 Protocol :: Synthesized ( _) => Type :: ProtocolInstance ( self ) ,
150167 }
151168 }
152169
153- /// TODO: should iterate over the types of the members
154- /// and check if any of them contain `Todo` types
170+ /// TODO: this should return `true` if any of the members of this protocol type contain any `Todo` types.
155171 #[ expect( clippy:: unused_self) ]
156172 pub ( super ) fn contains_todo ( self ) -> bool {
157173 false
158174 }
159175
176+ /// Return `true` if this protocol type is fully static.
177+ ///
160178 /// TODO: should not be considered fully static if any members do not have fully static types
161179 #[ expect( clippy:: unused_self) ]
162180 pub ( super ) fn is_fully_static ( self ) -> bool {
163181 true
164182 }
165183
184+ /// Return `true` if this protocol type is a subtype of the protocol `other`.
185+ ///
166186 /// TODO: consider the types of the members as well as their existence
167187 pub ( super ) fn is_subtype_of ( self , db : & ' db dyn Db , other : Self ) -> bool {
168- self . protocol_members ( db)
169- . is_superset ( other. protocol_members ( db) )
188+ self . 0
189+ . protocol_members ( db)
190+ . is_superset ( other. 0 . protocol_members ( db) )
170191 }
171192
193+ /// Return `true` if this protocol type is assignable to the protocol `other`.
194+ ///
172195 /// TODO: consider the types of the members as well as their existence
173196 pub ( super ) fn is_assignable_to ( self , db : & ' db dyn Db , other : Self ) -> bool {
174197 self . is_subtype_of ( db, other)
175198 }
176199
200+ /// Return `true` if this protocol type is equivalent to the protocol `other`.
201+ ///
177202 /// TODO: consider the types of the members as well as their existence
178203 pub ( super ) fn is_equivalent_to ( self , db : & ' db dyn Db , other : Self ) -> bool {
179204 self . normalized ( db) == other. normalized ( db)
180205 }
181206
207+ /// Return `true` if this protocol type is gradually equivalent to the protocol `other`.
208+ ///
182209 /// TODO: consider the types of the members as well as their existence
183210 pub ( super ) fn is_gradual_equivalent_to ( self , db : & ' db dyn Db , other : Self ) -> bool {
184211 self . is_equivalent_to ( db, other)
185212 }
186213
214+ /// Return `true` if this protocol type is disjoint from the protocol `other`.
215+ ///
187216 /// TODO: a protocol `X` is disjoint from a protocol `Y` if `X` and `Y`
188217 /// have a member with the same name but disjoint types
189218 #[ expect( clippy:: unused_self) ]
@@ -192,9 +221,8 @@ impl<'db> ProtocolInstanceType<'db> {
192221 }
193222}
194223
195- /// Private inner enum to represent the two kinds of protocol types.
196- /// This is not exposed publicly, so that the only way of constructing `Protocol` instances
197- /// is through the [`Type::instance`] constructor function.
224+ /// An enumeration of the two kinds of protocol types: those that originate from a class
225+ /// definition in source code, and those that are synthesized from a set of members.
198226#[ derive(
199227 Copy , Clone , Debug , Eq , PartialEq , Hash , salsa:: Update , salsa:: Supertype , PartialOrd , Ord ,
200228) ]
@@ -203,8 +231,8 @@ pub(super) enum Protocol<'db> {
203231 Synthesized ( SynthesizedProtocolType < ' db > ) ,
204232}
205233
206- #[ salsa:: tracked]
207234impl < ' db > Protocol < ' db > {
235+ /// Return the members of this protocol type
208236 fn protocol_members ( self , db : & ' db dyn Db ) -> & ' db FxOrderSet < Name > {
209237 match self {
210238 Self :: FromClass ( class) => class
@@ -218,6 +246,12 @@ impl<'db> Protocol<'db> {
218246 }
219247}
220248
249+ /// A "synthesized" protocol type that is dissociated from a class definition in source code.
250+ ///
251+ /// Two synthesized protocol types with the same members will share the same Salsa ID,
252+ /// making them easy to compare for equivalence. A synthesized protocol type is therefore
253+ /// returned by [`ProtocolInstanceType::normalized`] so that two protocols with the same members
254+ /// will be understood as equivalent even in the context of differently ordered unions or intersections.
221255#[ salsa:: interned( debug) ]
222256pub ( super ) struct SynthesizedProtocolType < ' db > {
223257 #[ return_ref]
0 commit comments