{"record":{"id":"d02225215b0edf47","repo":"gleam-lang/gleam","slug":"expected-t1-to-be-a-direct-link-but-found-t1","errorCode":null,"errorMessage":"Expected t1 to be a direct link but found: {t1:?}","messagePattern":"Expected t1 to be a direct link but found: (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"compiler-core/src/type_/environment.rs","lineNumber":1248,"sourceCode":"        assert!(unify(t1.clone(), t2).is_ok());\n        assert_direct_link_to_unbound(t1.deref(), 2);\n\n        // And this would add a link to the var of the new link\n        // As unify is recursive, this eventually cause a stack overflow\n        let t2 = unbound(3);\n        assert!(unify(t1.clone(), t2).is_ok());\n        assert_direct_link_to_unbound(t1.deref(), 3);\n    }\n\n    fn assert_direct_link_to_unbound(t1: &Type, expect_id: u64) {\n        if let Type::Var { type_: var } = t1\n            && let TypeVar::Link { type_: link } = var.borrow().deref()\n            && let Type::Var { type_: var } = link.deref()\n            && let TypeVar::Unbound { id } = var.borrow().deref()\n        {\n            assert_eq!(*id, expect_id, \"Expected unbound id to be unified\")\n        } else {\n            panic!(\"Expected t1 to be a direct link but found: {t1:?}\")\n        }\n    }\n\n    fn unbound(id: u64) -> Arc<Type> {\n        Arc::new(Type::Var {\n            type_: Arc::new(RefCell::new(TypeVar::Unbound { id })),\n        })\n    }\n}\n","sourceCodeStart":1230,"sourceCodeEnd":1258,"githubUrl":"https://github.com/gleam-lang/gleam/blob/15b07c783065c92bb016b1b74ed0995a5259850f/compiler-core/src/type_/environment.rs#L1230-L1258","documentation":"A test-assertion panic in the Gleam type environment's unification test helpers (`environment.rs:1248`). The helper expects `t1` to be a `TypeVar::Link` directly pointing at a `TypeVar::Unbound` with a specific id (the result of unifying an unbound variable). If the structure differs — wrong shape, extra indirection, or a different id — it panics with a debug dump of `t1`.","triggerScenarios":"Running environment/unification unit tests where `assert_unified` (the helper containing this panic) receives a `t1` that is not a direct `Link -> Unbound` chain, or whose unbound id does not match `expect_id`.","commonSituations":"Compiler contributors changing unification logic so variables end up linked indirectly or not at all; tests updated to construct types differently (e.g. passing a named type instead of a var); refactors of `Type`/`TypeVar` shapes that break the pattern the helper matches on.","solutions":["Read the panic's `{t1:?}` dump to see the actual type structure and compare with the expected `Link(Unbound(id))` shape.","Fix the unification code under test so unifying an unbound variable links it directly to the other variable, preserving the expected id.","Update the test's expected id (`expect_id`) or the constructed input types if the test setup, not the unifier, is wrong.","If `Type`/`TypeVar` variants were refactored, update the helper's pattern match to the new representation."],"exampleFix":"// before (test asserting against the wrong id)\nassert_unified(t1, unbound(7));\n\n// after\nassert_unified(t1, unbound(3)); // match the id actually produced by unification","handlingStrategy":"type-guard","validationCode":"// Rust: verify the expected shape before asserting the id\nfn is_direct_link_to_unbound(t: &Type) -> Option<u64> {\n    match t {\n        Type::Var { type_ } => match &*type_.borrow() {\n            TypeVar::Link { type_: link } => match link.deref() {\n                Type::Var { type_ } => match &*type_.borrow() {\n                    TypeVar::Unbound { id } => Some(*id),\n                    _ => None,\n                },\n                _ => None,\n            },\n            _ => None,\n        },\n        _ => None,\n    }\n}","typeGuard":"fn is_direct_link_to_unbound(t: &Type) -> Option<u64> { /* unwrap Link->Unbound id, else None */ }","tryCatchPattern":"// Panics abort tests; prefer a descriptive assertion\nmatch is_direct_link_to_unbound(t1) {\n    Some(id) => assert_eq!(id, expect_id, \"unbound id mismatch\"),\n    None => panic!(\"t1 is not a direct link to unbound: {t1:?}\"),\n}","preventionTips":["Use the `{t1:?}` debug dump in the panic message to diagnose mismatches quickly.","Keep test helper pattern matches in sync whenever `Type`/`TypeVar` variants change.","After changing unification behaviour, run the environment test module to catch shape regressions early."],"tags":["type-system","unification","test-assertion","compiler-development"],"backgroundTag":"internal-invariant-violation","analyzedSha":"15b07c783065c92bb016b1b74ed0995a5259850f","analyzedAt":"2026-09-14T11:14:59.388Z","contentChangedAt":"2026-09-14T11:14:59.388Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}