//
// Copyright (c) 2006, Brian Frank and Andy Frank
// Licensed under the Academic Free License version 3.0
//
// History:
// 4 Jan 06 Brian Frank Creation
//
**
** Type defines the contract of an Obj by the slots it supports.
** Types model the inheritance relationships and provide a mapping
** for all the slots both inherited and declared.
**
const class Type
{
//////////////////////////////////////////////////////////////////////////
// Constructor
//////////////////////////////////////////////////////////////////////////
**
** Private constructor.
**
private new privateMake()
//////////////////////////////////////////////////////////////////////////
// Management
//////////////////////////////////////////////////////////////////////////
**
** Get the class Type of the given instance. Also
** see `Obj.typeof` which provides the same functionality.
**
static Type of(Obj obj)
**
** Find a Type by its qualified name "pod::Type". If the type
** doesn't exist and checked is false then return null, otherwise
** throw UnknownTypeErr.
**
static Type? find(Str qname, Bool checked := true)
//////////////////////////////////////////////////////////////////////////
// Naming
//////////////////////////////////////////////////////////////////////////
**
** Parent pod which defines this type. For parameterized types derived
** from List, Map, or Func, this method always returns the sys pod.
**
** Examples:
** Str#.pod => sys
** acme::Foo#.pod => acme
** acme::Foo[]#.pod => sys
**
Pod? pod()
**
** Simple name of the type such as "Str". For parameterized types derived
** from List, Map, or Func, this method always returns "List", "Map",
** or "Func" respectively.
**
** Examples:
** Str#.name => "Str"
** acme::Foo#.name => "Foo"
** acme::Foo[]#.name => "List"
**
Str name()
**
** Qualified name formatted as "pod::name". For parameterized
** types derived from List, Map, or Func, this method always returns
** "sys::List", "sys::Map", or "sys::Func" respectively. If this is
** a nullable type, the qname does *not* include the "?".
**
** Examples:
** Str#.qname => "sys::Str"
** Str?#.qname => "sys::Str"
** acme::Foo#.qname => "acme::Foo"
** acme::Foo[]#.qname => "sys::List"
**
Str qname()
**
** Return the formal signature of this type. In the case of
** non-parameterized types the signature is the same as qname.
** For parameterized types derived from List, Map, or Func the
** signature uses the following special syntax:
** List => V[]
** Map => [K:V]
** Func => |A,B...->R|
**
** If this is a nullable type, the signature ends with "?" such
** as "sys::Int?".
**
** Examples:
** Str#.signature => "sys::Str"
** Str?#.signature => "sys::Str?"
** Int[]#.signature => "sys::Int[]"
** Int:Str#.signature => "[sys::Int:sys::Str]"
** Str:Buf[]#.signature => [sys::Str:sys::Buf[]]
** |Float x->Bool|#.signature => "|sys::Float->sys::Bool|"
** |Float x, Int y|#.signature => |sys::Float,sys::Int->sys::Void|
**
Str signature()
//////////////////////////////////////////////////////////////////////////
// Inheritance
//////////////////////////////////////////////////////////////////////////
**
** The direct super class of this type (null for Obj).
** Return sys::Obj for all mixin types.
**
** Examples:
** Obj#.base => null
** Int#.base => sys::Num
** OutStream#.base => sys::Obj
**
Type? base()
**
** Return the mixins directly implemented by this type.
**
** Examples:
** Obj#.mixins => [,]
** Buf#.mixins => [sys::InStream, sys::OutStream]
** OutStream#.mixins => [,]
**
Type[] mixins()
**
** Return a recursive flattened list of all the types this type
** inherits from. The result list always includes this type itself.
** The result of this method represents the complete list of types
** implemented by this type - instances of this type are assignable
** to any type in this list. All types (including mixins) will
** include sys::Obj in this list.
**
** Examples:
** Obj#.inheritance => [sys::Obj]
** Int#.inheritance => [sys::Int, sys::Num, sys::Obj]
**
Type[] inheritance()
**
** Does this type implement the specified type. If true, then
** this type is assignable to the specified type (although the
** converse is not necessarily true). This method provides the
** same semantics as the 'is' operator, but between two types
** rather than an instance and a type. All types (including
** mixin types) fit 'sys::Obj'.
**
** This method implicitly ignores the nullability of both 'this'
** and 't' such that this method is always equivalent to:
** this.toNonNullable.fits(t.toNonNullable)
**
** Example:
** Float#.fits(Float#) => true
** Float#.fits(Num#) => true
** Float#.fits(Obj#) => true
** Float#.fits(Str#) => false
** Obj#.fits(Float#) => false
**
Bool fits(Type t)
//////////////////////////////////////////////////////////////////////////
// Value Types
//////////////////////////////////////////////////////////////////////////
**
** Is this a value type. Fantom supports three implicit value
** types: `Bool`, `Int`, and `Float`.
**
Bool isVal()
//////////////////////////////////////////////////////////////////////////
// Nullable
//////////////////////////////////////////////////////////////////////////
**
** Is this a nullable type. Nullable types can store the 'null'
** value, but non-nullables are never null. Null types are indicated
** with a trailing "?".
**
Bool isNullable()
**
** Return this type as a nullable type. If this type is already
** nullable then return this.
**
Type toNullable()
**
** Return this type as a non-nullable type. If this type is already
** non-nullable then return this.
**
Type toNonNullable()
//////////////////////////////////////////////////////////////////////////
// Generics
//////////////////////////////////////////////////////////////////////////
**
** A generic type contains slot signatures which may be parameterized - for
** example Map's key and value types are generic as K and V. Fantom supports
** three built-in generic types: List, Map, and Func. A parameterized
** type such as Str[] is not a generic type (all of its generic parameters
** have been filled in). User defined generic types are not supported in Fantom.
**
** Examples:
** Str#.isGeneric => false
** List#.isGeneric => true
** Str[]#.isGeneric => false
**
Bool isGeneric()
**
** If this is a parameterized type, then return the map of names to
** types. If this is not a parameterized type return an empty map.
**
** Examples:
** Str#.params => [:]
** Str[]#.params => ["V":Str, "L":Str[]]
** Int:Slot#.params => ["K":Int, "V":Slot, "M":Int:Slot]
** |Int x, Float y->Bool|#.params => ["A":Int, "B":Float, "R":Bool]
**
Str:Type params()
**
** If this is a generic type, then dynamically create a new parameterized
** type with the specified name to type map. If this type is not generic
** then throw UnsupportedErr. Throw ArgErr if params fails to specify
** the required parameters:
** List => V required
** Map => K, V required
** Func => R required, A-H optional
**
** Examples:
** List#.parameterize(["V":Bool#]) => Bool[]
** Map#.parameterize(["K":Str#, "V":Obj#]) => Str:Obj
**
Type parameterize(Str:Type params)
**
** Convenience for 'List#.parameterize(["V":this])'
**
** Examples:
** Int#.toListOf => Int[]
** Str[]#.toListOf => Str[][]
**
Type toListOf()
**
** Return an immutable empty list of this type. Since immutable
** lists can be used safely everywhere, this allows signficant memory
** savings instead of allocating new empty lists.
**
** Examples:
** Str#.emptyList => Str[,]
**
Obj[] emptyList()
//////////////////////////////////////////////////////////////////////////
// Flags
//////////////////////////////////////////////////////////////////////////
**
** Return if this Type is abstract and cannot be instantiated. This
** method will always return true if the type is a mixin.
**
Bool isAbstract()
**
** Return if this Type is a class (as opposed to enum or mixin)
**
Bool isClass()
**
** Return if this is a const class which means instances of this
** class are immutable.
**
Bool isConst()
**
** Return if this Type is an Enum type.
**
Bool isEnum()
**
** Return if this Type is a Facet type.
**
Bool isFacet()
**
** Return if this Type is marked final which means it may not be subclassed.
**
Bool isFinal()
**
** Return if this Type has internal protection scope.
**
Bool isInternal()
**
** Return if this Type is a mixin type and cannot be instantiated.
**
Bool isMixin()
**
** Return if this Type has public protection scope.
**
Bool isPublic()
**
** Return if this Type was generated by the compiler.
**
Bool isSynthetic()
//////////////////////////////////////////////////////////////////////////
// Slots
//////////////////////////////////////////////////////////////////////////
**
** List of all the defined fields (including inherited fields).
**
Field[] fields()
**
** List of all the defined methods (including inherited methods).
**
Method[] methods()
**
** List of all the defined slots, both fields and methods (including
** inherited slots).
**
Slot[] slots()
**
** Convenience for (Field)slot(name, checked)
**
Field? field(Str name, Bool checked := true)
**
** Convenience for (Method)slot(name, checked)
**
Method? method(Str name, Bool checked := true)
**
** Lookup a slot by name. If the slot doesn't exist and checked
** is false then return null, otherwise throw UnknownSlotErr.
** Slots are any field or method in this type's scope including
** those defined directly by this type and those inherited from
** super class or mixins.
**
Slot? slot(Str name, Bool checked := true)
**
** Create a new instance of this Type using the following rules:
** 1. Call public constructor 'make' with specified arguments
** 2. If no public constructor called 'make' or invalid number of
** of required arguments, then return value of 'defVal' slot (must
** be static field or static method with zero params)
** 3. If no public 'defVal' field, then throw Err
**
Obj make(Obj[]? args := null)
//////////////////////////////////////////////////////////////////////////
// Facets
//////////////////////////////////////////////////////////////////////////
**
** Get the list of facets defined on this type or return an empty
** list if no facets are defined. If looking up a facet by type, then
** use the `facet` method which will provide better performance.
** See [Facets Doc]`docLang::Facets` for details.
**
Facet[] facets()
**
** Get a facet by its type. If not found on this type then
** return null or throw UnknownFacetErr based on check flag.
** See [Facets Doc]`docLang::Facets` for details.
**
Facet? facet(Type type, Bool checked := true)
**
** Return if this type has the specified facet defined.
**
Bool hasFacet(Type type)
//////////////////////////////////////////////////////////////////////////
// Documentation
//////////////////////////////////////////////////////////////////////////
**
** Return the raw fandoc for this type or null if not available.
**
Str? doc()
//////////////////////////////////////////////////////////////////////////
// Conversion
//////////////////////////////////////////////////////////////////////////
**
** Always return signature().
**
override Str toStr()
**
** Return `signature`. This method is used to enable 'toLocale' to
** be used with duck typing across most built-in types. Note: we may
** change the specification of this method in the future to allow
** localized type names.
**
Str toLocale()
}