▾ modified src/lower.rs +28 -0 Viewed
@@ -5405,6 +5405,34 @@ impl Lowerer { 5405 5405 Err ( " block expression with statements in value position is not implemented yet " . into ( ) ) 5406 5406 } 5407 5407 } 5408 + // A `match` in value position. Nim's `case` is an expression only 5409 + // when every arm is one, and Rust's arms routinely bind and 5410 + // destructure -- so instead the whole thing is lowered as the 5411 + // statement it already knows how to be, writing into a temporary, 5412 + // and the temporary is the value. That is what the statement form 5413 + // does for `let x = match ..` too. 5414 + Expr ::Match ( _ ) = > { 5415 + let t = match expect { 5416 + Some ( t ) = > t . clone ( ) , 5417 + None = > { 5418 + let save = self . out . len ( ) ; 5419 + let probe = self . result_ty ( e ) ; 5420 + self . out . truncate ( save ) ; 5421 + probe . ok_or_else ( | | { 5422 + " cannot infer the type of a `match` used as a value; \ 5423 + annotate the binding or the return type " 5424 + . to_string ( ) 5425 + } ) ? 5426 + } 5427 + } ; 5428 + let tmp = self . fresh ( " MatchVal " ) ; 5429 + self . line ( & format! ( " var {} : {} " , tmp , t . render ( ) ) ) ; 5430 + let outer = self . target . replace ( ( tmp . clone ( ) , Some ( t . clone ( ) ) ) ) ; 5431 + let r = self . match_stmt ( e ) ; 5432 + self . target = outer ; 5433 + r ? ; 5434 + Ok ( Val ::new ( tmp , Some ( t ) ) ) 5435 + } 5408 5436 other = > Err ( format! ( 5409 5437 " unsupported expression in value position: {} -- ` {} ` " , 5410 5438 expr_kind ( other ) ,
@@ -5405,6 +5405,34 @@ impl Lowerer { 5405 Err ( " block expression with statements in value position is not implemented yet " . into ( ) ) 5405 Err ( " block expression with statements in value position is not implemented yet " . into ( ) ) 5406 } 5406 } 5407 } 5407 } 5408 + // A `match` in value position. Nim's `case` is an expression only 5409 + // when every arm is one, and Rust's arms routinely bind and 5410 + // destructure -- so instead the whole thing is lowered as the 5411 + // statement it already knows how to be, writing into a temporary, 5412 + // and the temporary is the value. That is what the statement form 5413 + // does for `let x = match ..` too. 5414 + Expr ::Match ( _ ) = > { 5415 + let t = match expect { 5416 + Some ( t ) = > t . clone ( ) , 5417 + None = > { 5418 + let save = self . out . len ( ) ; 5419 + let probe = self . result_ty ( e ) ; 5420 + self . out . truncate ( save ) ; 5421 + probe . ok_or_else ( | | { 5422 + " cannot infer the type of a `match` used as a value; \ 5423 + annotate the binding or the return type " 5424 + . to_string ( ) 5425 + } ) ? 5426 + } 5427 + } ; 5428 + let tmp = self . fresh ( " MatchVal " ) ; 5429 + self . line ( & format! ( " var {} : {} " , tmp , t . render ( ) ) ) ; 5430 + let outer = self . target . replace ( ( tmp . clone ( ) , Some ( t . clone ( ) ) ) ) ; 5431 + let r = self . match_stmt ( e ) ; 5432 + self . target = outer ; 5433 + r ? ; 5434 + Ok ( Val ::new ( tmp , Some ( t ) ) ) 5435 + } 5408 other = > Err ( format! ( 5436 other = > Err ( format! ( 5409 " unsupported expression in value position: {} -- ` {} ` " , 5437 " unsupported expression in value position: {} -- ` {} ` " , 5410 expr_kind ( other ) , 5438 expr_kind ( other ) ,
▾ added tests/cases/062-match-as-value.rs +41 -0 Viewed
new file mode 100644 @@ -0,0 +1,41 @@ 1 + // A `match` used as a value. Nim's `case` is an expression only when every arm 2 + // is one, and Rust's arms routinely bind and destructure — so it is lowered as 3 + // the statement it already knows how to be, writing into a temporary. 4 + enum Shape { 5 + Circle ( u32 ) , 6 + Rect ( u32 , u32 ) , 7 + Point , 8 + } 9 + 10 + fn area ( s : & Shape ) -> u32 { 11 + match s { 12 + Shape ::Circle ( r ) = > r * r * 3 , 13 + Shape ::Rect ( w , h ) = > w * h , 14 + Shape ::Point = > 0 , 15 + } 16 + } 17 + 18 + fn describe ( s : & Shape ) -> String { 19 + format! ( 20 + " {} / {} " , 21 + match s { 22 + Shape ::Circle ( _ ) = > " circle " , 23 + Shape ::Rect ( _ , _ ) = > " rect " , 24 + Shape ::Point = > " point " , 25 + } , 26 + area ( s ) 27 + ) 28 + } 29 + 30 + fn main ( ) { 31 + let shapes = vec! [ Shape ::Circle ( 2 u32 ) , Shape ::Rect ( 3 u32 , 4 u32 ) , Shape ::Point ] ; 32 + for s in & shapes { 33 + println! ( " {} " , describe ( s ) ) ; 34 + } 35 + // Nested in an arithmetic expression. 36 + let n : u32 = 1 + match & shapes [ 0 ] { 37 + Shape ::Circle ( r ) = > * r , 38 + _ = > 100 , 39 + } ; 40 + println! ( " {} " , n ) ; 41 + }
new file mode 100644 @@ -0,0 +1,41 @@ 1 + // A `match` used as a value. Nim's `case` is an expression only when every arm 2 + // is one, and Rust's arms routinely bind and destructure — so it is lowered as 3 + // the statement it already knows how to be, writing into a temporary. 4 + enum Shape { 5 + Circle ( u32 ) , 6 + Rect ( u32 , u32 ) , 7 + Point , 8 + } 9 + 10 + fn area ( s : & Shape ) -> u32 { 11 + match s { 12 + Shape ::Circle ( r ) = > r * r * 3 , 13 + Shape ::Rect ( w , h ) = > w * h , 14 + Shape ::Point = > 0 , 15 + } 16 + } 17 + 18 + fn describe ( s : & Shape ) -> String { 19 + format! ( 20 + " {} / {} " , 21 + match s { 22 + Shape ::Circle ( _ ) = > " circle " , 23 + Shape ::Rect ( _ , _ ) = > " rect " , 24 + Shape ::Point = > " point " , 25 + } , 26 + area ( s ) 27 + ) 28 + } 29 + 30 + fn main ( ) { 31 + let shapes = vec! [ Shape ::Circle ( 2 u32 ) , Shape ::Rect ( 3 u32 , 4 u32 ) , Shape ::Point ] ; 32 + for s in & shapes { 33 + println! ( " {} " , describe ( s ) ) ; 34 + } 35 + // Nested in an arithmetic expression. 36 + let n : u32 = 1 + match & shapes [ 0 ] { 37 + Shape ::Circle ( r ) = > * r , 38 + _ = > 100 , 39 + } ; 40 + println! ( " {} " , n ) ; 41 + }