@@ -1291,3 +1291,256 @@ let completionPathFromMaybeBuiltin path =
12911291 (* Route Stdlib_X to Stdlib.X for proper completions without the Stdlib_ prefix *)
12921292 Some (String. split_on_char '_' mainModule)
12931293 | _ -> None )
1294+
1295+ module ExpandType = struct
1296+ type expandTypeInput =
1297+ | TypeExpr of {
1298+ typeExpr : Types .type_expr ;
1299+ name : string Location .loc option ;
1300+ env : QueryEnv .t ;
1301+ }
1302+ | TypeDecl of {
1303+ typeDecl : Types .type_declaration ;
1304+ name : string Location .loc ;
1305+ env : QueryEnv .t ;
1306+ }
1307+
1308+ type expandTypeReturn = {
1309+ mainTypes : expandTypeInput list ;
1310+ relatedTypes : expandTypeInput list ;
1311+ }
1312+
1313+ module TypeIdSet = Set. Make (String )
1314+
1315+ let expandTypes (input : expandTypeInput ) ~(full : SharedTypes.full ) =
1316+ let rootEnv = QueryEnv. fromFile full.file in
1317+
1318+ let expandTypeInputToKey = function
1319+ | TypeExpr {name; env} ->
1320+ typeId ~env
1321+ ~name:
1322+ (match name with
1323+ | None -> Location. mkloc " <unknown>" Location. none
1324+ | Some n -> n)
1325+ | TypeDecl {name; env} -> typeId ~env ~name
1326+ in
1327+
1328+ let deduplicateAndRemoveAlreadyPresent mainTypes relatedTypes =
1329+ let mainIds = ref TypeIdSet. empty in
1330+ let dedupedMain =
1331+ mainTypes
1332+ |> List. fold_left
1333+ (fun acc item ->
1334+ let id = expandTypeInputToKey item in
1335+ if TypeIdSet. mem id ! mainIds then acc
1336+ else (
1337+ mainIds := TypeIdSet. add id ! mainIds;
1338+ item :: acc))
1339+ []
1340+ |> List. rev
1341+ in
1342+
1343+ let relatedIds = ref TypeIdSet. empty in
1344+ let dedupedRelated =
1345+ relatedTypes
1346+ |> List. fold_left
1347+ (fun acc item ->
1348+ let id = expandTypeInputToKey item in
1349+ if TypeIdSet. mem id ! mainIds || TypeIdSet. mem id ! relatedIds then
1350+ acc
1351+ else (
1352+ relatedIds := TypeIdSet. add id ! relatedIds;
1353+ item :: acc))
1354+ []
1355+ |> List. rev
1356+ in
1357+
1358+ (dedupedMain, dedupedRelated)
1359+ in
1360+
1361+ let rec followTypeAliases acc (typeExpr : Types.type_expr ) =
1362+ match typeExpr.desc with
1363+ | Tlink t1 | Tsubst t1 | Tpoly (t1 , [] ) -> followTypeAliases acc t1
1364+ | Tconstr (path , typeArgs , _ ) -> (
1365+ match
1366+ References. digConstructor ~env: rootEnv ~package: full.package path
1367+ with
1368+ | Some
1369+ ( env,
1370+ {
1371+ name;
1372+ item = {decl = {type_manifest = Some t1; type_params} as decl};
1373+ } ) ->
1374+ let instantiated =
1375+ instantiateType ~type Params:type_params ~type Args t1
1376+ in
1377+ let currentAlias = TypeDecl {typeDecl = decl; name; env} in
1378+ followTypeAliases (currentAlias :: acc) instantiated
1379+ | Some (env , {name; item = {decl} } ) ->
1380+ TypeDecl {typeDecl = decl; name; env} :: acc
1381+ | None -> acc)
1382+ | _ -> acc
1383+ in
1384+
1385+ let rec findFinalConcreteType (typeExpr : Types.type_expr ) =
1386+ match typeExpr.desc with
1387+ | Tlink t1 | Tsubst t1 | Tpoly (t1 , [] ) -> findFinalConcreteType t1
1388+ | Tconstr (path , typeArgs , _ ) -> (
1389+ match
1390+ References. digConstructor ~env: rootEnv ~package: full.package path
1391+ with
1392+ | Some (_env, {item = {decl = {type_manifest = Some t1; type_params}}})
1393+ ->
1394+ let instantiated =
1395+ instantiateType ~type Params:type_params ~type Args t1
1396+ in
1397+ findFinalConcreteType instantiated
1398+ | _ -> typeExpr)
1399+ | _ -> typeExpr
1400+ in
1401+
1402+ let rec extractRelevantTypesFromTypeExpr ?(depth = 0 )
1403+ (typeExpr : Types.type_expr ) =
1404+ if depth > 1 then []
1405+ else
1406+ match typeExpr.desc with
1407+ | Tlink t1 | Tsubst t1 | Tpoly (t1 , [] ) ->
1408+ extractRelevantTypesFromTypeExpr ~depth t1
1409+ | Tconstr (path , typeArgs , _ ) ->
1410+ let constructorTypes =
1411+ match
1412+ References. digConstructor ~env: rootEnv ~package: full.package path
1413+ with
1414+ | Some (env , {name; item = {kind = Record fields ; decl} } ) ->
1415+ TypeDecl {typeDecl = decl; name; env}
1416+ ::
1417+ (if depth = 0 then
1418+ fields
1419+ |> List. fold_left
1420+ (fun acc field ->
1421+ acc
1422+ @ extractRelevantTypesFromTypeExpr ~depth: (depth + 1 )
1423+ field.typ)
1424+ []
1425+ else [] )
1426+ | Some (env , {name; item = {kind = Variant constructors ; decl} } ) ->
1427+ TypeDecl {typeDecl = decl; name; env}
1428+ ::
1429+ (if depth = 0 then
1430+ constructors
1431+ |> List. fold_left
1432+ (fun acc (constructor : Constructor.t ) ->
1433+ match constructor.args with
1434+ | Args args ->
1435+ args
1436+ |> List. fold_left
1437+ (fun acc (argType , _ ) ->
1438+ acc
1439+ @ extractRelevantTypesFromTypeExpr
1440+ ~depth: (depth + 1 ) argType)
1441+ acc
1442+ | InlineRecord fields ->
1443+ fields
1444+ |> List. fold_left
1445+ (fun acc field ->
1446+ acc
1447+ @ extractRelevantTypesFromTypeExpr
1448+ ~depth: (depth + 1 ) field.typ)
1449+ acc)
1450+ []
1451+ else [] )
1452+ | Some (_env , {item = {decl = {type_manifest = Some t1 } } } ) ->
1453+ extractRelevantTypesFromTypeExpr ~depth t1
1454+ | _ -> []
1455+ in
1456+ let typeArgTypes =
1457+ typeArgs
1458+ |> List. fold_left
1459+ (fun acc typeArg ->
1460+ acc
1461+ @ extractRelevantTypesFromTypeExpr ~depth: (depth + 1 ) typeArg)
1462+ []
1463+ in
1464+ constructorTypes @ typeArgTypes
1465+ | Tvariant {row_fields} when depth = 0 ->
1466+ row_fields
1467+ |> List. fold_left
1468+ (fun acc (_label , field ) ->
1469+ match field with
1470+ | Types. Rpresent (Some typeExpr ) ->
1471+ acc
1472+ @ extractRelevantTypesFromTypeExpr ~depth: (depth + 1 )
1473+ typeExpr
1474+ | Reither (_ , typeExprs , _ , _ ) ->
1475+ typeExprs
1476+ |> List. fold_left
1477+ (fun acc typeExpr ->
1478+ acc
1479+ @ extractRelevantTypesFromTypeExpr ~depth: (depth + 1 )
1480+ typeExpr)
1481+ acc
1482+ | _ -> acc)
1483+ []
1484+ | _ -> []
1485+ in
1486+
1487+ let extractRelevantTypesFromTypeDecl (typeDecl : Types.type_declaration ) =
1488+ match typeDecl.type_manifest with
1489+ | Some typeExpr -> extractRelevantTypesFromTypeExpr typeExpr
1490+ | None -> (
1491+ match typeDecl.type_kind with
1492+ | Type_record (label_declarations , _ ) ->
1493+ label_declarations
1494+ |> List. fold_left
1495+ (fun acc (label_decl : Types.label_declaration ) ->
1496+ acc
1497+ @ extractRelevantTypesFromTypeExpr ~depth: 1 label_decl.ld_type)
1498+ []
1499+ | Type_variant constructor_declarations ->
1500+ constructor_declarations
1501+ |> List. fold_left
1502+ (fun acc (constructor_decl : Types.constructor_declaration ) ->
1503+ match constructor_decl.cd_args with
1504+ | Cstr_tuple type_exprs ->
1505+ type_exprs
1506+ |> List. fold_left
1507+ (fun acc type_expr ->
1508+ acc
1509+ @ extractRelevantTypesFromTypeExpr ~depth: 1 type_expr)
1510+ acc
1511+ | Cstr_record label_declarations ->
1512+ label_declarations
1513+ |> List. fold_left
1514+ (fun acc (label_decl : Types.label_declaration ) ->
1515+ acc
1516+ @ extractRelevantTypesFromTypeExpr ~depth: 1
1517+ label_decl.ld_type)
1518+ acc)
1519+ []
1520+ | Type_abstract | Type_open -> [] )
1521+ in
1522+
1523+ match input with
1524+ | TypeExpr {typeExpr; name; env} ->
1525+ let aliases = followTypeAliases [] typeExpr in
1526+ let mainTypesRaw = TypeExpr {typeExpr; name; env} :: aliases in
1527+
1528+ (* Extract related types from the final concrete type *)
1529+ let finalConcreteType = findFinalConcreteType typeExpr in
1530+ let relatedTypesRaw =
1531+ extractRelevantTypesFromTypeExpr finalConcreteType
1532+ in
1533+
1534+ let mainTypes, relatedTypes =
1535+ deduplicateAndRemoveAlreadyPresent mainTypesRaw relatedTypesRaw
1536+ in
1537+ {mainTypes; relatedTypes}
1538+ | TypeDecl {typeDecl} ->
1539+ let mainTypes = [input] in
1540+ let relatedTypesRaw = extractRelevantTypesFromTypeDecl typeDecl in
1541+
1542+ let _, relatedTypes =
1543+ deduplicateAndRemoveAlreadyPresent mainTypes relatedTypesRaw
1544+ in
1545+ {mainTypes; relatedTypes}
1546+ end
0 commit comments