tala-compiler-0.1.0: test/TypeClassificationTests.hs
-- SPDX-FileCopyrightText: 2026 Progmasoft <support@progmasoft.com>
-- SPDX-License-Identifier: MPL-2.0 WITH AdditionRef-Progmasoft-Exception-1.1
module TypeClassificationTests (typeClassificationTests) where
import Progmasoft.Tala.AST
import Progmasoft.Tala.BuiltinTypes
import Progmasoft.Tala.TypeClassification
typeClassificationTests :: [(String, Bool)]
typeClassificationTests =
[ ("every built-in scalar is a trivial value", all scalarIsTrivial scalarTypes)
, ("void is a trivial no-result marker", classifyType catalog voidType == TrivialValueStorage)
, ("String has reference identity", classifyType catalog stringType == AarcReferenceStorage)
, ("callable values own AARC environments", classifyType catalog callableType == AarcReferenceStorage)
, ("value declaration families use CoW", all nominalIsValue valueNominals)
, ("reference declaration families use AARC", all nominalIsReference referenceNominals)
, ("an all-value construction remains a value", classifyType catalog nestedValue == CopyOnWriteValueStorage)
, ("a direct reference argument makes a value construction reference", usesAarc catalog directReference)
, ("reference classification propagates through arbitrary nesting", usesAarc catalog deepReference)
, ("a nominal reference propagates through a value construction", usesAarc catalog nominalReference)
, ("a reference outer type ignores unresolved arguments", usesAarc catalog referenceWithOpenArgument)
, ("an open all-value construction remains unresolved", classifyType catalog openValue == UnresolvedStorage)
, ("reference evidence dominates an earlier unresolved argument", usesAarc catalog unresolvedThenReference)
, ("reference evidence dominates a later unresolved argument", usesAarc catalog referenceThenUnresolved)
, ("compile-time value arguments do not affect storage", usesCopyOnWrite catalog fixedBuffer)
, ("unknown nominal declarations remain unresolved", classifyType catalog missingType == UnresolvedStorage)
, ("catalog registration rejects empty qualified names", rejectsEmptyName)
, ("catalog registration rejects empty name components", rejectsEmptyComponent)
, ("catalog registration rejects exact duplicates", rejectsDuplicate)
, ("catalog lookup is case-sensitive", caseSensitiveCatalog)
]
where
scalarIsTrivial scalar = classifyType catalog (scalarTypeToType scalar) == TrivialValueStorage
nominalIsValue kind = classifyNominal kind == CopyOnWriteValueStorage
nominalIsReference kind = classifyNominal kind == AarcReferenceStorage
name :: String -> QualifiedName
name spelling = QualifiedName [Identifier spelling]
named :: String -> [Type] -> Type
named spelling arguments = NamedType (name spelling) (map TypeTemplateArgument arguments)
typeVariable :: String -> Int -> Type
typeVariable spelling unique = TypeVariable (ResolvedName (SymbolId unique) (Identifier spelling))
catalog :: NominalCatalog
catalog = case registrations of
Right result -> result
Left problem -> error ("invalid ownership test catalog: " ++ show problem)
where
registrations = do
withValue <- registerNominal (name "ValueCell") DataNominal emptyNominalCatalog
withReference <- registerNominal (name "ReferenceCell") ClassNominal withValue
registerNominal (name "Buffer") LiteralTypeNominal withReference
valueNominals :: [NominalKind]
valueNominals = [DataNominal, LiteralTypeNominal, ClassicEnumNominal]
referenceNominals :: [NominalKind]
referenceNominals = [ClassNominal, DataClassNominal, EnumClassNominal, ObjectNominal, InterfaceNominal]
callableType :: Type
callableType = FunctionType [intType] voidType
nestedValue :: Type
nestedValue = named "ValueCell" [named "ValueCell" [intType]]
directReference :: Type
directReference = named "ValueCell" [stringType]
deepReference :: Type
deepReference = named "ValueCell" [named "ValueCell" [named "ValueCell" [stringType]]]
nominalReference :: Type
nominalReference = named "ValueCell" [named "ReferenceCell" [intType]]
referenceWithOpenArgument :: Type
referenceWithOpenArgument = named "ReferenceCell" [typeVariable "T" 1]
openValue :: Type
openValue = named "ValueCell" [typeVariable "T" 2]
unresolvedThenReference :: Type
unresolvedThenReference = named "ValueCell" [typeVariable "U" 3, stringType]
referenceThenUnresolved :: Type
referenceThenUnresolved = named "ValueCell" [stringType, typeVariable "V" 4]
fixedBuffer :: Type
fixedBuffer =
NamedType
(name "Buffer")
[TypeTemplateArgument intType, ValueTemplateArgument (IntegerTemplateValue 16)]
missingType :: Type
missingType = named "Missing" [intType]
rejectsEmptyName :: Bool
rejectsEmptyName = registerNominal (QualifiedName []) DataNominal emptyNominalCatalog == Left EmptyNominalName
rejectsEmptyComponent :: Bool
rejectsEmptyComponent =
registerNominal malformed DataNominal emptyNominalCatalog == Left (EmptyNominalNameComponent malformed)
where
malformed = QualifiedName [Identifier "Example", Identifier ""]
rejectsDuplicate :: Bool
rejectsDuplicate = case registerNominal (name "Example") DataNominal emptyNominalCatalog of
Left _ -> False
Right once -> registerNominal (name "Example") ClassNominal once == Left (DuplicateNominalName (name "Example"))
caseSensitiveCatalog :: Bool
caseSensitiveCatalog = case registerNominal upper DataNominal emptyNominalCatalog of
Left _ -> False
Right result -> lookupNominal upper result == Just DataNominal && lookupNominal lower result == Nothing
where
upper = QualifiedName [Identifier "Example", Identifier "Value"]
lower = QualifiedName [Identifier "Example", Identifier "value"]