@@ -454,8 +454,12 @@ type IncrementalOptimizationEnv =
454454 { /// An identifier to help with name generation
455455 latestBoundId: Ident option
456456
457- /// The set of lambda IDs we've inlined to reach this point. Helps to prevent recursive inlining
458- dontInline: Zset < Unique >
457+ /// Prevents recursive inlining/specialization. Maps lambda ID to a list of specialized types
458+ /// currently being processed. An empty list means "block unconditionally" (used by normal
459+ /// inlining and non-concrete debug specialization). A non-empty list means "block only these
460+ /// specific type specializations" (used by concrete debug specialization, allowing different
461+ /// type instantiations of the same function to proceed).
462+ dontInline: Map < Stamp , TType list >
459463
460464 /// Recursively bound vars. If an sub-expression that is a candidate for method splitting
461465 /// contains any of these variables then don't split it, for fear of mucking up tailcalls.
@@ -479,7 +483,7 @@ type IncrementalOptimizationEnv =
479483
480484 static member Empty =
481485 { latestBoundId = None
482- dontInline = Zset .empty Int64.order
486+ dontInline = Map .empty
483487 typarInfos = []
484488 functionVal = None
485489 dontSplitVars = ValMap.Empty
@@ -3481,22 +3485,35 @@ and TryInlineApplication cenv env finfo (valExpr: Expr) (tyargs: TType list, arg
34813485
34823486 let origFinfo = GetInfoForValWithCheck cenv env m vref
34833487 match stripValue origFinfo.ValExprInfo with
3484- | CurriedLambdaValue( origLambdaId, _, _, origLambda, origLambdaTy) when not ( Zset.contains origLambdaId env.dontInline ) ->
3488+ | CurriedLambdaValue( origLambdaId, _, _, origLambda, origLambdaTy) ->
34853489 let f2R = CopyExprForInlining cenv true origLambda m
34863490 let specLambda = MakeApplicationAndBetaReduce g ( f2R, origLambdaTy, [ tyargs], [], m)
34873491 let specLambdaTy = tyOfExpr g specLambda
34883492
3493+ // For concrete type args, only block the exact same (stamp, type) pair, allowing different
3494+ // type instantiations to proceed (e.g. sum<int, int->int> calling sum<int, int> in its body).
3495+ // For non-concrete type args, block unconditionally.
3496+ let shouldInline =
3497+ match Map.tryFind origLambdaId env.dontInline with
3498+ | Some tys -> not allTyargsAreConcrete || tys.IsEmpty || tys |> List.exists ( typeEquiv g specLambdaTy)
3499+ | None -> false
3500+
3501+ if shouldInline then
3502+ None else
3503+
34893504 let specLambdaR =
34903505 if allTyargsAreConcrete then
34913506 match cenv.specializedInlineVals.FindAll( origLambdaId) |> List.tryFind ( fun ( ty , _ ) -> typeEquiv g ty specLambdaTy) with
34923507 | Some (_, body) -> copyExpr g CloneAll body
34933508 | None ->
34943509
3495- let specLambdaR , _ = OptimizeExpr cenv { env with dontInline = Zset.add origLambdaId env.dontInline } specLambda
3510+ let existingTypes = defaultArg ( Map.tryFind origLambdaId env.dontInline) []
3511+ let env = { env with dontInline = Map.add origLambdaId ( specLambdaTy :: existingTypes) env.dontInline }
3512+ let specLambdaR , _ = OptimizeExpr cenv env specLambda
34963513 cenv.specializedInlineVals.Add( origLambdaId, ( specLambdaTy, specLambdaR))
34973514 specLambdaR
34983515 else
3499- let specLambdaR , _ = OptimizeExpr cenv { env with dontInline = Zset .add origLambdaId env.dontInline } specLambda
3516+ let specLambdaR , _ = OptimizeExpr cenv { env with dontInline = Map .add origLambdaId [] env.dontInline } specLambda
35003517 specLambdaR
35013518
35023519 let specLambdaR =
@@ -3537,7 +3554,7 @@ and TryInlineApplication cenv env finfo (valExpr: Expr) (tyargs: TType list, arg
35373554 cenv.settings.InlineLambdas &&
35383555 not finfo.HasEffect &&
35393556 // Don't inline recursively!
3540- not ( Zset.contains lambdaId env.dontInline) &&
3557+ not ( Map.containsKey lambdaId env.dontInline) &&
35413558 ( // Check the number of argument groups is enough to saturate the lambdas of the target.
35423559 ( if tyargs |> List.exists ( fun t -> match t with TType_ measure _ -> false | _ -> true ) then 1 else 0 ) + args.Length = arities &&
35433560 if size <= cenv.settings.lambdaInlineThreshold + args.Length then true
@@ -3609,7 +3626,7 @@ and TryInlineApplication cenv env finfo (valExpr: Expr) (tyargs: TType list, arg
36093626 // Inlining: beta reducing
36103627 let exprR = MakeApplicationAndBetaReduce g ( f2R, f2ty, [ tyargs], argsR, m)
36113628 // Inlining: reoptimizing
3612- Some( OptimizeExpr cenv { env with dontInline= Zset .add lambdaId env.dontInline} exprR)
3629+ Some( OptimizeExpr cenv { env with dontInline = Map .add lambdaId [] env.dontInline} exprR)
36133630
36143631 | _ -> None
36153632
0 commit comments