tala-frontend-0.1.0: src/Progmasoft/Tala/Template/Specialization.hs
-- SPDX-FileCopyrightText: 2026 Progmasoft <support@progmasoft.com>
-- SPDX-License-Identifier: MPL-2.0 WITH AdditionRef-Progmasoft-Exception-1.1
{- |
Declaration-level template specialization planning.
The application binder answers whether arguments fit a declaration and the
instantiator substitutes them. This module joins those operations into an
immutable batch plan suitable for a later demand-driven Core lowering pass.
It deliberately accepts explicit semantic demands. Resolved calls between
members of the selected declaration are followed by SymbolId so a lazy member
request remains closed under its internal call dependencies. Constraint
ordering and cross-declaration dispatch remain separate future stages.
-}
module Progmasoft.Tala.Template.Specialization
( TemplateDemandScope (..)
, TemplateSpecializationDemand (..)
, TemplateSpecializationLimits (..)
, defaultTemplateSpecializationLimits
, TemplateSpecializationId (..)
, TemplateSpecialization (..)
, TemplateSpecializationStatistics (..)
, TemplateSpecializationPlan (..)
, TemplateSpecializationError (..)
, planTemplateSpecializations
, findTemplateSpecialization
, findTemplateSpecializationByIdentity
, specializationEmissionOrder
, specializationTypedAST
, renderTemplateSpecializationError
) where
import Data.List (intercalate, sortOn)
import Data.Map.Strict (Map)
import Data.Map.Strict qualified as Map
import Progmasoft.Tala.AST
import Progmasoft.Tala.Template.Application
import Progmasoft.Tala.Template.Freshen
import Progmasoft.Tala.Template.Instantiation
import Progmasoft.Tala.Template.Mangling
import Progmasoft.Tala.Template.MemberReachability
{- | Layout-only requests do not instantiate method bodies. Member requests
select every overload carrying one of the requested spellings. Complete is
reserved for an explicit whole-declaration request; it is never inferred.
-}
data TemplateDemandScope
= -- | Retain layout and signatures without method bodies.
TemplateLayoutDemand
| -- | Retain named methods and their call closure.
TemplateMemberDemand [Identifier]
| -- | Explicit request for the complete declaration.
TemplateCompleteDemand
deriving (Eq, Ord, Read, Show)
-- | One source or compiler request to materialize a template specialization.
data TemplateSpecializationDemand = TemplateSpecializationDemand
{ specializationDemandApplication :: TemplateApplication
-- ^ Declaration and bound arguments requested.
, specializationDemandScope :: TemplateDemandScope
-- ^ Portion of the declaration that must be retained.
, specializationDemandOrigin :: String
-- ^ Stable provenance used in diagnostics and deduplication.
}
deriving (Eq, Ord, Read, Show)
-- | Resource ceilings preventing specialization requests from exhausting the compiler.
data TemplateSpecializationLimits = TemplateSpecializationLimits
{ maximumTemplateSpecializations :: Int
-- ^ Maximum unique specializations in one plan.
, maximumTemplateOrigins :: Int
-- ^ Maximum recorded request origins.
, maximumMembersPerSpecialization :: Int
-- ^ Maximum materialized members per specialization.
}
deriving (Eq, Ord, Read, Show)
-- | Finite defaults suitable for normal compiler and project builds.
defaultTemplateSpecializationLimits :: TemplateSpecializationLimits
defaultTemplateSpecializationLimits = TemplateSpecializationLimits 4096 16384 4096
-- | Stable ordinal identity within one specialization plan.
newtype TemplateSpecializationId = TemplateSpecializationId
{ templateSpecializationIdValue :: Int
}
deriving (Eq, Ord, Read, Show)
-- | One closed specialization and all identities needed by later lowering.
data TemplateSpecialization = TemplateSpecialization
{ templateSpecializationId :: TemplateSpecializationId
-- ^ Plan-local stable identity.
, templateSpecializationIdentity :: String
-- ^ Canonical concrete-type identity key.
, templateSpecializationType :: Type
-- ^ Closed concrete application type.
, templateSpecializationScope :: TemplateDemandScope
-- ^ Strongest coalesced materialization scope.
, templateSpecializationOrigins :: [String]
-- ^ All deduplicated request provenance strings.
, templateSpecializationDependencies :: [TemplateSpecializationId]
-- ^ Specializations referenced by this body.
, templateSpecializationDeclaration :: Declaration ResolvedName Type
-- ^ Instantiated and symbol-freshened declaration.
, templateSpecializationSymbolMap :: [(SymbolId, SymbolId)]
-- ^ Original-to-fresh definition identities.
, templateSpecializationMangledType :: MangledTemplateType
-- ^ Internal stable type symbol.
, templateSpecializationMangledMembers :: [MangledTemplateMember]
-- ^ Internal member symbols in declaration order.
}
deriving (Eq, Ord, Read, Show)
-- | Demand, coalescing, materialization, and dependency counts.
data TemplateSpecializationStatistics = TemplateSpecializationStatistics
{ requestedTemplateSpecializations :: Int
-- ^ Number of input demands.
, uniqueTemplateSpecializations :: Int
-- ^ Number of retained concrete specializations.
, coalescedTemplateSpecializations :: Int
-- ^ Requests merged into existing entries.
, instantiatedTemplateMembers :: Int
-- ^ Total members materialized across entries.
, retainedTemplateOrigins :: Int
-- ^ Provenance strings retained after merging.
, templateDependencyEdges :: Int
-- ^ Number of specialization-to-specialization edges.
}
deriving (Eq, Ord, Read, Show)
-- | Immutable batch result consumed by dependency ordering and Core lowering.
data TemplateSpecializationPlan = TemplateSpecializationPlan
{ plannedTemplateNamespace :: Maybe QualifiedName
-- ^ Namespace shared by source declarations.
, plannedTemplateSpecializations :: [TemplateSpecialization]
-- ^ Closed specializations retained in the plan.
, plannedTemplateStatistics :: TemplateSpecializationStatistics
-- ^ Aggregate counts for the plan.
}
deriving (Eq, Ord, Read, Show)
-- | Planning, binding, closure, resource, or internal-name generation failure.
data TemplateSpecializationError
= -- | A configured plan limit is invalid.
InvalidTemplateSpecializationLimits String
| -- | Binding failed for this demand.
TemplateApplicationFailed String [TemplateApplicationError]
| -- | Substitution failed during materialization.
TemplateInstantiationFailed String TemplateInstantiationError
| -- | Bound declaration has no matching source.
TemplateDeclarationSourceMissing QualifiedName SymbolId
| -- | Requested member spelling is absent.
TemplateMemberNotFound QualifiedName Identifier
| -- | Type/value variables remain after binding.
TemplateSpecializationRemainsOpen String [SymbolId]
| -- | Unique specialization count exceeded its ceiling.
TemplateSpecializationLimitExceeded Int String
| -- | Recorded provenance exceeded its ceiling.
TemplateOriginLimitExceeded Int String
| -- | Materialized member count exceeded its ceiling.
TemplateMemberLimitExceeded QualifiedName Int Int
| -- | Member call closure could not be computed.
TemplateMemberReachabilityFailed QualifiedName [TemplateMemberReachabilityError]
| -- | Concrete identity could not be encoded.
TemplateMangleFailed String [TemplateMangleError]
deriving (Eq, Ord, Read, Show)
data PreparedDemand = PreparedDemand
{ preparedBinding :: TemplateBinding
, preparedType :: Type
, preparedIdentity :: String
, preparedScope :: TemplateDemandScope
, preparedOrigins :: [String]
}
-- | Bind, coalesce, instantiate, freshen, and dependency-link explicit demands.
planTemplateSpecializations ::
TemplateSpecializationLimits ->
TypedAST ->
[TemplateSpecializationDemand] ->
Either [TemplateSpecializationError] TemplateSpecializationPlan
planTemplateSpecializations limits typed demands = do
validateLimits limits
prepared <- collectResults (map (prepareDemand catalog) demands)
let coalesced = coalesceDemands prepared
validateBatchLimits limits coalesced
materialized <- materializeAll limits typed sources coalesced
let linked = attachDependencies materialized
statistics =
TemplateSpecializationStatistics
{ requestedTemplateSpecializations = length demands
, uniqueTemplateSpecializations = length linked
, coalescedTemplateSpecializations = length demands - length linked
, instantiatedTemplateMembers = sum (map memberCount linked)
, retainedTemplateOrigins = sum (map (length . templateSpecializationOrigins) linked)
, templateDependencyEdges = sum (map (length . templateSpecializationDependencies) linked)
}
pure (TemplateSpecializationPlan namespace linked statistics)
where
TypedAST tree = typed
namespace = syntaxNamespace tree
catalog = buildTemplateCatalog typed
sources = declarationSources (syntaxDeclarations tree)
validateLimits :: TemplateSpecializationLimits -> Either [TemplateSpecializationError] ()
validateLimits limits
| maximumTemplateSpecializations limits <= 0 = invalid "maximum specialization count must be positive"
| maximumTemplateOrigins limits <= 0 = invalid "maximum origin count must be positive"
| maximumMembersPerSpecialization limits < 0 = invalid "maximum member count cannot be negative"
| otherwise = Right ()
where
invalid message = Left [InvalidTemplateSpecializationLimits message]
prepareDemand ::
TemplateCatalog ->
TemplateSpecializationDemand ->
Either [TemplateSpecializationError] PreparedDemand
prepareDemand catalog demand = case bindTemplateApplication catalog application of
Left failures -> Left [TemplateApplicationFailed origin failures]
Right binding -> case substituteType binding (templateApplicationType binding) of
Left failure -> Left [TemplateApplicationFailed origin [failure]]
Right concrete ->
let identity = renderSpecializationIdentity concrete
open = collectOpenSymbols concrete
in if null open
then
Right
( PreparedDemand
binding
concrete
identity
(normalizeScope (specializationDemandScope demand))
[origin]
)
else Left [TemplateSpecializationRemainsOpen identity open]
where
application = specializationDemandApplication demand
origin = specializationDemandOrigin demand
templateApplicationType :: TemplateBinding -> Type
templateApplicationType binding =
NamedType
(templateDeclarationName (templateBindingDeclaration binding))
(concatMap (map unwrap . snd) (templateBindingArguments binding))
where
unwrap (ExplicitTemplateArgument argument) = argument
unwrap (DefaultTemplateArgument argument) = argument
coalesceDemands :: [PreparedDemand] -> [PreparedDemand]
coalesceDemands = Map.elems . foldl' insert Map.empty
where
insert table demand = Map.insertWith merge (preparedIdentity demand) demand table
-- insertWith supplies the new request first. Keep the old binding so
-- source-order defaults remain the canonical representative, while
-- merging scope and unique origins from both requests.
merge new old =
old
{ preparedScope = mergeScope (preparedScope old) (preparedScope new)
, preparedOrigins = unique (preparedOrigins old ++ preparedOrigins new)
}
normalizeScope :: TemplateDemandScope -> TemplateDemandScope
normalizeScope scope = case scope of
TemplateMemberDemand names -> TemplateMemberDemand (unique names)
_ -> scope
mergeScope :: TemplateDemandScope -> TemplateDemandScope -> TemplateDemandScope
mergeScope TemplateCompleteDemand _ = TemplateCompleteDemand
mergeScope _ TemplateCompleteDemand = TemplateCompleteDemand
mergeScope TemplateLayoutDemand right = right
mergeScope left TemplateLayoutDemand = left
mergeScope (TemplateMemberDemand left) (TemplateMemberDemand right) =
TemplateMemberDemand (unique (left ++ right))
validateBatchLimits ::
TemplateSpecializationLimits ->
[PreparedDemand] ->
Either [TemplateSpecializationError] ()
validateBatchLimits limits prepared
| length prepared > maximumTemplateSpecializations limits =
Left
[ TemplateSpecializationLimitExceeded
(maximumTemplateSpecializations limits)
(preparedIdentity (prepared !! maximumTemplateSpecializations limits))
]
| originCount > maximumTemplateOrigins limits =
Left
[ TemplateOriginLimitExceeded
(maximumTemplateOrigins limits)
(firstOverflowOrigin (maximumTemplateOrigins limits) prepared)
]
| otherwise = Right ()
where
originCount = sum (map (length . preparedOrigins) prepared)
firstOverflowOrigin :: Int -> [PreparedDemand] -> String
firstOverflowOrigin limit prepared = case drop limit (concatMap preparedOrigins prepared) of
origin : _ -> origin
[] -> "<unknown-origin>"
materializeAll ::
TemplateSpecializationLimits ->
TypedAST ->
Map SymbolId (Declaration ResolvedName Type) ->
[PreparedDemand] ->
Either [TemplateSpecializationError] [TemplateSpecialization]
materializeAll limits typed sources prepared = go firstFresh 1 [] ordered
where
SymbolId maximumSource = maximumSymbolInTypedAST typed
firstFresh = SymbolId (maximumSource + 1)
ordered = sortOn preparedIdentity prepared
go _ _ output [] = Right (reverse output)
go next identifier output (demand : remaining) = do
(selected, selectedScope, memberTotal) <- selectDeclarationMembers limits sources demand
instantiated <- mapInstantiation demand (instantiateTemplateType (preparedBinding demand) selected)
-- The source annotation may retain a namespace-relative spelling.
-- The planner owns the canonical concrete application, so the
-- cloned declaration crosses into Core with that exact type.
let canonicalDeclaration = instantiated {declarationAnnotation = preparedType demand}
freshened = freshenDeclaration next canonicalDeclaration
mangledType <- mapMangle demand (singleMangle (mangleTemplateType defaultTemplateMangleLimits (preparedType demand)))
mangledMembers <-
mapMangle
demand
(mangleTemplateMembers defaultTemplateMangleLimits (preparedType demand) (freshenedDeclaration freshened))
let specialization =
TemplateSpecialization
{ templateSpecializationId = TemplateSpecializationId identifier
, templateSpecializationIdentity = preparedIdentity demand
, templateSpecializationType = preparedType demand
, templateSpecializationScope = selectedScope
, templateSpecializationOrigins = preparedOrigins demand
, templateSpecializationDependencies = []
, templateSpecializationDeclaration = freshenedDeclaration freshened
, templateSpecializationSymbolMap = freshenedSymbols freshened
, templateSpecializationMangledType = mangledType
, templateSpecializationMangledMembers = mangledMembers
}
if memberTotal > maximumMembersPerSpecialization limits
then
Left
[ TemplateMemberLimitExceeded
(templateDeclarationName (templateBindingDeclaration (preparedBinding demand)))
(maximumMembersPerSpecialization limits)
memberTotal
]
else go (nextFreshSymbol freshened) (identifier + 1) (specialization : output) remaining
selectDeclarationMembers ::
TemplateSpecializationLimits ->
Map SymbolId (Declaration ResolvedName Type) ->
PreparedDemand ->
Either [TemplateSpecializationError] (Declaration ResolvedName Type, TemplateDemandScope, Int)
selectDeclarationMembers _ sources demand = do
source <- case Map.lookup symbol sources of
Just declaration -> Right declaration
Nothing -> Left [TemplateDeclarationSourceMissing name symbol]
case source of
declaration@TemplateTypeDeclaration {typeMembers = members} -> do
(selected, selectedScope) <- selectMembers name (preparedScope demand) members
pure (declaration {typeMembers = selected}, selectedScope, length selected)
_ -> Left [TemplateDeclarationSourceMissing name symbol]
where
descriptor = templateBindingDeclaration (preparedBinding demand)
name = templateDeclarationName descriptor
symbol = templateDeclarationSymbol descriptor
selectMembers ::
QualifiedName ->
TemplateDemandScope ->
[Declaration ResolvedName Type] ->
Either [TemplateSpecializationError] ([Declaration ResolvedName Type], TemplateDemandScope)
selectMembers _ TemplateLayoutDemand _ = Right ([], TemplateLayoutDemand)
selectMembers _ TemplateCompleteDemand members = Right (members, TemplateCompleteDemand)
selectMembers owner (TemplateMemberDemand requested) members =
case selectReachableMembersByName requested members of
Left failures -> Left (mapReachabilityFailures owner failures)
Right reachability ->
let selected = memberReachabilityMembers reachability
selectedNames = unique (map memberSpelling selected)
in Right (selected, TemplateMemberDemand selectedNames)
mapReachabilityFailures ::
QualifiedName ->
[TemplateMemberReachabilityError] ->
[TemplateSpecializationError]
mapReachabilityFailures owner failures =
case [name | MissingTemplateMemberName name <- failures] of
[] -> [TemplateMemberReachabilityFailed owner failures]
names -> map (TemplateMemberNotFound owner) names
memberSpelling :: Declaration ResolvedName Type -> Identifier
memberSpelling = resolvedSpelling . declarationName
mapInstantiation ::
PreparedDemand ->
Either TemplateInstantiationError value ->
Either [TemplateSpecializationError] value
mapInstantiation demand result = case result of
Left failure -> Left [TemplateInstantiationFailed (preparedIdentity demand) failure]
Right value -> Right value
singleMangle :: Either TemplateMangleError value -> Either [TemplateMangleError] value
singleMangle result = case result of
Left failure -> Left [failure]
Right value -> Right value
mapMangle ::
PreparedDemand ->
Either [TemplateMangleError] value ->
Either [TemplateSpecializationError] value
mapMangle demand result = case result of
Left failures -> Left [TemplateMangleFailed (preparedIdentity demand) failures]
Right value -> Right value
declarationSources ::
[Declaration ResolvedName Type] ->
Map SymbolId (Declaration ResolvedName Type)
declarationSources = Map.fromList . concatMap collect
where
collect declaration@TemplateTypeDeclaration {} =
(resolvedSymbol (declarationName declaration), declaration) : concatMap collect (typeMembers declaration)
collect TypeDeclaration {typeMembers = members} = concatMap collect members
collect FunctionDeclaration {} = []
collect EnumDeclaration {} = []
attachDependencies :: [TemplateSpecialization] -> [TemplateSpecialization]
attachDependencies specializations = map attach specializations
where
identityIds =
Map.fromList
[ (templateSpecializationIdentity specialization, templateSpecializationId specialization)
| specialization <- specializations
]
attach specialization =
specialization
{ templateSpecializationDependencies =
unique
[ dependency
| valueType <- declarationTypes (templateSpecializationDeclaration specialization)
, let identity = renderSpecializationIdentity valueType
, identity /= templateSpecializationIdentity specialization
, Just dependency <- [Map.lookup identity identityIds]
]
}
-- | Find a plan entry by its plan-local identity.
findTemplateSpecialization ::
TemplateSpecializationId ->
TemplateSpecializationPlan ->
Maybe TemplateSpecialization
findTemplateSpecialization identifier =
first ((== identifier) . templateSpecializationId) . plannedTemplateSpecializations
-- | Find a plan entry by its canonical concrete-type identity string.
findTemplateSpecializationByIdentity ::
String ->
TemplateSpecializationPlan ->
Maybe TemplateSpecialization
findTemplateSpecializationByIdentity identity =
first ((== identity) . templateSpecializationIdentity) . plannedTemplateSpecializations
{- | Produce a stable dependency-first order. Reference-recursive cycles are
legal, so a grey node closes the current DFS edge instead of becoming an
error. Every specialization still appears exactly once.
-}
-- | Return stable dependency-first IDs for specialization emission.
specializationEmissionOrder :: TemplateSpecializationPlan -> [TemplateSpecializationId]
specializationEmissionOrder plan = reverse completed
where
table = Map.fromList [(templateSpecializationId value, value) | value <- plannedTemplateSpecializations plan]
(_, completed) = foldl' visitRoot ([], []) (Map.keys table)
visitRoot state identifier = visit table state identifier
visit ::
Map TemplateSpecializationId TemplateSpecialization ->
([TemplateSpecializationId], [TemplateSpecializationId]) ->
TemplateSpecializationId ->
([TemplateSpecializationId], [TemplateSpecializationId])
visit table state@(active, completed) identifier
| identifier `elem` completed = state
| identifier `elem` active = state
| otherwise = case Map.lookup identifier table of
Nothing -> state
Just specialization ->
let entered = (identifier : active, completed)
(afterActive, afterDependencies) =
foldl' (visit table) entered (templateSpecializationDependencies specialization)
in (filter (/= identifier) afterActive, identifier : afterDependencies)
{- | Build the exact closed TypedAST view consumed by declaration lowering.
Open templates remain in the semantic artifacts but are not copied here.
-}
-- | Assemble the exact closed typed AST consumed by declaration lowering.
specializationTypedAST :: TemplateSpecializationPlan -> TypedAST
specializationTypedAST plan =
TypedAST
( SyntaxTree
(plannedTemplateNamespace plan)
[ templateSpecializationDeclaration specialization
| identifier <- specializationEmissionOrder plan
, Just specialization <- [findTemplateSpecialization identifier plan]
]
)
memberCount :: TemplateSpecialization -> Int
memberCount specialization = case templateSpecializationDeclaration specialization of
TypeDeclaration {typeMembers = members} -> length members
_ -> 0
declarationTypes :: Declaration ResolvedName Type -> [Type]
declarationTypes declaration = case declaration of
TypeDeclaration _ _ annotation members -> annotation : concatMap declarationTypes members
FunctionDeclaration _ _ annotation _ parameters body _ _ ->
annotation : concatMap parameterTypes parameters ++ blockTypes body
TemplateTypeDeclaration {} -> []
EnumDeclaration {} -> []
parameterTypes :: Parameter ResolvedName Type -> [Type]
parameterTypes parameter = [parameterAnnotation parameter]
blockTypes :: Block ResolvedName Type -> [Type]
blockTypes (Block statements) = concatMap statementTypes statements
statementTypes :: Statement ResolvedName Type -> [Type]
statementTypes statement = case statement of
BindingStatement _ _ _ _ annotation value -> annotation : expressionTypes value
AssignmentStatement _ _ annotation value -> annotation : expressionTypes value
ReturnStatement _ value -> maybe [] expressionTypes value
IfStatement _ condition trueBlock falseBlock ->
expressionTypes condition ++ blockTypes trueBlock ++ maybe [] blockTypes falseBlock
WhileStatement _ condition body -> expressionTypes condition ++ blockTypes body
DoWhileStatement _ body condition -> blockTypes body ++ expressionTypes condition
ForStatement _ initializer condition updates body ->
maybe [] statementTypes initializer
++ maybe [] expressionTypes condition
++ concatMap statementTypes updates
++ blockTypes body
ForEachStatement _ _ _ _ annotation source body -> annotation : expressionTypes source ++ blockTypes body
IncrementStatement _ _ annotation -> [annotation]
CompoundAssignmentStatement _ _ _ annotation value -> annotation : expressionTypes value
DiscardStatement _ value -> expressionTypes value
BreakStatement _ value -> maybe [] expressionTypes value
ContinueStatement {} -> []
GuardStatement _ condition block -> expressionTypes condition ++ blockTypes block
BlockStatement _ block -> blockTypes block
ExpressionStatement _ value _ -> expressionTypes value
expressionTypes :: Expression ResolvedName Type -> [Type]
expressionTypes expression = case expression of
NameExpression _ _ annotation -> [annotation]
LiteralExpression _ _ annotation -> [annotation]
MemberAccessExpression _ receiver _ annotation -> annotation : expressionTypes receiver
MethodReferenceExpression _ receiver _ annotation -> annotation : expressionTypes receiver
CallExpression _ callee arguments annotation ->
annotation : expressionTypes callee ++ concatMap expressionTypes arguments
UnaryExpression _ _ value annotation -> annotation : expressionTypes value
BinaryExpression _ _ left right annotation -> annotation : expressionTypes left ++ expressionTypes right
IsPatternExpression _ subject patternValue annotation ->
annotation : expressionTypes subject ++ patternTypes patternValue
ConditionalExpression _ condition whenTrue whenFalse annotation ->
annotation : concatMap expressionTypes [condition, whenTrue, whenFalse]
CoalesceExpression _ left fallback annotation ->
annotation : expressionTypes left ++ expressionTypes fallback
AssignmentExpression _ _ _ value annotation -> annotation : expressionTypes value
IncrementExpression _ _ _ annotation -> [annotation]
LoopExpression _ loop annotation -> annotation : statementTypes loop
BlockExpression _ block annotation -> annotation : blockTypes block
MatchExpression _ subjects arms annotation ->
annotation
: map matchPatternAnnotation (concatMap matchArmPatterns arms)
++ concatMap expressionTypes (subjects ++ concatMap matchArmExpressions arms)
CallableExpression _ _ captures parameters body annotation ->
annotation
: concatMap captureTypes captures
++ concatMap parameterTypes parameters
++ callableBodyTypes body
patternTypes :: Pattern ResolvedName Type -> [Type]
patternTypes patternValue = case patternValue of
WildcardPattern _ annotation -> [annotation]
NullPattern _ annotation -> [annotation]
LiteralPattern _ _ annotation -> [annotation]
TypePattern _ _ annotation -> [annotation]
RelationalPattern _ _ _ annotation -> [annotation]
NotPattern _ nested annotation -> annotation : patternTypes nested
AndPattern _ left right annotation -> annotation : patternTypes left ++ patternTypes right
OrPattern _ left right annotation -> annotation : patternTypes left ++ patternTypes right
captureTypes :: Capture ResolvedName Type -> [Type]
captureTypes capture = captureAnnotation capture : maybe [] expressionTypes (captureInitializer capture)
callableBodyTypes :: CallableBody ResolvedName Type -> [Type]
callableBodyTypes body = case body of
CallableExpressionBody expression -> expressionTypes expression
CallableBlockBody block -> blockTypes block
collectOpenSymbols :: Type -> [SymbolId]
collectOpenSymbols valueType = unique (collectType valueType)
where
collectType current = case current of
NamedType _ arguments -> concatMap collectArgument arguments
FunctionType parameters result -> concatMap collectType (parameters ++ [result])
TypeVariable name -> [resolvedSymbol name]
ErrorType -> []
collectArgument argument = case argument of
TypeTemplateArgument nested -> collectType nested
ValueTemplateArgument (TemplateValueParameter name) -> [resolvedSymbol name]
ValueTemplateArgument _ -> []
renderSpecializationIdentity :: Type -> String
renderSpecializationIdentity valueType = case valueType of
NamedType name arguments -> renderName name ++ renderArguments arguments
FunctionType parameters result ->
"fn(" ++ intercalate "," (map renderSpecializationIdentity parameters) ++ ")->" ++ renderSpecializationIdentity result
TypeVariable name -> "open$" ++ show (symbolIdValue (resolvedSymbol name))
ErrorType -> "<error>"
where
renderArguments [] = ""
renderArguments arguments = "<" ++ intercalate "," (map renderArgument arguments) ++ ">"
renderArgument (TypeTemplateArgument nested) = "type:" ++ renderSpecializationIdentity nested
renderArgument (ValueTemplateArgument value) = "value:" ++ renderValue value
renderValue (IntegerTemplateValue value) = "i:" ++ show value
renderValue (BooleanTemplateValue value) = "b:" ++ if value then "true" else "false"
renderValue (CharacterTemplateValue value) = "c:" ++ show value
renderValue (TemplateValueParameter name) = "open$" ++ show (symbolIdValue (resolvedSymbol name))
renderName :: QualifiedName -> String
renderName (QualifiedName parts) = intercalate "." (map renderPart parts)
where
renderPart (Identifier value) = show (length value) ++ ":" ++ value
-- | Render a demand, resource, reachability, or mangling failure.
renderTemplateSpecializationError :: TemplateSpecializationError -> String
renderTemplateSpecializationError issue = case issue of
InvalidTemplateSpecializationLimits message -> "invalid template specialization limits: " ++ message
TemplateApplicationFailed origin failures ->
"template demand from " ++ origin ++ " failed: " ++ intercalate "; " (map renderTemplateApplicationError failures)
TemplateInstantiationFailed identity failure ->
"template specialization " ++ identity ++ " failed: " ++ renderTemplateInstantiationError failure
TemplateDeclarationSourceMissing name symbol ->
"template declaration " ++ renderPlainName name ++ " (symbol " ++ show (symbolIdValue symbol) ++ ") has no typed source"
TemplateMemberNotFound name member ->
"template declaration " ++ renderPlainName name ++ " has no member named " ++ identifierText member
TemplateSpecializationRemainsOpen identity symbols ->
"template specialization " ++ identity ++ " remains open over symbols " ++ show (map symbolIdValue symbols)
TemplateSpecializationLimitExceeded limit identity ->
"template specialization limit " ++ show limit ++ " was exceeded by " ++ identity
TemplateOriginLimitExceeded limit origin ->
"template origin limit " ++ show limit ++ " was exceeded by " ++ origin
TemplateMemberLimitExceeded name limit actual ->
"template declaration "
++ renderPlainName name
++ " selected "
++ show actual
++ " members, exceeding limit "
++ show limit
TemplateMemberReachabilityFailed name failures ->
"template declaration "
++ renderPlainName name
++ " has an invalid member call graph: "
++ intercalate "; " (map renderTemplateMemberReachabilityError failures)
TemplateMangleFailed identity failures ->
"template specialization "
++ identity
++ " cannot be mangled: "
++ intercalate "; " (map renderTemplateMangleError failures)
renderPlainName :: QualifiedName -> String
renderPlainName (QualifiedName parts) = intercalate "." (map identifierText parts)
first :: (value -> Bool) -> [value] -> Maybe value
first _ [] = Nothing
first predicate (value : remaining)
| predicate value = Just value
| otherwise = first predicate remaining
unique :: (Eq value) => [value] -> [value]
unique = foldl' append []
where
append values value
| value `elem` values = values
| otherwise = values ++ [value]
collectResults :: [Either [problem] value] -> Either [problem] [value]
collectResults results = case concat [problems | Left problems <- results] of
[] -> Right [value | Right value <- results]
problems -> Left problems