PreviousUpNext

15.3.266  src/lib/compiler/front/typer-stuff/types/types.api

## types.api
## (C) 2001 Lucent Technologies, Bell Labs

# Compiled by:
#     src/lib/compiler/front/typer-stuff/typecheckdata.sublib



# Datastructures describing type declarations.
#
# In particular, the datatype
#
#     Typ
#
# provides the value type bound by the symbol table
# for that namespace -- see OVERVIEW section in
#
#     compiler/typer-stuff/symbolmapstack/symbolmapstack.sml



stipulate
    package ip  =  inverse_path;                        # inverse_path  is from   src/lib/compiler/front/typer-stuff/basics/symbol-path.pkg
    package mp  =  stamppath;                           # stamppath     is from   src/lib/compiler/front/typer-stuff/modules/stamppath.pkg
    package ph  =  picklehash;                          # picklehash    is from   src/lib/compiler/front/basics/map/picklehash.pkg
    package pl  =  property_list;                       # property_list is from   src/lib/src/property-list.pkg
    package sta =  stamp;                               # stamp         is from   src/lib/compiler/front/typer-stuff/basics/stamp.pkg
    package sy  =  symbol;                              # symbol        is from   src/lib/compiler/front/basics/map/symbol.pkg
    package vh  =  varhome;                             # varhome       is from   src/lib/compiler/front/typer-stuff/basics/varhome.pkg
