Changes in / [fc19129:36e05a2]


Ignore:
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • doc/generic_types/generic_types.tex

    rfc19129 r36e05a2  
    123123\maketitle
    124124
     125
    125126\section{Introduction \& Background}
    126127
     
    145146int forty_two = identity( 42 );                         $\C{// T is bound to int, forty\_two == 42}$
    146147\end{lstlisting}
    147 The @identity@ function above can be applied to any complete object-type (or ``@otype@''). The type variable @T@ is transformed into a set of additional implicit parameters to @identity@ that encode sufficient information about @T@ to create and return a variable of that type. The \CFA implementation passes the size and alignment of the type represented by an @otype@ parameter, as well as an assignment operator, constructor, copy constructor and destructor. If this extra information is not needed, \eg for a pointer, the type parameter can be declared as @dtype T@, where @dtype@ is short for ``data type''.
     148The @identity@ function above can be applied to any complete object-type (or ``@otype@''). The type variable @T@ is transformed into a set of additional implicit parameters to @identity@ that encode sufficient information about @T@ to create and return a variable of that type. The \CFA implementation passes the size and alignment of the type represented by an @otype@ parameter, as well as an assignment operator, constructor, copy constructor and destructor. If this extra information is not needed, e.g., for a pointer, the type parameter can be declared as @dtype T@, where @dtype@ is short for ``data type''.
    148149
    149150Here, the runtime cost of polymorphism is spread over each polymorphic call, due to passing more arguments to polymorphic functions; preliminary experiments have shown this overhead to be similar to \CC virtual function calls. An advantage of this design is that, unlike \CC template functions, \CFA @forall@ functions are compatible with C separate compilation.
     
    386387\subsection{Dynamic Generic Types}
    387388
    388 Though \CFA implements concrete generic types efficiently, it also has a fully general system for computing with dynamic generic types. As mentioned in Section~\ref{sec:poly-fns}, @otype@ function parameters (in fact all @sized@ polymorphic parameters) come with implicit size and alignment parameters provided by the caller. Dynamic generic structs also have implicit size and alignment parameters, and also an \emph{offset array} which contains the offsets of each member of the struct\footnote{Dynamic generic unions need no such offset array, as all members are at offset 0; the size and alignment parameters are still provided for dynamic unions, however.}. Access to members\footnote{The \lstinline@offsetof@ macro is implemented similarly.} of a dynamic generic struct is provided by adding the corresponding member of the offset array to the struct pointer at runtime, essentially moving a compile-time offset calculation to runtime where necessary.
     389Though \CFA implements concrete generic types efficiently, it also has a fully general system for computing with dynamic generic types. As mentioned in Section~\ref{sec:poly-fns}, @otype@ function parameters (in fact all @sized@ polymorphic parameters) come with implicit size and alignment parameters provided by the caller. Dynamic generic structs have the same size and alignment parameter, and also an \emph{offset array} which contains the offsets of each member of the struct\footnote{Dynamic generic unions need no such offset array, as all members are at offset 0; the size and alignment parameters are still provided for dynamic unions, however.}. Access to members\footnote{The \lstinline@offsetof@ macro is implemented similarly.} of a dynamic generic struct is provided by adding the corresponding member of the offset array to the struct pointer at runtime, essentially moving a compile-time offset calculation to runtime where necessary.
    389390
    390391These offset arrays are statically generated where possible. If a dynamic generic type is declared to be passed or returned by value from a polymorphic function, the translator can safely assume that the generic type is complete (that is, has a known layout) at any call-site, and the offset array is passed from the caller; if the generic type is concrete at the call site the elements of this offset array can even be statically generated using the C @offsetof@ macro. As an example, @p.second@ in the @value@ function above is implemented as @*(p + _offsetof_pair[1])@, where @p@ is a @void*@, and @_offsetof_pair@ is the offset array passed in to @value@ for @pair(const char*, T)@. The offset array @_offsetof_pair@ is generated at the call site as @size_t _offsetof_pair[] = { offsetof(_pair_conc1, first), offsetof(_pair_conc1, second) };@.
     
    520521In \CFA, each of these calls is valid. In the call to @f@, @x@ is implicitly flattened so that the components of @x@ are passed as the two arguments to @f@. For the call to @g@, the values @y@ and @10@ are structured into a single argument of type @[int, int]@ to match the type of the parameter of @g@. Finally, in the call to @h@, @y@ is flattened to yield an argument list of length 3, of which the first component of @x@ is passed as the first parameter of @h@, and the second component of @x@ and @y@ are structured into the second argument of type @[int, int]@. The flexible structure of tuples permits a simple and expressive function call syntax to work seamlessly with both single- and multiple-return-value functions, and with any number of arguments of arbitrarily complex structure.
    521522
    522 % In {K-W C} \citep{Buhr94a,Till89}, a precursor to \CFA, there were 4 tuple coercions: opening, closing, flattening, and structuring. Opening coerces a tuple value into a tuple of values, while closing converts a tuple of values into a single tuple value. Flattening coerces a nested tuple into a flat tuple, \ie it takes a tuple with tuple components and expands it into a tuple with only non-tuple components. Structuring moves in the opposite direction, \ie it takes a flat tuple value and provides structure by introducing nested tuple components.
     523In {K-W C}~\citep{Buhr94a,Till89}, a precursor to \CFA, there were 4 tuple coercions: opening, closing, flattening, and structuring. Opening coerces a tuple value into a tuple of values, while closing converts a tuple of values into a single tuple value. Flattening coerces a nested tuple into a flat tuple, \ie it takes a tuple with tuple components and expands it into a tuple with only non-tuple components. Structuring moves in the opposite direction, \ie it takes a flat tuple value and provides structure by introducing nested tuple components.
    523524
    524525In \CFA, the design has been simplified to require only the two conversions previously described, which trigger only in function call and return situations. Specifically, the expression resolution algorithm examines all of the possible alternatives for an expression to determine the best match. In resolving a function call expression, each combination of function value and list of argument alternatives is examined. Given a particular argument list and function value, the list of argument alternatives is flattened to produce a list of non-tuple valued expressions. Then the flattened list of expressions is compared with each value in the function's parameter list. If the parameter's type is not a tuple type, then the current argument value is unified with the parameter type, and on success the next argument and parameter are examined. If the parameter's type is a tuple type, then the structuring conversion takes effect, recursively applying the parameter matching algorithm using the tuple's component types as the parameter list types. Assuming a successful unification, eventually the algorithm gets to the end of the tuple type, which causes all of the matching expressions to be consumed and structured into a tuple expression. For example, in
  • src/GenPoly/InstantiateGeneric.cc

    rfc19129 r36e05a2  
    255255                }
    256256
    257                 assertf( baseParam == baseParams.end() && param == params.end(), "Type parameters should match type variables" );
     257                assert( baseParam == baseParams.end() && param == params.end() && "Type parameters should match type variables" );
    258258                return gt;
    259259        }
  • src/ResolvExpr/Unify.cc

    rfc19129 r36e05a2  
    134134                  case TypeDecl::Ftype:
    135135                        return isFtype( type, indexer );
    136                   case TypeDecl::Ttype:
     136                        case TypeDecl::Ttype:
    137137                        // ttype unifies with any tuple type
    138138                        return dynamic_cast< TupleType * >( type ) || Tuples::isTtype( type );
     
    592592                for ( ; it != params.end() && jt != otherParams.end(); ++it, ++jt ) {
    593593                        TypeExpr *param = dynamic_cast< TypeExpr* >(*it);
    594                         assertf(param, "Aggregate parameters should be type expressions");
     594                        assert(param && "Aggregate parameters should be type expressions");
    595595                        TypeExpr *otherParam = dynamic_cast< TypeExpr* >(*jt);
    596                         assertf(otherParam, "Aggregate parameters should be type expressions");
    597                        
    598                         Type* paramTy = param->get_type();
    599                         Type* otherParamTy = otherParam->get_type();
    600 
    601                         bool tupleParam = Tuples::isTtype( paramTy );
    602                         bool otherTupleParam = Tuples::isTtype( otherParamTy );
    603 
    604                         if ( tupleParam && otherTupleParam ) {
    605                                 ++it; ++jt;  // skip ttype parameters for break
    606                         } else if ( tupleParam ) {
    607                                 // bundle other parameters into tuple to match
    608                                 TupleType* binder = new TupleType{ paramTy->get_qualifiers() };
    609 
    610                                 do {
    611                                         binder->get_types().push_back( otherParam->get_type()->clone() );
    612                                         ++jt;
    613 
    614                                         if ( jt == otherParams.end() ) break;
    615 
    616                                         otherParam = dynamic_cast< TypeExpr* >(*jt);
    617                                         assertf(otherParam, "Aggregate parameters should be type expressions");
    618                                 } while (true);
    619 
    620                                 otherParamTy = binder;
    621                                 ++it;  // skip ttype parameter for break
    622                         } else if ( otherTupleParam ) {
    623                                 // bundle parameters into tuple to match other
    624                                 TupleType* binder = new TupleType{ otherParamTy->get_qualifiers() };
    625 
    626                                 do {
    627                                         binder->get_types().push_back( param->get_type()->clone() );
    628                                         ++it;
    629 
    630                                         if ( it == params.end() ) break;
    631 
    632                                         param = dynamic_cast< TypeExpr* >(*it);
    633                                         assertf(param, "Aggregate parameters should be type expressions");
    634                                 } while (true);
    635 
    636                                 paramTy = binder;
    637                                 ++jt;  // skip ttype parameter for break
    638                         }
    639 
    640                         if ( ! unifyExact( paramTy, otherParamTy, env, needAssertions, haveAssertions, openVars, WidenMode(false, false), indexer ) ) {
     596                        assert(otherParam && "Aggregate parameters should be type expressions");
     597
     598                        if ( ! unifyExact( param->get_type(), otherParam->get_type(), env, needAssertions, haveAssertions, openVars, WidenMode(false, false), indexer ) ) {
    641599                                result = false;
    642600                                return;
    643601                        }
    644 
    645                         // ttype parameter should be last
    646                         if ( tupleParam || otherTupleParam ) break;
    647602                }
    648603                result = ( it == params.end() && jt == otherParams.end() );
Note: See TracChangeset for help on using the changeset viewer.