Repository: gleam-lang/gleam (rust)

Issue:
compiler crash when a variant has duplicate labels in specific circumstance
```gleam
pub type X {
  A
  B(e0: Int, e0: Int)
}

fn compiler_crash(x: X) {
  case x {
    A -> todo
    _ -> todo
  }
}
```

1. One variant has a duplicate field
2. The other variant is used in a pattern match

```rust
Panic: compiler-core/src/exhaustiveness.rs:780
	Custom type variants must exist: Type { name: "X", hint: AlternativeTypes(["UtfCodepoint", "Bool", "Node", "X", "BitArray", "Nil", "Int", "List", "String", "Result", "Float"]) }
Gleam version: 1.5.0
Operating system: linux
``` 

Pull request:
Fix compiler crash on duplicate fields
Fixes #3713 
This is similar to several other bugs that arose from fault tolerance, where a type variant wouldn't be defined if it didn't have duplicate fields because the whole function would short-circuit from the `?` operator. This PR simply reports the error in `Problems` instead of returning.

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8e4531ada..eba8fa43e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -239,6 +239,10 @@
   item on its own line to make things easier to read.
   ([Giacomo Cavalieri](https://github.com/giacomocavalieri))
 
+- Fixed a bug where the compiler would crash when pattern matching on a type
+  which was defined with duplicate fields in one of its variants.
+  ([Surya Rose](https://github.com/GearsDatapacks))
+
 ## v1.5.1 - 2024-09-26
 
 ### Bug Fixes
diff --git a/compiler-core/src/analyse.rs b/compiler-core/src/analyse.rs
index 7a5bff7d7..4b5c39cbd 100644
--- a/compiler-core/src/analyse.rs
+++ b/compiler-core/src/analyse.rs
@@ -899,7 +899,6 @@ impl<'a, A> ModuleAnalyzer<'a, A> {
         type_parameters: &[&EcoString],
     ) -> Result<(), Error> {
         let CustomType {
-            location,
             publicity,
             opaque,
             name,
@@ -971,13 +970,13 @@ impl<'a, A> ModuleAnalyzer<'a, A> {
                 args_types.push(t);
 
                 // Register the label for this parameter, if there is one
-                if let Some((_, label)) = label {
-                    field_map.insert(label.clone(), i as u32).map_err(|_| {
-                        Error::DuplicateField {
+                if let Some((location, label)) = label {
+                    if field_map.insert(label.clone(), i as u32).is_err() {
+                        self.problems.error(Error::DuplicateField {
                             label: label.clone(),
                             location: *location,
-                        }
-                    })?;
+                        });
+                    };
                 }
             }
             let field_map = field_map.into_option();


Test patch:
diff --git a/compiler-core/src/type_/tests/errors.rs b/compiler-core/src/type_/tests/errors.rs
index f5e16957c..2bb6ad1bb 100644
--- a/compiler-core/src/type_/tests/errors.rs
+++ b/compiler-core/src/type_/tests/errors.rs
@@ -2471,3 +2471,23 @@ pub fn main() {
 "
     );
 }
+
+#[test]
+fn no_crash_on_duplicate_record_fields() {
+    // https://github.com/gleam-lang/gleam/issues/3713
+    assert_module_error!(
+        "
+pub type X {
+  A
+  B(e0: Int, e0: Int)
+}
+
+fn compiler_crash(x: X) {
+  case x {
+    A -> todo
+    _ -> todo
+  }
+}
+  "
+    );
+}
diff --git a/compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__no_crash_on_duplicate_record_fields.snap b/compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__no_crash_on_duplicate_record_fields.snap
new file mode 100644
index 000000000..c76ba5a71
--- /dev/null
+++ b/compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__errors__no_crash_on_duplicate_record_fields.snap
@@ -0,0 +1,11 @@
+---
+source: compiler-core/src/type_/tests/errors.rs
+expression: "\npub type X {\n  A\n  B(e0: Int, e0: Int)\n}\n\nfn compiler_crash(x: X) {\n  case x {\n    A -> todo\n    _ -> todo\n  }\n}\n  "
+---
+error: Duplicate label
+  ┌─ /src/one/two.gleam:4:14
+  │
+4 │   B(e0: Int, e0: Int)
+  │              ^^
+
+The label `e0` has already been defined. Rename this label.