@@ -55,6 +55,32 @@ pub(crate) enum ErrorContext<'db> {
5555 NotAssignableToNOtherUnionElements {
5656 n : usize ,
5757 } ,
58+ TypedDictFieldMissing {
59+ field_name : Name ,
60+ source : TypedDictType < ' db > ,
61+ } ,
62+ TypedDictFieldNotRequiredInSource {
63+ source : TypedDictType < ' db > ,
64+ target : TypedDictType < ' db > ,
65+ field_name : Name ,
66+ } ,
67+ TypedDictFieldNotRequiredAndMutableInTarget {
68+ source : TypedDictType < ' db > ,
69+ target : TypedDictType < ' db > ,
70+ field_name : Name ,
71+ } ,
72+ TypedDictFieldReadOnlyInSource {
73+ field_name : Name ,
74+ source : TypedDictType < ' db > ,
75+ target : TypedDictType < ' db > ,
76+ } ,
77+ TypedDictFieldIncompatible {
78+ field_name : Name ,
79+ source : TypedDictType < ' db > ,
80+ target : TypedDictType < ' db > ,
81+ source_field : Type < ' db > ,
82+ target_field : Type < ' db > ,
83+ } ,
5884 TypedDictNotAssignableToDict ( TypedDictType < ' db > ) ,
5985 IncompatibleReturnTypes {
6086 source : Type < ' db > ,
@@ -105,6 +131,11 @@ impl<'db> ErrorContext<'db> {
105131 db : & ' db dyn Db ,
106132 help_messages : & mut FxOrderSet < HelpMessages > ,
107133 ) -> Option < String > {
134+ let typed_dict_name = |typed_dict : & TypedDictType < ' db > | match typed_dict {
135+ TypedDictType :: Class ( class) => format ! ( "TypedDict `{}`" , class. name( db) ) ,
136+ TypedDictType :: Synthesized ( _) => Type :: TypedDict ( * typed_dict) . display ( db) . to_string ( ) ,
137+ } ;
138+
108139 Some ( match self {
109140 Self :: Empty => {
110141 return None ;
@@ -128,15 +159,67 @@ impl<'db> ErrorContext<'db> {
128159 "... omitted {n} union element{} without additional context" ,
129160 if * n == 1 { "" } else { "s" }
130161 ) ,
162+ Self :: TypedDictFieldMissing { field_name, source } => {
163+ format ! (
164+ "required field \" {field_name}\" is not present in source {source}" ,
165+ source = typed_dict_name( source)
166+ )
167+ }
168+ Self :: TypedDictFieldNotRequiredInSource {
169+ field_name,
170+ source,
171+ target,
172+ } => {
173+ format ! (
174+ "field \" {field_name}\" is required in {target} but not required in {source}" ,
175+ source = typed_dict_name( source) ,
176+ target = typed_dict_name( target)
177+ )
178+ }
179+ Self :: TypedDictFieldNotRequiredAndMutableInTarget {
180+ field_name,
181+ source,
182+ target,
183+ } => {
184+ help_messages. insert ( HelpMessages :: RequiredFieldCouldBeRemoved ) ;
185+ format ! (
186+ "field \" {field_name}\" is required in {source} but not required and mutable in {target}" ,
187+ source = typed_dict_name( source) ,
188+ target = typed_dict_name( target)
189+ )
190+ }
191+ Self :: TypedDictFieldReadOnlyInSource {
192+ field_name,
193+ source,
194+ target,
195+ } => {
196+ format ! (
197+ "field \" {field_name}\" is read-only in {source} but mutable in {target}" ,
198+ source = typed_dict_name( source) ,
199+ target = typed_dict_name( target)
200+ )
201+ }
202+ Self :: TypedDictFieldIncompatible {
203+ field_name,
204+ source,
205+ target,
206+ source_field,
207+ target_field,
208+ } => format ! (
209+ "field \" {field_name}\" on {source} has type `{source_field}` which is not assignable to type `{target_field}` expected by {target}" ,
210+ source = typed_dict_name( source) ,
211+ target = typed_dict_name( target) ,
212+ source_field = source_field. display( db) ,
213+ target_field = target_field. display( db) ,
214+ ) ,
131215 Self :: TypedDictNotAssignableToDict ( typed_dict) => {
132216 help_messages. insert ( HelpMessages :: TypedDictNotAssignableToDict ) ;
133217 help_messages. insert ( HelpMessages :: ConsiderUsingMappingInsteadOfDict ) ;
134218
135- let name = match typed_dict {
136- TypedDictType :: Class ( class) => format ! ( "TypedDict `{}`" , class. name( db) ) ,
137- TypedDictType :: Synthesized ( _) => "TypedDict" . to_string ( ) ,
138- } ;
139- format ! ( "{name} is not assignable to `dict`" )
219+ format ! (
220+ "{source} is not assignable to `dict`" ,
221+ source = typed_dict_name( typed_dict)
222+ )
140223 }
141224 Self :: IncompatibleReturnTypes { source, target } => format ! (
142225 "incompatible return types: `{source}` is not assignable to `{target}`" ,
@@ -230,13 +313,17 @@ impl<'db> ErrorContext<'db> {
230313
231314#[ derive( Clone , Debug , PartialEq , Eq , Hash ) ]
232315enum HelpMessages {
316+ RequiredFieldCouldBeRemoved ,
233317 TypedDictNotAssignableToDict ,
234318 ConsiderUsingMappingInsteadOfDict ,
235319}
236320
237321impl std:: fmt:: Display for HelpMessages {
238322 fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
239323 match self {
324+ HelpMessages :: RequiredFieldCouldBeRemoved => {
325+ f. write_str ( "The required field could be removed through a destructive operation like `del` on the target." )
326+ }
240327 HelpMessages :: TypedDictNotAssignableToDict => {
241328 f. write_str ( "A TypedDict is not usually assignable to any `dict[..]` type; `dict` types allow destructive operations like `clear()`." )
242329 }
0 commit comments