Changes in / [36e05a2:fc19129]
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
doc/generic_types/generic_types.tex
r36e05a2 rfc19129 123 123 \maketitle 124 124 125 126 125 \section{Introduction \& Background} 127 126 … … 146 145 int forty_two = identity( 42 ); $\C{// T is bound to int, forty\_two == 42}$ 147 146 \end{lstlisting} 148 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, e.g.,for a pointer, the type parameter can be declared as @dtype T@, where @dtype@ is short for ``data type''.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''. 149 148 150 149 Here, 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. … … 387 386 \subsection{Dynamic Generic Types} 388 387 389 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 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.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. 390 389 391 390 These 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) };@. … … 521 520 In \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. 522 521 523 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.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. 524 523 525 524 In \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
r36e05a2 rfc19129 255 255 } 256 256 257 assert ( baseParam == baseParams.end() && param == params.end() &&"Type parameters should match type variables" );257 assertf( baseParam == baseParams.end() && param == params.end(), "Type parameters should match type variables" ); 258 258 return gt; 259 259 } -
src/ResolvExpr/Unify.cc
r36e05a2 rfc19129 134 134 case TypeDecl::Ftype: 135 135 return isFtype( type, indexer ); 136 136 case TypeDecl::Ttype: 137 137 // ttype unifies with any tuple type 138 138 return dynamic_cast< TupleType * >( type ) || Tuples::isTtype( type ); … … 592 592 for ( ; it != params.end() && jt != otherParams.end(); ++it, ++jt ) { 593 593 TypeExpr *param = dynamic_cast< TypeExpr* >(*it); 594 assert (param &&"Aggregate parameters should be type expressions");594 assertf(param, "Aggregate parameters should be type expressions"); 595 595 TypeExpr *otherParam = dynamic_cast< TypeExpr* >(*jt); 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 ) ) { 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 ) ) { 599 641 result = false; 600 642 return; 601 643 } 644 645 // ttype parameter should be last 646 if ( tupleParam || otherTupleParam ) break; 602 647 } 603 648 result = ( it == params.end() && jt == otherParams.end() );
Note: See TracChangeset
for help on using the changeset viewer.