@@ -723,115 +723,155 @@ fn get_specialization_lambda_set_ambient_function<P: Phase>(
723
723
phase : & P ,
724
724
ability_member : Symbol ,
725
725
lset_region : u8 ,
726
- specialization_key : SpecializationTypeKey ,
726
+ mut specialization_key : SpecializationTypeKey ,
727
727
target_rank : Rank ,
728
728
) -> Result < Variable , ( ) > {
729
- match specialization_key {
730
- SpecializationTypeKey :: Opaque ( opaque) => {
731
- let opaque_home = opaque. module_id ( ) ;
732
- let external_specialized_lset =
733
- phase. with_module_abilities_store ( opaque_home, |abilities_store| {
734
- let impl_key = roc_can:: abilities:: ImplKey {
729
+ loop {
730
+ match specialization_key {
731
+ SpecializationTypeKey :: Opaque ( opaque) => {
732
+ let opaque_home = opaque. module_id ( ) ;
733
+ let found = phase. with_module_abilities_store ( opaque_home, |abilities_store| {
734
+ find_opaque_specialization_ambient_function (
735
+ abilities_store,
735
736
opaque,
736
737
ability_member,
737
- } ;
738
-
739
- let opt_specialization =
740
- abilities_store. get_implementation ( impl_key) ;
741
- match opt_specialization {
742
- None => {
743
- if P :: IS_LATE {
744
- internal_error ! (
745
- "expected to know a specialization for {:?}#{:?}, but it wasn't found" ,
746
- opaque,
747
- ability_member
748
- ) ;
749
- } else {
750
- // doesn't specialize, we'll have reported an error for this
751
- Err ( ( ) )
752
- }
738
+ lset_region,
739
+ )
740
+ } ) ;
741
+
742
+ let external_specialized_lset = match found {
743
+ FoundOpaqueSpecialization :: UpdatedSpecializationKey ( key) => {
744
+ specialization_key = key;
745
+ continue ;
746
+ }
747
+ FoundOpaqueSpecialization :: AmbientFunction ( lset) => lset,
748
+ FoundOpaqueSpecialization :: NotFound => {
749
+ if P :: IS_LATE {
750
+ internal_error ! (
751
+ "expected to know a specialization for {:?}#{:?}, but it wasn't found" ,
752
+ opaque,
753
+ ability_member
754
+ ) ;
755
+ } else {
756
+ // We'll have reported an error for this.
757
+ return Err ( ( ) ) ;
753
758
}
754
- Some ( member_impl) => match member_impl {
755
- MemberImpl :: Impl ( spec_symbol) => {
756
- let specialization =
757
- abilities_store. specialization_info ( * spec_symbol) . expect ( "expected custom implementations to always have complete specialization info by this point" ) ;
758
-
759
- let specialized_lambda_set = * specialization
760
- . specialization_lambda_sets
761
- . get ( & lset_region)
762
- . unwrap_or_else ( || panic ! ( "lambda set region not resolved: {:?}" , ( spec_symbol, specialization) ) ) ;
763
- Ok ( specialized_lambda_set)
764
- }
765
- MemberImpl :: Error => todo_abilities ! ( ) ,
766
- } ,
767
759
}
768
- } ) ? ;
760
+ } ;
769
761
770
- let specialized_ambient = phase. copy_lambda_set_ambient_function_to_home_subs (
771
- external_specialized_lset,
772
- opaque_home,
773
- subs,
774
- ) ;
762
+ let specialized_ambient = phase. copy_lambda_set_ambient_function_to_home_subs (
763
+ external_specialized_lset,
764
+ opaque_home,
765
+ subs,
766
+ ) ;
775
767
776
- Ok ( specialized_ambient)
777
- }
768
+ return Ok ( specialized_ambient) ;
769
+ }
778
770
779
- SpecializationTypeKey :: Derived ( derive_key) => {
780
- let mut derived_module = derived_env. derived_module . lock ( ) . unwrap ( ) ;
771
+ SpecializationTypeKey :: Derived ( derive_key) => {
772
+ let mut derived_module = derived_env. derived_module . lock ( ) . unwrap ( ) ;
781
773
782
- let ( _, _, specialization_lambda_sets) =
783
- derived_module. get_or_insert ( derived_env. exposed_types , derive_key) ;
774
+ let ( _, _, specialization_lambda_sets) =
775
+ derived_module. get_or_insert ( derived_env. exposed_types , derive_key) ;
784
776
785
- let specialized_lambda_set = * specialization_lambda_sets
786
- . get ( & lset_region)
787
- . expect ( "lambda set region not resolved" ) ;
777
+ let specialized_lambda_set = * specialization_lambda_sets
778
+ . get ( & lset_region)
779
+ . expect ( "lambda set region not resolved" ) ;
788
780
789
- let specialized_ambient = derived_module. copy_lambda_set_ambient_function_to_subs (
790
- specialized_lambda_set,
791
- subs,
792
- target_rank,
793
- ) ;
781
+ let specialized_ambient = derived_module. copy_lambda_set_ambient_function_to_subs (
782
+ specialized_lambda_set,
783
+ subs,
784
+ target_rank,
785
+ ) ;
794
786
795
- Ok ( specialized_ambient)
796
- }
787
+ return Ok ( specialized_ambient) ;
788
+ }
797
789
798
- SpecializationTypeKey :: Immediate ( imm) => {
799
- // Immediates are like opaques in that we can simply look up their type definition in
800
- // the ability store, there is nothing new to synthesize.
801
- //
802
- // THEORY: if something can become an immediate, it will always be available in the
803
- // local ability store, because the transformation is local (?)
804
- //
805
- // TODO: I actually think we can get what we need here by examining `derived_env.exposed_types`,
806
- // since immediates can only refer to builtins - and in userspace, all builtin types
807
- // are available in `exposed_types`.
808
- let immediate_lambda_set_at_region =
809
- phase. get_and_copy_ability_member_ambient_function ( imm, lset_region, subs) ;
810
-
811
- Ok ( immediate_lambda_set_at_region)
812
- }
790
+ SpecializationTypeKey :: Immediate ( imm) => {
791
+ // Immediates are like opaques in that we can simply look up their type definition in
792
+ // the ability store, there is nothing new to synthesize.
793
+ //
794
+ // THEORY: if something can become an immediate, it will always be available in the
795
+ // local ability store, because the transformation is local (?)
796
+ //
797
+ // TODO: I actually think we can get what we need here by examining `derived_env.exposed_types`,
798
+ // since immediates can only refer to builtins - and in userspace, all builtin types
799
+ // are available in `exposed_types`.
800
+ let immediate_lambda_set_at_region =
801
+ phase. get_and_copy_ability_member_ambient_function ( imm, lset_region, subs) ;
802
+
803
+ return Ok ( immediate_lambda_set_at_region) ;
804
+ }
813
805
814
- SpecializationTypeKey :: SingleLambdaSetImmediate ( imm) => {
815
- let module_id = imm. module_id ( ) ;
816
- debug_assert ! ( module_id. is_builtin( ) ) ;
806
+ SpecializationTypeKey :: SingleLambdaSetImmediate ( imm) => {
807
+ let module_id = imm. module_id ( ) ;
808
+ debug_assert ! ( module_id. is_builtin( ) ) ;
817
809
818
- let module_types = & derived_env
819
- . exposed_types
820
- . get ( & module_id)
821
- . unwrap ( )
822
- . exposed_types_storage_subs ;
810
+ let module_types = & derived_env
811
+ . exposed_types
812
+ . get ( & module_id)
813
+ . unwrap ( )
814
+ . exposed_types_storage_subs ;
823
815
824
- // Since this immediate has only one lambda set, the region must be pointing to 1, and
825
- // moreover the imported function type is the ambient function of the single lset.
826
- debug_assert_eq ! ( lset_region, 1 ) ;
827
- let storage_var = module_types. stored_vars_by_symbol . get ( & imm) . unwrap ( ) ;
828
- let imported = module_types
829
- . storage_subs
830
- . export_variable_to ( subs, * storage_var) ;
816
+ // Since this immediate has only one lambda set, the region must be pointing to 1, and
817
+ // moreover the imported function type is the ambient function of the single lset.
818
+ debug_assert_eq ! ( lset_region, 1 ) ;
819
+ let storage_var = module_types. stored_vars_by_symbol . get ( & imm) . unwrap ( ) ;
820
+ let imported = module_types
821
+ . storage_subs
822
+ . export_variable_to ( subs, * storage_var) ;
831
823
832
- roc_types:: subs:: instantiate_rigids ( subs, imported. variable ) ;
824
+ roc_types:: subs:: instantiate_rigids ( subs, imported. variable ) ;
833
825
834
- Ok ( imported. variable )
826
+ return Ok ( imported. variable ) ;
827
+ }
835
828
}
836
829
}
837
830
}
831
+
832
+ enum FoundOpaqueSpecialization {
833
+ UpdatedSpecializationKey ( SpecializationTypeKey ) ,
834
+ AmbientFunction ( Variable ) ,
835
+ NotFound ,
836
+ }
837
+
838
+ fn find_opaque_specialization_ambient_function (
839
+ abilities_store : & AbilitiesStore ,
840
+ opaque : Symbol ,
841
+ ability_member : Symbol ,
842
+ lset_region : u8 ,
843
+ ) -> FoundOpaqueSpecialization {
844
+ let impl_key = roc_can:: abilities:: ImplKey {
845
+ opaque,
846
+ ability_member,
847
+ } ;
848
+
849
+ let opt_specialization = abilities_store. get_implementation ( impl_key) ;
850
+ match opt_specialization {
851
+ None => match ability_member {
852
+ Symbol :: INSPECT_TO_INSPECTOR => FoundOpaqueSpecialization :: UpdatedSpecializationKey (
853
+ SpecializationTypeKey :: Immediate ( Symbol :: INSPECT_OPAQUE ) ,
854
+ ) ,
855
+ _ => FoundOpaqueSpecialization :: NotFound ,
856
+ } ,
857
+ Some ( member_impl) => match member_impl {
858
+ MemberImpl :: Impl ( spec_symbol) => {
859
+ let specialization =
860
+ abilities_store. specialization_info ( * spec_symbol) . expect ( "expected custom implementations to always have complete specialization info by this point" ) ;
861
+
862
+ let specialized_lambda_set = * specialization
863
+ . specialization_lambda_sets
864
+ . get ( & lset_region)
865
+ . unwrap_or_else ( || {
866
+ panic ! (
867
+ "lambda set region not resolved: {:?}" ,
868
+ ( spec_symbol, specialization)
869
+ )
870
+ } ) ;
871
+
872
+ FoundOpaqueSpecialization :: AmbientFunction ( specialized_lambda_set)
873
+ }
874
+ MemberImpl :: Error => todo_abilities ! ( ) ,
875
+ } ,
876
+ }
877
+ }
0 commit comments