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

Configure Feed

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

Use `instanceof` checks for comparisons with empty lists

author
Gears
committer
Louis Pilfold
date (Jun 11, 2026, 11:11 AM +0100) commit 6c54c781 parent a6397ff4
+179 -28
+40 -21
compiler-core/src/javascript/expression.rs
··· 1889 1889 }); 1890 1890 Some(self.singleton_equal(left_doc, Some(module_alias), name, should_be_equal)) 1891 1891 } 1892 + // Empty lists are implemented as a variant with no fields, so we can 1893 + // use `instanceof` for a faster check. 1894 + TypedExpr::List { elements, .. } if elements.is_empty() => { 1895 + let left_doc = self.not_in_tail_position(Some(Ordering::Strict), |this| { 1896 + this.wrap_expression(left) 1897 + }); 1898 + self.tracker.list_empty_class_used = true; 1899 + Some(self.singleton_equal(left_doc, None, "$Empty".into(), should_be_equal)) 1900 + } 1892 1901 TypedExpr::Int { .. } 1893 1902 | TypedExpr::Float { .. } 1894 1903 | TypedExpr::String { .. } ··· 2409 2418 operator, 2410 2419 .. 2411 2420 } => { 2412 - let left_document = self.wrapped_guard(left); 2413 - let right_document = self.wrapped_guard(right); 2414 - 2415 2421 let operator = match operator { 2416 2422 BinOp::Eq if is_js_scalar(left.type_()) => "===", 2417 2423 BinOp::NotEq if is_js_scalar(left.type_()) => "!==", ··· 2447 2453 2448 2454 BinOp::DivFloat => { 2449 2455 self.tracker.float_division_used = true; 2456 + 2450 2457 return docvec![ 2451 2458 "divideFloat", 2452 - wrap_arguments([left_document, right_document]) 2459 + wrap_arguments([self.guard(left), self.guard(right)]) 2453 2460 ]; 2454 2461 } 2455 2462 ··· 2457 2464 self.tracker.int_division_used = true; 2458 2465 return docvec![ 2459 2466 "divideInt", 2460 - wrap_arguments([left_document, right_document]) 2467 + wrap_arguments([self.guard(left), self.guard(right)]) 2461 2468 ]; 2462 2469 } 2463 2470 ··· 2465 2472 self.tracker.int_remainder_used = true; 2466 2473 return docvec![ 2467 2474 "remainderInt", 2468 - wrap_arguments([left_document, right_document]) 2475 + wrap_arguments([self.guard(left), self.guard(right)]) 2469 2476 ]; 2470 2477 } 2471 2478 2472 2479 BinOp::And => "&&", 2473 2480 BinOp::Or => "||", 2474 2481 }; 2482 + 2483 + let left_document = self.wrapped_guard(left); 2484 + let right_document = self.wrapped_guard(right); 2475 2485 2476 2486 docvec![left_document, " ", operator, " ", right_document] 2477 2487 } ··· 2504 2514 right: &'a TypedClauseGuard, 2505 2515 should_be_equal: bool, 2506 2516 ) -> Option<Document<'a>> { 2507 - if let ClauseGuard::Constant(Constant::Record { 2508 - record_constructor: Some(constructor), 2509 - module, 2510 - name, 2511 - .. 2512 - }) = right 2513 - && let ValueConstructorVariant::Record { arity: 0, .. } = constructor.variant 2514 - { 2515 - let left_doc = self.guard(left); 2516 - return Some(self.singleton_equal( 2517 - left_doc, 2518 - module.as_ref().map(|(module, _)| module.as_str()), 2517 + match right { 2518 + ClauseGuard::Constant(Constant::Record { 2519 + record_constructor: Some(constructor), 2520 + module, 2519 2521 name, 2520 - should_be_equal, 2521 - )); 2522 + .. 2523 + }) if let ValueConstructorVariant::Record { arity: 0, .. } = constructor.variant => { 2524 + let left_doc = self.guard(left); 2525 + Some(self.singleton_equal( 2526 + left_doc, 2527 + module.as_ref().map(|(module, _)| module.as_str()), 2528 + name, 2529 + should_be_equal, 2530 + )) 2531 + } 2532 + ClauseGuard::Constant(Constant::List { 2533 + elements, 2534 + tail: None, 2535 + .. 2536 + }) if elements.is_empty() => { 2537 + let left_doc = self.guard(left); 2538 + self.tracker.list_empty_class_used = true; 2539 + Some(self.singleton_equal(left_doc, None, "$Empty", should_be_equal)) 2540 + } 2541 + _ => None, 2522 2542 } 2523 - None 2524 2543 } 2525 2544 2526 2545 fn wrapped_guard(&mut self, guard: &'a TypedClauseGuard) -> Document<'a> {
+50
compiler-core/src/javascript/tests/lists.rs
··· 111 111 "#, 112 112 ); 113 113 } 114 + 115 + #[test] 116 + fn comparison_with_empty_list() { 117 + assert_js!( 118 + " 119 + pub fn go(x) { 120 + x == [] && [] == x 121 + } 122 + " 123 + ); 124 + } 125 + 126 + #[test] 127 + fn negated_comparison_with_empty_list() { 128 + assert_js!( 129 + " 130 + pub fn go(x) { 131 + x != [] && [] != x 132 + } 133 + " 134 + ); 135 + } 136 + 137 + #[test] 138 + fn comparison_with_empty_list_ing_guard() { 139 + assert_js!( 140 + " 141 + pub fn go(x) { 142 + case x { 143 + _ if x == [] && [] == x -> 1 144 + _ -> 2 145 + } 146 + } 147 + " 148 + ); 149 + } 150 + 151 + #[test] 152 + fn negated_comparison_with_empty_list_ing_guard() { 153 + assert_js!( 154 + " 155 + pub fn go(x) { 156 + case x { 157 + _ if x != [] && [] != x -> 1 158 + _ -> 2 159 + } 160 + } 161 + " 162 + ); 163 + }
+2 -2
compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case_clause_guards__constructor_function_in_guard.snap
··· 12 12 13 13 14 14 ----- COMPILED JAVASCRIPT 15 - import { Ok, toList, isEqual } from "../gleam.mjs"; 15 + import { Ok, toList, Empty as $Empty } from "../gleam.mjs"; 16 16 17 17 export function func(x) { 18 18 let $ = toList([]); 19 - if (isEqual(toList([]), toList([(var0) => { return new Ok(var0); }]))) { 19 + if (toList([(var0) => { return new Ok(var0); }]) instanceof $Empty) { 20 20 return true; 21 21 } else { 22 22 return false;
+2 -2
compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case_clause_guards__imported_ok.snap
··· 17 17 18 18 ----- COMPILED JAVASCRIPT 19 19 import * as $gleam from "../gleam.mjs"; 20 - import { Ok, toList, CustomType as $CustomType, isEqual } from "../gleam.mjs"; 20 + import { Ok, toList, Empty as $Empty, CustomType as $CustomType } from "../gleam.mjs"; 21 21 22 22 export class Ok extends $CustomType {} 23 23 export const X$Ok = () => new Ok(); ··· 25 25 26 26 export function func(x) { 27 27 let $ = (var0) => { return new $gleam.Ok(var0); }; 28 - if (isEqual(toList([]), toList([(var0) => { return new Ok(var0); }]))) { 28 + if (toList([(var0) => { return new Ok(var0); }]) instanceof $Empty) { 29 29 return true; 30 30 } else { 31 31 return false;
+17
compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__lists__comparison_with_empty_list.snap
··· 1 + --- 2 + source: compiler-core/src/javascript/tests/lists.rs 3 + expression: "\npub fn go(x) {\n x == [] && [] == x\n}\n" 4 + --- 5 + ----- SOURCE CODE 6 + 7 + pub fn go(x) { 8 + x == [] && [] == x 9 + } 10 + 11 + 12 + ----- COMPILED JAVASCRIPT 13 + import { Empty as $Empty } from "../gleam.mjs"; 14 + 15 + export function go(x) { 16 + return (x instanceof $Empty) && (x instanceof $Empty); 17 + }
+24
compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__lists__comparison_with_empty_list_ing_guard.snap
··· 1 + --- 2 + source: compiler-core/src/javascript/tests/lists.rs 3 + expression: "\npub fn go(x) {\n case x {\n _ if x == [] && [] == x -> 1\n _ -> 2\n }\n}\n" 4 + --- 5 + ----- SOURCE CODE 6 + 7 + pub fn go(x) { 8 + case x { 9 + _ if x == [] && [] == x -> 1 10 + _ -> 2 11 + } 12 + } 13 + 14 + 15 + ----- COMPILED JAVASCRIPT 16 + import { Empty as $Empty } from "../gleam.mjs"; 17 + 18 + export function go(x) { 19 + if ((x instanceof $Empty) && (x instanceof $Empty)) { 20 + return 1; 21 + } else { 22 + return 2; 23 + } 24 + }
+3 -3
compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__lists__equality.snap
··· 11 11 12 12 13 13 ----- COMPILED JAVASCRIPT 14 - import { toList, isEqual } from "../gleam.mjs"; 14 + import { toList, Empty as $Empty } from "../gleam.mjs"; 15 15 16 16 export function go() { 17 - isEqual(toList([]), toList([1])); 18 - return !isEqual(toList([]), toList([1])); 17 + toList([1]) instanceof $Empty; 18 + return !(toList([1]) instanceof $Empty); 19 19 }
+17
compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__lists__negated_comparison_with_empty_list.snap
··· 1 + --- 2 + source: compiler-core/src/javascript/tests/lists.rs 3 + expression: "\npub fn go(x) {\n x != [] && [] != x\n}\n" 4 + --- 5 + ----- SOURCE CODE 6 + 7 + pub fn go(x) { 8 + x != [] && [] != x 9 + } 10 + 11 + 12 + ----- COMPILED JAVASCRIPT 13 + import { Empty as $Empty } from "../gleam.mjs"; 14 + 15 + export function go(x) { 16 + return (!(x instanceof $Empty)) && (!(x instanceof $Empty)); 17 + }
+24
compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__lists__negated_comparison_with_empty_list_ing_guard.snap
··· 1 + --- 2 + source: compiler-core/src/javascript/tests/lists.rs 3 + expression: "\npub fn go(x) {\n case x {\n _ if x != [] && [] != x -> 1\n _ -> 2\n }\n}\n" 4 + --- 5 + ----- SOURCE CODE 6 + 7 + pub fn go(x) { 8 + case x { 9 + _ if x != [] && [] != x -> 1 10 + _ -> 2 11 + } 12 + } 13 + 14 + 15 + ----- COMPILED JAVASCRIPT 16 + import { Empty as $Empty } from "../gleam.mjs"; 17 + 18 + export function go(x) { 19 + if ((!(x instanceof $Empty)) && (!(x instanceof $Empty))) { 20 + return 1; 21 + } else { 22 + return 2; 23 + } 24 + }