herein

    api Types {
        #
        #

        #  Not quite abstract types... 
        #
        Label;                                  #  = sy::Symbol 
        Type_Scheme_Arg_Eq_Properties;          #  = List( Bool )



        # Mythryl semantics distinguish types whose values
        # may be compared for equality (e.g., integers),
        # which get declared 'eqtype', from those which may not.
        #
        # This distinction dates from the original Definition of
        # Standard ML. The distinction complicates the semantics
        # greatly and is nowadays regarded as a design flaw.
        #
        # The latest type-theoretical treatments of ML semantics
        # infer equality test support for a type silently without
        # explicit user declarations, but for the moment at least
        # the Mythryl compiler still follows the old semantics.
        # 
        # The following type lets us record what we know about the
        # equality properties of a type during the type inference
        # process.  YES and NO represent definite knowledge and
        # INDETERMINATE means we haven't yet learned anything
        # one way or the other.  The remainder cover various
        # special cases.
        # 
        package eq_type: api {                                  # Give YES/NO/... their own little namespace.
            #
            Data
              = YES
              | NO
              | INDETERMINATE                                   # This was "IND", which I'm guessing is a cryponym for "INDETERMINATE" -- 2009-03-21 CrT
              | CHUNK
              | DATA
              | EQ_ABSTRACT                                     # Used to implement "abstype" declarations.
              | UNDEF
              ;
        };

        Literal_Kind
            =
            INT | UNT | FLOAT | CHAR | STRING;


        # The following variable types are core to the
        # Mythryl Hindley-Milner type deduction logic
        # implemented by code centered in the vicinity of
        # 
        #     src/lib/compiler/front/typer/main/type-package-language-g.pkg
        #     src/lib/compiler/front/typer/types/unify-and-generalize-types-g.pkg
        #     src/lib/compiler/front/typer/types/unify-types.pkg
        #     src/lib/compiler/front/typer-stuff/types/type-junk.pkg
        # 
        # The canonical type inference progression is
        #     USER_TYPE_VARIABLE -> META_TYPE_VARIABLE -> RESOLVED_TYPE_VARIABLE.
        # 
        # Type variables supplied by the user like the X in
        #     my (foo: X) = ... ;
        # start out represented as USER_TYPE_VARIABLE records.
        #
        # When permitted by the "value restriction" (see is_value in type-junk.pkg),
        # they get generalized to typeagnostic ("polymorphic") META_TYPE_VARIABLE records.
        #
        # INCOMPLETE_RECORD_TYPE_VARIABLE records are used to track incompletely specified
        # records, canonically those declared using "..." ellipses.
        #
        # When we infer a type for a META_TYPE_VARIABLE record we replace it by a RESOLVED_TYPE_VARIABLE record.
        #
        # LITERAL_TYPE_VARIABLE records are used in inferring the types of literals like '0',
        # which may resolve to any one of several different arithmetic types.
        #
        # OVERLOADED_TYPE_VARIABLE is used in resolving the types of + and other overloaded operators.
        # The Bool value is TRUE iff it must resolve to an equality type.
        #


                                                                            # symbol    is from   src/lib/compiler/front/basics/map/symbol.pkg
        Type_Variable
            #
            #
            = USER_TYPE_VARIABLE {
                name:        sy::Symbol,                                        # X or such.  Construct via  sy::make_type_variable_symbol.
                eq:          Bool,                                              # Must it resolve to an 'equality type'?
                fn_nesting:  Int                                                # Outermost fun/fn lexical context mentioning/using us.
              }                                                                 #   fn_nesting = infinity for type variables like X.
              #                                                                 #   fn_nesting < infinity for fun/fn arguments.
              # A user type variable like 'X' which
              # has not been generalized into a
              # META_TYPE_VARIABLE
              # variable, either because generalization
              # has not yet been done or because the
              # type_junk::is_value() "value restruction"
              # forbade doing so:

            
            | META_TYPE_VARIABLE {                                              # A typeagnostic ("polymorphic") type variable.
                eq:          Bool,                                              # Must it resolve to an 'equality type'?
                fn_nesting:  Int                                                # Outermost fun/fn lexical context mentioning/using us.
              }

            | INCOMPLETE_RECORD_TYPE_VARIABLE {                                 # An incompletely specified record type -- one specified using "..." 
                known_fields: List( (Label, Type) ),
                eq:           Bool,                                             # Must it resolve to an 'equality type'?
                fn_nesting:   Int                                               # Outermost fun/fn lexical context mentioning/using us.
              }

            | RESOLVED_TYPE_VARIABLE  Type                                      # When we resolve a META_TYPE_VARIABLE to a concrete type, we replace it by this.

            | LITERAL_TYPE_VARIABLE {                                           # Literals like '0' may be any of (Int, Unt, Integer, ...). We use this until the type resolves.
                kind:               Literal_Kind,
                source_code_region: line_number_db::Source_Code_Region          # line_number_db        is from   src/lib/compiler/front/basics/source/line-number-db.pkg
              }

            | OVERLOADED_TYPE_VARIABLE  Bool
                #
                # Deducing the type of overloaded operators
                # like '+' is a separate kludge from regular
                # Hindley-Milner type inference.  This represents
                # an overloaded operator not yet resolved to a
                # specific type.  The Boolean argument records
                # whether it must resolve to an equality type:

            | TYPE_VARIABLE_MARK  Int
                #
                # For marking a type variable so that it can be easily identified
                #
                # A type variable's REF cell provides an identity already, but
                # since REF cells are unordered, this is not enough for efficient
                # data package lookups (binary trees...).
                #
                # TYPE_VARIABLE_MARK is really a hack for the benefit of
                # later translation phases, specifically:
                #     src/lib/compiler/back/top/translate/translate-deep-syntax-types-to-lambdacode.pkg
                #     src/lib/compiler/back/top/translate/translate-deep-syntax-to-lambdacode.pkg
                #
                # In any case, we should figure out how to get rid of it altogether. XXX BUGGO FIXME


        also
        Typ_Path
            = TYPPATH_VARIABLE          Exception
            | TYPPATH_TYP  Typ
            | TYPPATH_GENERIC           (List( Typ_Path ), List( Typ_Path ))
            | TYPPATH_APPLY             (Typ_Path, List( Typ_Path ))
            | TYPPATH_SELECT            (Typ_Path, Int)

        also
        Typ_Kind
            = BASE  Int                 # base kinds are abstractly numbered 
            | ABSTRACT  Typ
            | DATATYPE  {
                index:                  Int,
                stamps:                 Vector(  sta::Stamp ),
                root:                   Null_Or( sta::Stamp ),
                free_typs:              List( Typ ),
                family:                 Datatype_Family
              }
            | FLEXIBLE_TYP              Typ_Path                                # "Definition of SML" calls typcons from apis "flexible" an all others "rigid".
            | FORMAL
            | TEMP

        also
        Typ
            = PLAIN_TYP  Plain_Typ_Record                                       # Seems to be mainly (only?) used for prim types like char/string/int/float/...

            | DEFINED_TYP  {
                stamp:          sta::Stamp,                                     # stamp         is from   src/lib/compiler/front/typer-stuff/basics/stamp.pkg
                type_scheme:    Type_Scheme,
                strict:         List( Bool ),
                path:           ip::Inverse_Path                                # inverse_path  is from   src/lib/compiler/front/typer-stuff/basics/symbol-path.pkg
              }

            | TYP_BY_STAMPPATH  {
                arity:          Int,
                stamppath:      mp::Stamppath,                                  # stamppath     is from   src/lib/compiler/front/typer-stuff/modules/stamppath.pkg
                path:           ip::Inverse_Path                                # inverse_path  is from   src/lib/compiler/front/typer-stuff/basics/symbol-path.pkg
              }

            | RECORD_TYP  List( Label )
            | RECURSIVE_TYPE  Int               # Used only in domain type of Constructor_Description 
            | FREE_TYPE       Int               # Used only in domain type of Constructor_Description 
            | ERRONEOUS_TYP


        also
        Type
            = TYPE_VARIABLE_REF  Typevar_Ref
            | WILDCARD_TYPE
            | TYPCON_TYPE  (Typ, List( Type ))
            | TYPE_SCHEME_TYPE  {
                type_scheme:                    Type_Scheme,
                type_scheme_arg_eq_properties:  Type_Scheme_Arg_Eq_Properties   # Records which Type_Scheme args need to resolve to equality types.
              }
            | TYPE_SCHEME_ARG_I       Int                                               # i-th argument to a Type_Scheme (qv)
            | UNDEFINED_TYPE
            #
            #
            # Core types:
            #
            #  o TYPE_VARIABLE_REF
            #    This marks the reference cells which get
            #    updated by the 'unify' operation during
            #    Hindley-Milner type inference.  Once type
            #    inference is complete these are deadwood
            #    and we remove them at the first opportunity.
            #
            #  o WILDCARD_TYPE
            #    This matches anything during type inference.
            #
            #    We use it, for example, for the return type
            #    of 'raise MY_EXCEPTION' statements:  Since
            #    'raise' in fact never returns it is ok to
            #    treat it as though it had whatever type the
            #    local context requires, possibly a different type
            #    each place it appears in the code.
            #
            #    We also use it in error recovery.   When a type
            #    has syntax errors we set it to WILDCARD_TYPE
            #    after issuing diagnostics, so that we can compile
            #    the rest of the file without generating spurious
            #    additional error messages.
            #
            #  o TYPCON_TYPE
            #    This represents a type constructor like List
            #    which takes one or more types as arguments
            #    and returns a new type:  List(Int) and List(Float)
            #    are different types generated this way, for example.
            #
            #  o TYPE_SCHEME_TYPE
            #    See comments below at Type_Scheme.
            #
            #  o TYPE_SCHEME_ARG_I
            #    This represents the i-th type argument to a type scheme.
            #    It will only appear within the body of a type scheme.
            #
            #  o UNDEFINED_TYPE
            #    This represents a type which we need to know but do not
            #    currently know.  It is a compile error if we do not find
            #    a user definition of this type by the end of type inference.


        also
        Type_Scheme
            =
            TYPE_SCHEME  {
              arity:  Int,              # Number of arguments
              body:   Type              # Contains TYPE_SCHEME_ARG_I values marking where fresh META type variables get inserted.
            }
            #
            # Mythryl supports "don't-care" type polymorphism.
            # "Polymorphic" literally means "many-shapes".
            # A type-polymorphic function acts as though it
            # has many types. (I prefer to call them "typeagnostic".)
            #
            # Type-agnosticism is what lets list::length()
            # compute the length of a list of any type of value
            # without triggering complaints from the typechecker.
            # It is also called "parametric polymorphism" and
            # "let-polymorphism".
            #
            # Type schemes implement typeagnostic types.
            # The idea is that instead of assigning a typeagnostic
            # function like list::length() a regular type,
            # we assign it a "type scheme", which is essentially
            # a type macro which we will expand into an actual
            # type at each place in the code where the function
            # is used.  Since we can expand the "type scheme"
            # macro with different type arguments each time,
            # the function can behave as though it had a different
            # type every time it is called.
            # 
            # Our type schemes are essentially templates for producing
            # regular types by plugging fresh META type variables into
            # slots marked by TYPE_SCHEME_ARG_I values, a procedure
            # implemented by
            #
            #     instantiate_if_type_scheme()
            #
            # from
            #
            #     src/lib/compiler/front/typer-stuff/types/type-junk.pkg 
            #
            # For more background see the discussion near the top of
            #
            #     src/lib/compiler/front/typer/types/unify-and-generalize-types-g.pkg


        withtype
        Constructor_Description                                                         # Used in Datatype_Member.
          =
          { name:               sy::Symbol,
            form:                       vh::Valcon_Form,
            domain:             Null_Or( Type )
          }


        also
        Datatype_Member                                                                 # Member of a family of (potentially) mutually recursive datatypes.
          =
          { typ_name:                   sy::Symbol,
            arity:                      Int,
            eqtype_info:                Ref( eq_type::Data ),
            #
            is_lazy:                    Bool,
            constructor_list:           List( Constructor_Description ),
            an_api:                     vh::Valcon_Signature
          }

        also
        Datatype_Family
          =
          { mkey:                       sta::Stamp,
            members:                    Vector( Datatype_Member ),
            property_list:              pl::Property_List
          }


        also
        Stub_Info
          =
          { owner:                      ph::Picklehash,
            is_lib:                     Bool
          }

        also
        Plain_Typ_Record
          =
          { stamp:                      sta::Stamp,
            arity:                      Int,
            eqtype_info:                Ref( eq_type::Data ),
            #   
            kind:                       Typ_Kind,
            path:                       ip::Inverse_Path,                               # inverse_path  is from   src/lib/compiler/front/typer-stuff/basics/symbol-path.pkg
            stub:                       Null_Or( Stub_Info )
          }
          #     
          # The "stub" field will be set for any
          # Plain_Typ that comes 
          # out of the unpickler.
          #
          # The stub owner picklehash is the picklehash
          # of the compilation unit on whose behalf this
          # Plain_Typ was pickled.
          #
          # Normally, this is expected to be the same as
          # the picklehash in the (global) "stamp", but there are
          # odd cases related to recursive types where this
          # assumption breaks.
          # (Is there a way of fixing this? -- David MacQueen.) XXX BUGGO FIXME


        also
        Typevar_Ref
            =
            { ref_typevar:  Ref( Type_Variable ),                               
              id:           Int                                                 # Purely for debuggging printout purposes.
            };
            # 
            # The 'ref_typevar' above is the core hook for doing
            # type inference via unification:  Unification
            # proceeds by re/setting these variables.  The
            # core unification code is in
            # 
            #   src/lib/compiler/front/typer/types/unify-types.pkg


        infinity:                 Int;
        copy_type_variable_ref:   Typevar_Ref            -> Typevar_Ref;
        make_type_variable_ref:   (    Type_Variable , List(String)) -> Typevar_Ref;
        make_type_variable_ref':  (Ref(Type_Variable), List(String)) -> Typevar_Ref;

    #    next_type_variable_id: Void -> Int; 

                            #  Data constructors 

        Valcon                                                                  # Valcon" == "Value Constructor" -- "FOO' in   "Foo = FOO".
            =
            VALCON  {                                                           # The first three fields are the only ones that really matter:
              name:             sy::Symbol,                                     # Name of valcon -- "FOO" value-symbol.
              type:             Type,
              form:             vh::Valcon_Form,                                # Runtime form for constructor -- can be tagged_int or exception or all sorts of other stuff.
              #
              is_constant:      Bool,                                           # TRUE iff constructor takes no arguments -- e.g., TRUE, FALSE, NULL.   (This field is redundant, could be determined from type.) 
              signature:        vh::Valcon_Signature,                           # (Redundant, could be determined from type.) 
              #
              is_lazy:          Bool                                            # Does valcon belong to a lazy datatype? (Nonstandard undocumented extension.)
            };

    };                                                                          # api Types 
end;                                                                            # stipulate


Comments and suggestions to: bugs@mythryl.org

PreviousUpNext