@@ -798,51 +798,24 @@ impl<'interner, 'arena> Context<'interner, 'arena> {
798
798
match ( surface_term, expected_type. as_ref ( ) ) {
799
799
( Term :: Let ( range, def_pattern, def_type, def_expr, body_expr) , _) => {
800
800
let ( def_pattern, def_type_value) = self . synth_ann_pattern ( def_pattern, * def_type) ;
801
- let mut scrut = self . check_scrutinee ( def_expr, def_type_value. clone ( ) ) ;
801
+ let scrut = self . check_scrutinee ( def_expr, def_type_value. clone ( ) ) ;
802
802
let value = self . eval_env ( ) . eval ( scrut. expr ) ;
803
-
804
- // Bind the scrut to a fresh variable if it is unsafe to evaluate multiple times,
805
- // and may be evaluated multiple times by the pattern match compiler
806
- let extra_def = match ( scrut. expr . is_atomic ( ) , def_pattern. is_atomic ( ) ) {
807
- ( false , false ) => {
808
- let def_name = None ; // TODO: generate a fresh name
809
- let def_type = self . quote_env ( ) . quote ( self . scope , & scrut. r#type ) ;
810
- let def_expr = scrut. expr . clone ( ) ;
811
-
812
- let var = core:: Term :: LocalVar ( def_expr. span ( ) , env:: Index :: last ( ) ) ;
813
- scrut. expr = self . scope . to_scope ( var) ;
814
- ( self . local_env ) . push_def ( def_name, value. clone ( ) , scrut. r#type . clone ( ) ) ;
815
- Some ( ( def_name, def_type, def_expr) )
816
- }
817
- _ => None ,
818
- } ;
803
+ let ( scrut, extra_def) =
804
+ self . freshen_scrutinee ( scrut, & value, & [ def_pattern. clone ( ) ] ) ;
819
805
820
806
let initial_len = self . local_env . len ( ) ;
821
807
let defs = self . push_local_def ( & def_pattern, scrut. clone ( ) , value) ;
822
808
let body_expr = self . check ( body_expr, & expected_type) ;
823
809
self . local_env . truncate ( initial_len) ;
824
810
825
811
let matrix = PatMatrix :: singleton ( scrut, def_pattern) ;
826
- let expr = self . elab_match (
812
+ let body = self . elab_match (
827
813
matrix,
828
814
& [ Body :: new ( body_expr, defs) ] ,
829
815
* range,
830
816
def_expr. range ( ) ,
831
817
) ;
832
- let expr = match extra_def {
833
- None => expr,
834
- Some ( ( def_name, def_type, def_expr) ) => {
835
- self . local_env . pop ( ) ;
836
- core:: Term :: Let (
837
- range. into ( ) ,
838
- def_name,
839
- self . scope . to_scope ( def_type) ,
840
- self . scope . to_scope ( def_expr) ,
841
- self . scope . to_scope ( expr) ,
842
- )
843
- }
844
- } ;
845
- expr
818
+ self . bind_scrutinee ( * range, body, extra_def)
846
819
}
847
820
( Term :: If ( range, cond_expr, then_expr, else_expr) , _) => {
848
821
let cond_expr = self . check ( cond_expr, & self . bool_type . clone ( ) ) ;
@@ -1134,51 +1107,25 @@ impl<'interner, 'arena> Context<'interner, 'arena> {
1134
1107
}
1135
1108
Term :: Let ( range, def_pattern, def_type, def_expr, body_expr) => {
1136
1109
let ( def_pattern, def_type_value) = self . synth_ann_pattern ( def_pattern, * def_type) ;
1137
- let mut scrut = self . check_scrutinee ( def_expr, def_type_value. clone ( ) ) ;
1110
+ let scrut = self . check_scrutinee ( def_expr, def_type_value. clone ( ) ) ;
1138
1111
let value = self . eval_env ( ) . eval ( scrut. expr ) ;
1139
-
1140
- // Bind the scrut to a fresh variable if it is unsafe to evaluate multiple times,
1141
- // and may be evaluated multiple times by the pattern match compiler
1142
- let extra_def = match ( scrut. expr . is_atomic ( ) , def_pattern. is_atomic ( ) ) {
1143
- ( false , false ) => {
1144
- let def_name = None ; // TODO: generate a fresh name
1145
- let def_type = self . quote_env ( ) . quote ( self . scope , & scrut. r#type ) ;
1146
- let def_expr = scrut. expr . clone ( ) ;
1147
-
1148
- let var = core:: Term :: LocalVar ( def_expr. span ( ) , env:: Index :: last ( ) ) ;
1149
- scrut. expr = self . scope . to_scope ( var) ;
1150
- ( self . local_env ) . push_def ( def_name, value. clone ( ) , scrut. r#type . clone ( ) ) ;
1151
- Some ( ( def_name, def_type, def_expr) )
1152
- }
1153
- _ => None ,
1154
- } ;
1112
+ let ( scrut, extra_def) =
1113
+ self . freshen_scrutinee ( scrut, & value, & [ def_pattern. clone ( ) ] ) ;
1155
1114
1156
1115
let initial_len = self . local_env . len ( ) ;
1157
1116
let defs = self . push_local_def ( & def_pattern, scrut. clone ( ) , value) ;
1158
1117
let ( body_expr, body_type) = self . synth ( body_expr) ;
1159
1118
self . local_env . truncate ( initial_len) ;
1160
1119
1161
1120
let matrix = patterns:: PatMatrix :: singleton ( scrut, def_pattern) ;
1162
- let expr = self . elab_match (
1121
+ let body = self . elab_match (
1163
1122
matrix,
1164
1123
& [ Body :: new ( body_expr, defs) ] ,
1165
1124
* range,
1166
1125
def_expr. range ( ) ,
1167
1126
) ;
1168
- let expr = match extra_def {
1169
- None => expr,
1170
- Some ( ( def_name, def_type, def_expr) ) => {
1171
- self . local_env . pop ( ) ;
1172
- core:: Term :: Let (
1173
- range. into ( ) ,
1174
- def_name,
1175
- self . scope . to_scope ( def_type) ,
1176
- self . scope . to_scope ( def_expr) ,
1177
- self . scope . to_scope ( expr) ,
1178
- )
1179
- }
1180
- } ;
1181
- ( expr, body_type)
1127
+ let let_expr = self . bind_scrutinee ( * range, body, extra_def) ;
1128
+ ( let_expr, body_type)
1182
1129
}
1183
1130
Term :: If ( range, cond_expr, then_expr, else_expr) => {
1184
1131
let cond_expr = self . check ( cond_expr, & self . bool_type . clone ( ) ) ;
@@ -1871,32 +1818,14 @@ impl<'interner, 'arena> Context<'interner, 'arena> {
1871
1818
expected_type : & ArcValue < ' arena > ,
1872
1819
) -> core:: Term < ' arena > {
1873
1820
let expected_type = self . elim_env ( ) . force ( expected_type) ;
1874
- let mut scrut = self . synth_scrutinee ( scrutinee_expr) ;
1821
+ let scrut = self . synth_scrutinee ( scrutinee_expr) ;
1875
1822
let value = self . eval_env ( ) . eval ( scrut. expr ) ;
1876
1823
1877
1824
let patterns: Vec < _ > = equations
1878
1825
. iter ( )
1879
1826
. map ( |( pat, _) | self . check_pattern ( pat, & scrut. r#type ) )
1880
1827
. collect ( ) ;
1881
-
1882
- // Bind the scrut to a fresh variable if it is unsafe to evaluate multiple times,
1883
- // and may be evaluated multiple times by the pattern match compiler
1884
- let extra_def = match (
1885
- scrut. expr . is_atomic ( ) ,
1886
- patterns. iter ( ) . all ( |pat| pat. is_atomic ( ) ) ,
1887
- ) {
1888
- ( false , false ) => {
1889
- let def_name = None ; // TODO: generate a fresh name
1890
- let def_type = self . quote_env ( ) . quote ( self . scope , & scrut. r#type ) ;
1891
- let def_expr = scrut. expr . clone ( ) ;
1892
-
1893
- let var = core:: Term :: LocalVar ( def_expr. span ( ) , env:: Index :: last ( ) ) ;
1894
- scrut. expr = self . scope . to_scope ( var) ;
1895
- ( self . local_env ) . push_def ( def_name, value. clone ( ) , scrut. r#type . clone ( ) ) ;
1896
- Some ( ( def_name, def_type, def_expr) )
1897
- }
1898
- _ => None ,
1899
- } ;
1828
+ let ( scrut, extra_def) = self . freshen_scrutinee ( scrut, & value, & patterns) ;
1900
1829
1901
1830
let mut rows = Vec :: with_capacity ( equations. len ( ) ) ;
1902
1831
let mut bodies = Vec :: with_capacity ( equations. len ( ) ) ;
@@ -1918,21 +1847,8 @@ impl<'interner, 'arena> Context<'interner, 'arena> {
1918
1847
}
1919
1848
1920
1849
let matrix = patterns:: PatMatrix :: new ( rows) ;
1921
- let expr = self . elab_match ( matrix, & bodies, range, scrut. range ) ;
1922
- let expr = match extra_def {
1923
- None => expr,
1924
- Some ( ( def_name, def_type, def_expr) ) => {
1925
- self . local_env . pop ( ) ;
1926
- core:: Term :: Let (
1927
- range. into ( ) ,
1928
- def_name,
1929
- self . scope . to_scope ( def_type) ,
1930
- self . scope . to_scope ( def_expr) ,
1931
- self . scope . to_scope ( expr) ,
1932
- )
1933
- }
1934
- } ;
1935
- expr
1850
+ let body = self . elab_match ( matrix, & bodies, range, scrut. range ) ;
1851
+ self . bind_scrutinee ( range, body, extra_def)
1936
1852
}
1937
1853
1938
1854
fn synth_scrutinee ( & mut self , scrutinee_expr : & Term < ' _ , ByteRange > ) -> Scrutinee < ' arena > {
@@ -1957,6 +1873,53 @@ impl<'interner, 'arena> Context<'interner, 'arena> {
1957
1873
}
1958
1874
}
1959
1875
1876
+ // Bind `scrut` to a fresh variable if it is unsafe to evaluate multiple times,
1877
+ // and may be evaluated multiple times by any of `patterns`
1878
+ fn freshen_scrutinee (
1879
+ & mut self ,
1880
+ mut scrut : Scrutinee < ' arena > ,
1881
+ value : & ArcValue < ' arena > ,
1882
+ patterns : & [ CheckedPattern < ' arena > ] ,
1883
+ ) -> (
1884
+ Scrutinee < ' arena > ,
1885
+ Option < ( Option < StringId > , core:: Term < ' arena > , core:: Term < ' arena > ) > ,
1886
+ ) {
1887
+ if scrut. expr . is_atomic ( ) || patterns. iter ( ) . all ( |pat| pat. is_atomic ( ) ) {
1888
+ return ( scrut, None ) ;
1889
+ }
1890
+
1891
+ let def_name = None ; // TODO: generate a fresh name
1892
+ let def_type = self . quote_env ( ) . quote ( self . scope , & scrut. r#type ) ;
1893
+ let def_expr = scrut. expr . clone ( ) ;
1894
+
1895
+ let var = core:: Term :: LocalVar ( def_expr. span ( ) , env:: Index :: last ( ) ) ;
1896
+ scrut. expr = self . scope . to_scope ( var) ;
1897
+ ( self . local_env ) . push_def ( def_name, value. clone ( ) , scrut. r#type . clone ( ) ) ;
1898
+ let extra_def = Some ( ( def_name, def_type, def_expr) ) ;
1899
+ ( scrut, extra_def)
1900
+ }
1901
+
1902
+ fn bind_scrutinee (
1903
+ & mut self ,
1904
+ range : ByteRange ,
1905
+ body : core:: Term < ' arena > ,
1906
+ extra_def : Option < ( Option < StringId > , core:: Term < ' arena > , core:: Term < ' arena > ) > ,
1907
+ ) -> core:: Term < ' arena > {
1908
+ match extra_def {
1909
+ None => body,
1910
+ Some ( ( def_name, def_type, def_expr) ) => {
1911
+ self . local_env . pop ( ) ;
1912
+ core:: Term :: Let (
1913
+ range. into ( ) ,
1914
+ def_name,
1915
+ self . scope . to_scope ( def_type) ,
1916
+ self . scope . to_scope ( def_expr) ,
1917
+ self . scope . to_scope ( body) ,
1918
+ )
1919
+ }
1920
+ }
1921
+ }
1922
+
1960
1923
fn synth_param (
1961
1924
& mut self ,
1962
1925
pattern : & Pattern < ' _ , ByteRange > ,
0 commit comments