@@ -193,33 +193,21 @@ impl<'ir> From<ClassWalker<'ir>> for PartialPythonClass<'ir> {
193193 let needed: bool = f. attributes . get ( "stream.not_null" ) . is_some ( ) ;
194194 let ( _, metadata) = c. ir . distribute_metadata ( & f. elem . r#type . elem ) ;
195195 let done: bool = metadata. 1 . done ;
196- let field = match ( done, needed) {
197- // A normal partial field.
198- ( false , false ) => add_default_value (
199- c. ir ,
200- & f. elem . r#type . elem ,
201- & f. elem . r#type . elem . to_partial_type_ref ( c. ir , false , false ) ,
202- ) ,
203- // A field with @stream.done and no @stream.not_null
204- ( true , false ) => add_default_value (
205- c. ir ,
206- & f. elem . r#type . elem ,
207- & optional ( & f. elem . r#type . elem . to_type_ref ( c. ir , true ) ) ,
208- ) ,
209- ( false , true ) => add_default_value (
210- c. ir ,
211- & f. elem . r#type . elem ,
212- & f. elem . r#type . elem . to_partial_type_ref ( c. ir , false , true ) ,
213- ) ,
214- ( true , true ) => add_default_value (
215- c. ir ,
216- & f. elem . r#type . elem ,
217- & f. elem . r#type . elem . to_type_ref ( c. ir , true ) , // TODO: Fix.
218- ) ,
196+ let ( field, optional) = match ( done, needed) {
197+ ( false , false ) => {
198+ f. elem . r#type . elem . to_partial_type_ref ( c. ir , false , false )
199+ }
200+ ( true , false ) => ( format ! ( "Optional[{}]" , f. elem. r#type. elem. to_type_ref( c. ir, true ) ) , true ) ,
201+ ( false , true ) => f. elem . r#type . elem . to_partial_type_ref ( c. ir , true , true ) ,
202+ ( true , true ) => ( f. elem . r#type . elem . to_type_ref ( c. ir , true ) , false ) ,
219203 } ;
220204 (
221205 f. elem . name . as_str ( ) ,
222- field,
206+ add_default_value (
207+ c. ir ,
208+ & f. elem . r#type . elem ,
209+ & field,
210+ ) ,
223211 f. elem . docstring . as_ref ( ) . map ( render_docstring) ,
224212 )
225213 } )
@@ -304,7 +292,12 @@ pub fn to_python_literal(literal: &LiteralValue) -> String {
304292
305293trait ToTypeReferenceInTypeDefinition {
306294 fn to_type_ref ( & self , ir : & IntermediateRepr , module_prefix : bool ) -> String ;
307- fn to_partial_type_ref ( & self , ir : & IntermediateRepr , wrapped : bool , needed : bool ) -> String ;
295+ fn to_partial_type_ref (
296+ & self ,
297+ ir : & IntermediateRepr ,
298+ wrapped : bool ,
299+ needed : bool ,
300+ ) -> ( String , bool ) ;
308301}
309302
310303impl ToTypeReferenceInTypeDefinition for FieldType {
@@ -362,11 +355,20 @@ impl ToTypeReferenceInTypeDefinition for FieldType {
362355 }
363356 None => base. to_type_ref ( ir, use_module_prefix) ,
364357 } ,
365- FieldType :: Arrow ( _) => todo ! ( "Arrow types should not be used in generated type definitions" ) ,
358+ FieldType :: Arrow ( _) => {
359+ todo ! ( "Arrow types should not be used in generated type definitions" )
360+ }
366361 }
367362 }
368363
369- fn to_partial_type_ref ( & self , ir : & IntermediateRepr , wrapped : bool , needed : bool ) -> String {
364+ /// How to serialize the partial version of a field type.
365+ /// Also returns whether the field is optional during streaming.
366+ fn to_partial_type_ref (
367+ & self ,
368+ ir : & IntermediateRepr ,
369+ wrapped : bool ,
370+ needed : bool ,
371+ ) -> ( String , bool ) {
370372 let ( base_type, metadata) = ir. distribute_metadata ( self ) ;
371373 let is_partial_type = !metadata. 1 . done ;
372374 let use_module_prefix = !is_partial_type;
@@ -376,9 +378,9 @@ impl ToTypeReferenceInTypeDefinition for FieldType {
376378 let base_rep = match base_type {
377379 FieldType :: Class ( name) => {
378380 if wrapped || needed {
379- format ! ( "\" {module_prefix}{name}\" " )
381+ ( format ! ( "\" {module_prefix}{name}\" " ) , false )
380382 } else {
381- format ! ( "Optional[\" {module_prefix}{name}\" ]" )
383+ ( format ! ( "Optional[\" {module_prefix}{name}\" ]" ) , true )
382384 }
383385 }
384386 FieldType :: Enum ( name) => {
@@ -388,98 +390,108 @@ impl ToTypeReferenceInTypeDefinition for FieldType {
388390 . unwrap_or ( false )
389391 {
390392 if needed || wrapped {
391- format ! ( "Union[types.{name}, str]" )
393+ ( format ! ( "Union[types.{name}, str]" ) , false )
392394 } else {
393- format ! ( "Optional[Union[types.{name}, str]]" )
395+ ( format ! ( "Optional[Union[types.{name}, str]]" ) , true )
394396 }
395397 } else {
396398 if needed || wrapped {
397- format ! ( "types.{name}" )
399+ ( format ! ( "types.{name}" ) , false )
398400 } else {
399- format ! ( "Optional[types.{name}]" )
401+ ( format ! ( "Optional[types.{name}]" ) , true )
400402 }
401403 }
402404 }
403405 FieldType :: RecursiveTypeAlias ( name) => {
404406 if wrapped {
405- format ! ( "\" {name}\" " )
407+ ( format ! ( "\" {name}\" " ) , false )
406408 } else {
407- format ! ( "Optional[\" {name}\" ]" )
409+ ( format ! ( "Optional[\" {name}\" ]" ) , true )
408410 }
409411 }
410412 FieldType :: Literal ( value) => {
411413 if needed || wrapped {
412- to_python_literal ( value)
414+ ( to_python_literal ( value) , false )
413415 } else {
414- format ! ( "Optional[{}]" , to_python_literal( value) )
416+ ( format ! ( "Optional[{}]" , to_python_literal( value) ) , true )
415417 }
416418 } // TODO: Handle `needed` here.
417419
418- FieldType :: List ( inner) => {
419- format ! ( "List[{}]" , inner. to_partial_type_ref( ir, true , false ) )
420- }
421- FieldType :: Map ( key, value) => format ! (
422- "Dict[{}, {}]" ,
423- key. to_type_ref( ir, use_module_prefix) ,
424- value. to_partial_type_ref( ir, false , false )
420+ FieldType :: List ( inner) => (
421+ format ! ( "List[{}]" , inner. to_partial_type_ref( ir, true , false ) . 0 ) ,
422+ false ,
423+ ) ,
424+ FieldType :: Map ( key, value) => (
425+ format ! (
426+ "Dict[{}, {}]" ,
427+ key. to_type_ref( ir, use_module_prefix) ,
428+ value. to_partial_type_ref( ir, false , false ) . 0
429+ ) ,
430+ false ,
425431 ) ,
426432 FieldType :: Primitive ( r#type) => {
427433 if needed || wrapped {
428- r#type. to_python ( )
434+ ( r#type. to_python ( ) , false )
429435 } else {
430- format ! ( "Optional[{}]" , r#type. to_python( ) )
436+ ( format ! ( "Optional[{}]" , r#type. to_python( ) ) , true )
431437 }
432438 }
433439 FieldType :: Union ( inner) => {
434440 let union_contents = inner
435441 . iter ( )
436- . map ( |t| t. to_partial_type_ref ( ir, true , false ) )
442+ . map ( |t| t. to_partial_type_ref ( ir, true , false ) . 0 )
437443 . collect :: < Vec < _ > > ( )
438444 . join ( ", " ) ;
439445 if needed || wrapped {
440- format ! ( "Union[{union_contents}]" )
446+ ( format ! ( "Union[{union_contents}]" ) , false )
441447 } else {
442- format ! ( "Optional[Union[{union_contents}]]" )
448+ ( format ! ( "Optional[Union[{union_contents}]]" ) , true )
443449 }
444450 }
445451 FieldType :: Tuple ( inner) => {
446452 let tuple_contents = inner
447453 . iter ( )
448- . map ( |t| t. to_partial_type_ref ( ir, false , false ) )
454+ . map ( |t| t. to_partial_type_ref ( ir, false , false ) . 0 )
449455 . collect :: < Vec < _ > > ( )
450456 . join ( ", " ) ;
451457 if needed || wrapped {
452- format ! ( "Tuple[{tuple_contents}]" )
458+ ( format ! ( "Tuple[{tuple_contents}]" ) , false )
453459 } else {
454- format ! ( "Optional[Tuple[{tuple_contents}]]" )
460+ ( format ! ( "Optional[Tuple[{tuple_contents}]]" ) , true )
455461 }
456462 }
457- FieldType :: Optional ( inner) => {
458- format ! ( "Optional[{}]" , inner. to_partial_type_ref( ir, true , false ) )
459- }
463+ FieldType :: Optional ( inner) => (
464+ format ! ( "Optional[{}]" , inner. to_partial_type_ref( ir, true , false ) . 0 ) ,
465+ true ,
466+ ) ,
460467 FieldType :: WithMetadata { .. } => {
461468 unreachable ! ( "distribute_metadata makes this branch unreachable." )
462469 }
463- FieldType :: Arrow ( _) => todo ! ( "Arrow types should not be used in generated type definitions" ) ,
470+ FieldType :: Arrow ( _) => {
471+ todo ! ( "Arrow types should not be used in generated type definitions" )
472+ }
464473 } ;
465474 let base_type_ref = if is_partial_type {
466475 base_rep
467476 } else {
468477 if needed {
469- base_type. to_type_ref ( ir, use_module_prefix)
478+ ( base_type. to_type_ref ( ir, use_module_prefix) , false )
470479 } else {
471480 base_rep
472481 }
473482 } ;
474483 let rep_with_checks = match field_type_attributes ( self ) {
475484 Some ( checks) => {
476485 let checks_type_ref = type_name_for_checks ( & checks) ;
477- format ! ( "Checked[{base_type_ref},{checks_type_ref}]" )
486+ (
487+ format ! ( "Checked[{},{checks_type_ref}]" , base_type_ref. 0 ) ,
488+ base_type_ref. 1 ,
489+ )
478490 }
479491 None => base_type_ref,
480492 } ;
481493 let rep_with_stream_state = if with_state {
482- stream_state ( & rep_with_checks)
494+ ( stream_state ( & rep_with_checks. 0 ) , rep_with_checks . 1 )
483495 } else {
484496 rep_with_checks
485497 } ;
@@ -505,6 +517,7 @@ fn stream_state(base: &str) -> String {
505517#[ cfg( test) ]
506518mod tests {
507519 use super :: * ;
520+ use baml_types:: StreamingBehavior ;
508521 use internal_baml_core:: ir:: repr:: { make_test_ir, IntermediateRepr } ;
509522
510523 #[ test]
@@ -516,7 +529,7 @@ mod tests {
516529 let full = optional_list. to_type_ref ( & ir, false ) ;
517530 let partial = optional_list. to_partial_type_ref ( & ir, false , false ) ;
518531 assert_eq ! ( full, "Optional[List[str]]" ) ;
519- assert_eq ! ( partial, "Optional[List[str]]" ) ;
532+ assert_eq ! ( partial. 0 , "Optional[List[str]]" ) ;
520533 }
521534
522535 #[ test]
@@ -528,6 +541,23 @@ mod tests {
528541 let full = optional_list. to_type_ref ( & ir, false ) ;
529542 let partial = optional_list. to_partial_type_ref ( & ir, false , false ) ;
530543 assert_eq ! ( full, "Optional[List[str]]" ) ;
531- assert_eq ! ( partial, "Optional[List[str]]" ) ;
544+ assert_eq ! ( partial. 0 , "Optional[List[str]]" ) ;
545+ }
546+
547+ #[ test]
548+ fn test_stream_done_type ( ) {
549+ let ir = make_test_ir ( "" ) . unwrap ( ) ;
550+ let done_type = FieldType :: WithMetadata {
551+ base : Box :: new ( FieldType :: class ( "Foo" ) ) ,
552+ streaming_behavior : StreamingBehavior {
553+ done : true ,
554+ state : false ,
555+ } ,
556+ constraints : vec ! [ ] ,
557+ } ;
558+ let full = done_type. to_type_ref ( & ir, false ) ;
559+ let partial = done_type. to_partial_type_ref ( & ir, false , false ) ;
560+ assert_eq ! ( full, "\" Foo\" " ) ;
561+ assert_eq ! ( partial. 0 , "Optional[\" types.Foo\" ]" ) ;
532562 }
533563}
0 commit comments