@@ -1020,7 +1020,7 @@ resolve index cache annotation =
10201020 getRestrictions annotation cache
10211021 in
10221022 newAnnotation
1023- |> rewriteTypeVariables
1023+ |> rewriteTypeVariables cache
10241024 |> checkRestrictions restrictions
10251025
10261026 Err err ->
@@ -1286,30 +1286,130 @@ getRestrictionsHelper existingRestrictions notation cache =
12861286 existingRestrictions
12871287
12881288
1289- rewriteTypeVariables : Annotation .TypeAnnotation -> Annotation .TypeAnnotation
1290- rewriteTypeVariables type_ =
1289+ {- | Rewrite type variable names to clean forms, preserving typeclass
1290+ constraint names.
1291+
1292+ When a constrained type variable (like `number_0`) gets resolved to
1293+ another generic variable (like `arg_0`), the constraint name is lost.
1294+ This function builds a mapping from resolved variable names back to
1295+ their constraint names, so `arg_0` gets renamed to `number` instead
1296+ of `a`.
1297+ -}
1298+ rewriteTypeVariables :
1299+ VariableCache
1300+ -> Annotation . TypeAnnotation
1301+ -> Annotation . TypeAnnotation
1302+ rewriteTypeVariables cache resolvedAnnotation =
12911303 let
1304+ -- Build a map from resolved generic names to constraint names.
1305+ -- Check BOTH directions:
1306+ -- 1. Forward: a constrained name (number_0) maps to a generic (arg_0)
1307+ -- 2. Reverse: a generic (arg_0) maps to a constrained name (comparable)
1308+ -- Case 2 happens with applyInfix operators that use fixed names
1309+ -- like "comparable" which then get unified with arg variables.
1310+ constraintOverrides : Dict String String
1311+ constraintOverrides =
1312+ Dict . foldl
1313+ ( \ key value acc ->
1314+ case value of
1315+ Annotation . GenericType resolvedName ->
1316+ let
1317+ keyRestriction =
1318+ nameToRestrictions key
1319+ in
1320+ case keyRestriction of
1321+ NoRestrictions ->
1322+ -- Key has no constraint, but maybe the
1323+ -- resolved name does (reverse direction)
1324+ let
1325+ resolvedRestriction =
1326+ nameToRestrictions resolvedName
1327+ in
1328+ case resolvedRestriction of
1329+ NoRestrictions ->
1330+ acc
1331+
1332+ _ ->
1333+ -- The target has a constraint — propagate
1334+ -- it to the key name
1335+ Dict . insert key
1336+ ( restrictionToName resolvedRestriction)
1337+ acc
1338+
1339+ _ ->
1340+ -- Key has a constraint — propagate to resolved name
1341+ Dict . insert resolvedName
1342+ ( restrictionToName keyRestriction)
1343+ acc
1344+
1345+ _ ->
1346+ acc
1347+ )
1348+ Dict . empty
1349+ cache
1350+
12921351 existing : Set String
12931352 existing =
1294- getGenericsHelper type_
1353+ getGenericsHelper resolvedAnnotation
12951354 |> Set . fromList
12961355 in
1297- Tuple . second ( rewriteTypeVariablesHelper existing Dict . empty type_)
1356+ Tuple . second
1357+ ( rewriteTypeVariablesHelper
1358+ constraintOverrides
1359+ existing
1360+ Dict . empty
1361+ resolvedAnnotation
1362+ )
1363+
12981364
1365+ restrictionToName : Restrictions -> String
1366+ restrictionToName restriction =
1367+ case restriction of
1368+ IsNumber ->
1369+ " number"
1370+
1371+ IsComparable ->
1372+ " comparable"
1373+
1374+ IsAppendable ->
1375+ " appendable"
1376+
1377+ IsAppendableComparable ->
1378+ " compappend"
12991379
1300- rewriteTypeVariablesHelper : Set String -> Dict String String -> Annotation .TypeAnnotation -> ( Dict String String , Annotation .TypeAnnotation )
1301- rewriteTypeVariablesHelper existing renames type_ =
1380+ _ ->
1381+ " a"
1382+
1383+
1384+ {- | Rewrite type variable names to clean, simplified forms.
1385+
1386+ The `overrides` dict maps variable names to constraint names
1387+ (e.g., "arg\_0" → "number") so that typeclass constraints are
1388+ preserved through the renaming process. Pass `Dict.empty` when
1389+ no constraint preservation is needed.
1390+ -}
1391+ rewriteTypeVariablesHelper :
1392+ Dict String String
1393+ -> Set String
1394+ -> Dict String String
1395+ -> Annotation . TypeAnnotation
1396+ -> ( Dict String String , Annotation . TypeAnnotation )
1397+ rewriteTypeVariablesHelper overrides existing renames type_ =
13021398 case type_ of
13031399 Annotation . GenericType varName ->
13041400 case Dict . get varName renames of
13051401 Nothing ->
13061402 let
13071403 simplified : String
13081404 simplified =
1309- simplify varName
1405+ case Dict . get varName overrides of
1406+ Just constraintName ->
1407+ constraintName
1408+
1409+ Nothing ->
1410+ simplify varName
13101411 in
13111412 if Set . member simplified existing && varName /= simplified then
1312- -- We would have collided with an existing generic name
13131413 ( renames, Annotation . GenericType simplified )
13141414
13151415 else
@@ -1326,7 +1426,7 @@ rewriteTypeVariablesHelper existing renames type_ =
13261426 ( \ ( Node _ typevar) ( varUsed, varList ) ->
13271427 let
13281428 ( oneUsed, oneType ) =
1329- rewriteTypeVariablesHelper existing varUsed typevar
1429+ rewriteTypeVariablesHelper overrides existing varUsed typevar
13301430 in
13311431 ( oneUsed, nodify oneType :: varList )
13321432 )
@@ -1351,10 +1451,10 @@ rewriteTypeVariablesHelper existing renames type_ =
13511451 Annotation . FunctionTypeAnnotation ( Node _ one) ( Node _ two) ->
13521452 let
13531453 ( oneUsed, oneType ) =
1354- rewriteTypeVariablesHelper existing renames one
1454+ rewriteTypeVariablesHelper overrides existing renames one
13551455
13561456 ( twoUsed, twoType ) =
1357- rewriteTypeVariablesHelper existing oneUsed two
1457+ rewriteTypeVariablesHelper overrides existing oneUsed two
13581458 in
13591459 ( twoUsed
13601460 , Annotation . FunctionTypeAnnotation
0 commit comments