Fork of daniellemaywood.uk/gleam — Wasm codegen work
2

Configure Feed

Select the types of activity you want to include in your feed.

Make case expressions fault tolerant

+212 -102
+2 -1
compiler-core/src/ast/untyped.rs
··· 69 69 Case { 70 70 location: SrcSpan, 71 71 subjects: Vec<Self>, 72 - clauses: Vec<Clause<Self, (), ()>>, 72 + // None if the case expression is missing a body. 73 + clauses: Option<Vec<Clause<Self, (), ()>>>, 73 74 }, 74 75 75 76 FieldAccess {
+20 -18
compiler-core/src/ast_folder.rs
··· 457 457 clauses, 458 458 } => { 459 459 let subjects = subjects.into_iter().map(|e| self.fold_expr(e)).collect(); 460 - let clauses = clauses 461 - .into_iter() 462 - .map(|mut c| { 463 - c.pattern = c 464 - .pattern 465 - .into_iter() 466 - .map(|p| self.fold_pattern(p)) 467 - .collect(); 468 - c.alternative_patterns = c 469 - .alternative_patterns 470 - .into_iter() 471 - .map(|p| p.into_iter().map(|p| self.fold_pattern(p)).collect()) 472 - .collect(); 473 - c.then = self.fold_expr(c.then); 474 - c 475 - }) 476 - .collect(); 460 + let clauses = clauses.map(|clauses| { 461 + clauses 462 + .into_iter() 463 + .map(|mut c| { 464 + c.pattern = c 465 + .pattern 466 + .into_iter() 467 + .map(|p| self.fold_pattern(p)) 468 + .collect(); 469 + c.alternative_patterns = c 470 + .alternative_patterns 471 + .into_iter() 472 + .map(|p| p.into_iter().map(|p| self.fold_pattern(p)).collect()) 473 + .collect(); 474 + c.then = self.fold_expr(c.then); 475 + c 476 + }) 477 + .collect() 478 + }); 477 479 UntypedExpr::Case { 478 480 location, 479 481 subjects, ··· 742 744 &mut self, 743 745 location: SrcSpan, 744 746 subjects: Vec<UntypedExpr>, 745 - clauses: Vec<UntypedClause>, 747 + clauses: Option<Vec<UntypedClause>>, 746 748 ) -> UntypedExpr { 747 749 UntypedExpr::Case { 748 750 location,
+1 -1
compiler-core/src/call_graph.rs
··· 278 278 for subject in subjects { 279 279 self.expression(subject); 280 280 } 281 - for clause in clauses { 281 + for clause in clauses.as_deref().unwrap_or_default() { 282 282 let names = self.names.clone(); 283 283 for pattern in &clause.pattern { 284 284 self.pattern(pattern);
+21
compiler-core/src/error.rs
··· 3066 3066 } 3067 3067 } 3068 3068 3069 + TypeError::MissingCaseBody { location } => { 3070 + let text = wrap( 3071 + "This case expression is missing its body." 3072 + ); 3073 + Diagnostic { 3074 + title: "Missing case body".into(), 3075 + text, 3076 + hint: None, 3077 + level: Level::Error, 3078 + location: Some(Location { 3079 + src: src.clone(), 3080 + path: path.to_path_buf(), 3081 + label: Label { 3082 + text: None, 3083 + span: *location, 3084 + }, 3085 + extra_labels: Vec::new(), 3086 + }), 3087 + } 3088 + } 3089 + 3069 3090 TypeError::UnsupportedExpressionTarget { 3070 3091 location, 3071 3092 target: current_target,
+1 -1
compiler-core/src/format.rs
··· 1030 1030 subjects, 1031 1031 clauses, 1032 1032 location, 1033 - } => self.case(subjects, clauses, location), 1033 + } => self.case(subjects, clauses.as_deref().unwrap_or_default(), location), 1034 1034 1035 1035 UntypedExpr::FieldAccess { 1036 1036 label, container, ..
+24 -11
compiler-core/src/parse.rs
··· 701 701 self.advance(); 702 702 let subjects = 703 703 Parser::series_of(self, &Parser::parse_expression, Some(&Token::Comma))?; 704 - let _ = self.expect_one_following_series(&Token::LeftBrace, "an expression")?; 705 - let clauses = Parser::series_of(self, &Parser::parse_case_clause, None)?; 706 - let (_, end) = 707 - self.expect_one_following_series(&Token::RightBrace, "a case clause")?; 708 - if subjects.is_empty() { 709 - return parse_error( 710 - ParseErrorType::ExpectedExpr, 711 - SrcSpan { start, end: case_e }, 712 - ); 704 + if self.maybe_one(&Token::LeftBrace).is_some() { 705 + let clauses = Parser::series_of(self, &Parser::parse_case_clause, None)?; 706 + let (_, end) = 707 + self.expect_one_following_series(&Token::RightBrace, "a case clause")?; 708 + if subjects.is_empty() { 709 + return parse_error( 710 + ParseErrorType::ExpectedExpr, 711 + SrcSpan { start, end: case_e }, 712 + ); 713 + } else { 714 + UntypedExpr::Case { 715 + location: SrcSpan { start, end }, 716 + subjects, 717 + clauses: Some(clauses), 718 + } 719 + } 713 720 } else { 714 721 UntypedExpr::Case { 715 - location: SrcSpan { start, end }, 722 + location: SrcSpan::new( 723 + start, 724 + subjects 725 + .last() 726 + .map(|subject| subject.location().end) 727 + .unwrap_or(case_e), 728 + ), 716 729 subjects, 717 - clauses, 730 + clauses: None, 718 731 } 719 732 } 720 733 }
+68 -66
compiler-core/src/parse/snapshots/gleam_core__parse__tests__arithmetic_in_guards.snap
··· 27 27 int_value: 3, 28 28 }, 29 29 ], 30 - clauses: [ 31 - Clause { 32 - location: SrcSpan { 33 - start: 17, 34 - end: 43, 35 - }, 36 - pattern: [ 37 - Variable { 38 - location: SrcSpan { 39 - start: 17, 40 - end: 18, 41 - }, 42 - name: "x", 43 - type_: (), 44 - origin: Variable( 45 - "x", 46 - ), 30 + clauses: Some( 31 + [ 32 + Clause { 33 + location: SrcSpan { 34 + start: 17, 35 + end: 43, 47 36 }, 48 - Variable { 49 - location: SrcSpan { 50 - start: 20, 51 - end: 21, 37 + pattern: [ 38 + Variable { 39 + location: SrcSpan { 40 + start: 17, 41 + end: 18, 42 + }, 43 + name: "x", 44 + type_: (), 45 + origin: Variable( 46 + "x", 47 + ), 52 48 }, 53 - name: "y", 54 - type_: (), 55 - origin: Variable( 56 - "y", 57 - ), 58 - }, 59 - ], 60 - alternative_patterns: [], 61 - guard: Some( 62 - Equals { 63 - location: SrcSpan { 64 - start: 25, 65 - end: 35, 49 + Variable { 50 + location: SrcSpan { 51 + start: 20, 52 + end: 21, 53 + }, 54 + name: "y", 55 + type_: (), 56 + origin: Variable( 57 + "y", 58 + ), 66 59 }, 67 - left: AddInt { 60 + ], 61 + alternative_patterns: [], 62 + guard: Some( 63 + Equals { 68 64 location: SrcSpan { 69 65 start: 25, 70 - end: 30, 66 + end: 35, 71 67 }, 72 - left: Var { 68 + left: AddInt { 73 69 location: SrcSpan { 74 70 start: 25, 75 - end: 26, 71 + end: 30, 72 + }, 73 + left: Var { 74 + location: SrcSpan { 75 + start: 25, 76 + end: 26, 77 + }, 78 + type_: (), 79 + name: "x", 76 80 }, 77 - type_: (), 78 - name: "x", 81 + right: Var { 82 + location: SrcSpan { 83 + start: 29, 84 + end: 30, 85 + }, 86 + type_: (), 87 + name: "y", 88 + }, 79 89 }, 80 - right: Var { 81 - location: SrcSpan { 82 - start: 29, 83 - end: 30, 90 + right: Constant( 91 + Int { 92 + location: SrcSpan { 93 + start: 34, 94 + end: 35, 95 + }, 96 + value: "1", 97 + int_value: 1, 84 98 }, 85 - type_: (), 86 - name: "y", 87 - }, 99 + ), 100 + }, 101 + ), 102 + then: Var { 103 + location: SrcSpan { 104 + start: 39, 105 + end: 43, 88 106 }, 89 - right: Constant( 90 - Int { 91 - location: SrcSpan { 92 - start: 34, 93 - end: 35, 94 - }, 95 - value: "1", 96 - int_value: 1, 97 - }, 98 - ), 107 + name: "True", 99 108 }, 100 - ), 101 - then: Var { 102 - location: SrcSpan { 103 - start: 39, 104 - end: 43, 105 - }, 106 - name: "True", 107 109 }, 108 - }, 109 - ], 110 + ], 111 + ), 110 112 }, 111 113 ), 112 114 ]
+24
compiler-core/src/parse/snapshots/gleam_core__parse__tests__case_expression_without_body.snap
··· 1 + --- 2 + source: compiler-core/src/parse/tests.rs 3 + expression: case a 4 + --- 5 + [ 6 + Expression( 7 + Case { 8 + location: SrcSpan { 9 + start: 0, 10 + end: 6, 11 + }, 12 + subjects: [ 13 + Var { 14 + location: SrcSpan { 15 + start: 5, 16 + end: 6, 17 + }, 18 + name: "a", 19 + }, 20 + ], 21 + clauses: None, 22 + }, 23 + ), 24 + ]
+1 -2
compiler-core/src/parse/snapshots/gleam_core__parse__tests__case_invalid_expression.snap
··· 19 19 │ ^^^^ I was not expecting this 20 20 21 21 Found the keyword `type`, expected one of: 22 - - `{` 23 - - an expression 22 + - `}`
+24
compiler-core/src/parse/snapshots/gleam_core__parse__tests__case_without_body.snap
··· 1 + --- 2 + source: compiler-core/src/parse/tests.rs 3 + expression: case a 4 + --- 5 + [ 6 + Expression( 7 + Case { 8 + location: SrcSpan { 9 + start: 0, 10 + end: 6, 11 + }, 12 + subjects: [ 13 + Var { 14 + location: SrcSpan { 15 + start: 5, 16 + end: 6, 17 + }, 18 + name: "a", 19 + }, 20 + ], 21 + clauses: [], 22 + }, 23 + ), 24 + ]
+5
compiler-core/src/parse/tests.rs
··· 1678 1678 fn nested_tuple_access_after_function() { 1679 1679 assert_parse!("tuple().0.1"); 1680 1680 } 1681 + 1682 + #[test] 1683 + fn case_expression_without_body() { 1684 + assert_parse!("case a"); 1685 + }
+6
compiler-core/src/type_/error.rs
··· 443 443 missing: Vec<EcoString>, 444 444 }, 445 445 446 + /// A case expression is missing its body. 447 + MissingCaseBody { 448 + location: SrcSpan, 449 + }, 450 + 446 451 /// Let assignment's pattern does not match all possible values of the type. 447 452 InexhaustiveLetAssignment { 448 453 location: SrcSpan, ··· 1031 1036 | Error::InvalidExternalJavascriptModule { location, .. } 1032 1037 | Error::InvalidExternalJavascriptFunction { location, .. } 1033 1038 | Error::InexhaustiveCaseExpression { location, .. } 1039 + | Error::MissingCaseBody { location } 1034 1040 | Error::InexhaustiveLetAssignment { location, .. } 1035 1041 | Error::UnusedTypeAliasParameter { location, .. } 1036 1042 | Error::DuplicateTypeParameter { location, .. }
+15 -2
compiler-core/src/type_/expression.rs
··· 1428 1428 fn infer_case( 1429 1429 &mut self, 1430 1430 subjects: Vec<UntypedExpr>, 1431 - clauses: Vec<UntypedClause>, 1431 + clauses: Option<Vec<UntypedClause>>, 1432 1432 location: SrcSpan, 1433 1433 ) -> TypedExpr { 1434 1434 let subjects_count = subjects.len(); 1435 1435 let mut typed_subjects = Vec::with_capacity(subjects_count); 1436 1436 let mut subject_types = Vec::with_capacity(subjects_count); 1437 - let mut typed_clauses = Vec::with_capacity(clauses.len()); 1438 1437 1439 1438 let return_type = self.new_unbound_var(); 1440 1439 ··· 1459 1458 typed_subjects.push(subject); 1460 1459 } 1461 1460 1461 + let clauses = match clauses { 1462 + Some(clauses) => clauses, 1463 + None => { 1464 + self.problems.error(Error::MissingCaseBody { location }); 1465 + return TypedExpr::Case { 1466 + location: location, 1467 + type_: self.new_unbound_var(), 1468 + subjects: typed_subjects, 1469 + clauses: Vec::new(), 1470 + }; 1471 + } 1472 + }; 1473 + 1474 + let mut typed_clauses = Vec::with_capacity(clauses.len()); 1462 1475 let mut has_a_guard = false; 1463 1476 let mut all_patterns_are_discards = true; 1464 1477 // NOTE: if there are 0 clauses then there are 0 panics