source: src/GenPoly/BoxNew.cpp @ 8c13ca8

Last change on this file since 8c13ca8 was 5e0bba5, checked in by Andrew Beach <ajbeach@…>, 10 months ago

Work on the box pass, fixing up the FunctionDecl? update.

  • Property mode set to 100644
File size: 80.9 KB
Line 
1//
2// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
3//
4// The contents of this file are covered under the licence agreement in the
5// file "LICENCE" distributed with Cforall.
6//
7// BoxNew.cpp -- Implement polymorphic function calls and types.
8//
9// Author           : Andrew Beach
10// Created On       : Thr Oct  6 13:39:00 2022
11// Last Modified By : Andrew Beach
12// Last Modified On : Mon Oct  2 17:00:00 2023
13// Update Count     : 0
14//
15
16#include "Box.h"
17
18#include "AST/Decl.hpp"                // for Decl, FunctionDecl, ...
19#include "AST/Expr.hpp"                // for AlignofExpr, ConstantExpr, ...
20#include "AST/Init.hpp"                // for Init, SingleInit
21#include "AST/Inspect.hpp"             // for getFunctionName
22#include "AST/Pass.hpp"                // for Pass, WithDeclsToAdd, ...
23#include "AST/Stmt.hpp"                // for CompoundStmt, ExprStmt, ...
24#include "AST/Vector.hpp"              // for vector
25#include "AST/GenericSubstitution.hpp" // for genericSubstitution
26#include "CodeGen/OperatorTable.h"     // for isAssignment
27#include "Common/ScopedMap.h"          // for ScopedMap
28#include "Common/UniqueName.h"         // for UniqueName
29#include "Common/utility.h"            // for toCString, group_iterate
30#include "GenPoly/FindFunction.h"      // for findFunction
31#include "GenPoly/GenPoly.h"           // for getFunctionType, ...
32#include "GenPoly/Lvalue.h"            // for generalizedLvalue
33#include "GenPoly/ScopedSet.h"         // for ScopedSet
34#include "GenPoly/ScrubTyVars.h"       // for scrubTypeVars, scrubAllTypeVars
35#include "ResolvExpr/Unify.h"          // for typesCompatible
36#include "SymTab/Mangler.h"            // for mangle, mangleType
37
38namespace GenPoly {
39
40namespace {
41
42// --------------------------------------------------------------------------
43/// Adds layout-generation functions to polymorphic types.
44struct LayoutFunctionBuilder final :
45                public ast::WithDeclsToAdd<>,
46                public ast::WithShortCircuiting,
47                public ast::WithVisitorRef<LayoutFunctionBuilder> {
48        void previsit( ast::StructDecl const * decl );
49        void previsit( ast::UnionDecl const * decl );
50};
51
52/// Get all sized type declarations; those that affect a layout function.
53ast::vector<ast::TypeDecl> takeSizedParams(
54                ast::vector<ast::TypeDecl> const & decls ) {
55        ast::vector<ast::TypeDecl> sizedParams;
56        for ( ast::ptr<ast::TypeDecl> const & decl : decls ) {
57                if ( decl->isComplete() ) {
58                        sizedParams.emplace_back( decl );
59                }
60        }
61        return sizedParams;
62}
63
64ast::BasicType * makeSizeAlignType() {
65        return new ast::BasicType( ast::BasicType::LongUnsignedInt );
66}
67
68/// Adds parameters for otype size and alignment to a function type.
69void addSTypeParams(
70                ast::vector<ast::DeclWithType> & params,
71                ast::vector<ast::TypeDecl> const & sizedParams ) {
72        for ( ast::ptr<ast::TypeDecl> const & sizedParam : sizedParams ) {
73                ast::TypeInstType inst( sizedParam );
74                std::string paramName = Mangle::mangleType( &inst );
75                params.emplace_back( new ast::ObjectDecl(
76                        sizedParam->location,
77                        sizeofName( paramName ),
78                        makeSizeAlignType()
79                ) );
80                params.emplace_back( new ast::ObjectDecl(
81                        sizedParam->location,
82                        alignofName( paramName ),
83                        makeSizeAlignType()
84                ) );
85        }
86}
87
88ast::Type * makeSizeAlignOutType() {
89        return new ast::PointerType( makeSizeAlignType() );
90}
91
92struct LayoutData {
93        ast::FunctionDecl * function;
94        ast::ObjectDecl * sizeofParam;
95        ast::ObjectDecl * alignofParam;
96        ast::ObjectDecl * offsetofParam;
97};
98
99LayoutData buildLayoutFunction(
100                CodeLocation const & location, ast::AggregateDecl const * aggr,
101                ast::vector<ast::TypeDecl> const & sizedParams,
102                bool isInFunction, bool isStruct ) {
103        ast::ObjectDecl * sizeParam = new ast::ObjectDecl(
104                location,
105                sizeofName( aggr->name ),
106                makeSizeAlignOutType()
107        );
108        ast::ObjectDecl * alignParam = new ast::ObjectDecl(
109                location,
110                alignofName( aggr->name ),
111                makeSizeAlignOutType()
112        );
113        ast::ObjectDecl * offsetParam = nullptr;
114        ast::vector<ast::DeclWithType> params = { sizeParam, alignParam };
115        if ( isStruct ) {
116                offsetParam = new ast::ObjectDecl(
117                        location,
118                        offsetofName( aggr->name ),
119                        makeSizeAlignOutType()
120                );
121                params.push_back( offsetParam );
122        }
123        addSTypeParams( params, sizedParams );
124
125        // Routines at global scope marked "static" to prevent multiple
126        // definitions is separate translation units because each unit generates
127        // copies of the default routines for each aggregate.
128        ast::FunctionDecl * layoutDecl = new ast::FunctionDecl(
129                location,
130                layoutofName( aggr ),
131                {}, // forall
132                {}, // assertions
133                std::move( params ),
134                {}, // returns
135                new ast::CompoundStmt( location ),
136                isInFunction ? ast::Storage::Classes() : ast::Storage::Static,
137                ast::Linkage::AutoGen,
138                {}, // attrs
139                ast::Function::Inline,
140                ast::FixedArgs
141        );
142        layoutDecl->fixUniqueId();
143        return LayoutData{ layoutDecl, sizeParam, alignParam, offsetParam };
144}
145
146/// Makes a binary operation.
147ast::Expr * makeOp( CodeLocation const & location, std::string const & name,
148                ast::Expr const * lhs, ast::Expr const * rhs ) {
149        return new ast::UntypedExpr( location,
150                new ast::NameExpr( location, name ), { lhs, rhs } );
151}
152
153/// Make a binary operation and wrap it in a statement.
154ast::Stmt * makeOpStmt( CodeLocation const & location, std::string const & name,
155                ast::Expr const * lhs, ast::Expr const * rhs ) {
156        return new ast::ExprStmt( location, makeOp( location, name, lhs, rhs ) );
157}
158
159/// Returns the dereference of a local pointer variable.
160ast::Expr * derefVar(
161                CodeLocation const & location, ast::ObjectDecl const * var ) {
162        return ast::UntypedExpr::createDeref( location,
163                new ast::VariableExpr( location, var ) );
164}
165
166/// Makes an if-statement with a single-expression then and no else.
167ast::Stmt * makeCond( CodeLocation const & location,
168                ast::Expr const * cond, ast::Expr const * thenPart ) {
169        return new ast::IfStmt( location,
170                cond, new ast::ExprStmt( location, thenPart ), nullptr );
171}
172
173/// Makes a statement that aligns lhs to rhs (rhs should be an integer
174/// power of two).
175ast::Stmt * makeAlignTo( CodeLocation const & location,
176                ast::Expr const * lhs, ast::Expr const * rhs ) {
177        // Check that the lhs is zeroed out to the level of rhs.
178        ast::Expr * ifCond = makeOp( location, "?&?", lhs,
179                makeOp( location, "?-?", rhs,
180                                ast::ConstantExpr::from_ulong( location, 1 ) ) );
181        // If not aligned, increment to alignment.
182        ast::Expr * ifExpr = makeOp( location, "?+=?", ast::deepCopy( lhs ),
183                makeOp( location, "?-?", ast::deepCopy( rhs ),
184                                ast::deepCopy( ifCond ) ) );
185        return makeCond( location, ifCond, ifExpr );
186}
187
188/// Makes a statement that assigns rhs to lhs if lhs < rhs.
189ast::Stmt * makeAssignMax( CodeLocation const & location,
190                ast::Expr const * lhs, ast::Expr const * rhs ) {
191        return makeCond( location,
192                makeOp( location, "?<?", ast::deepCopy( lhs ), ast::deepCopy( rhs ) ),
193                makeOp( location, "?=?", lhs, rhs ) );
194}
195
196void LayoutFunctionBuilder::previsit( ast::StructDecl const * decl ) {
197        // Do not generate layout function for empty tag structures.
198        visit_children = false;
199        if ( decl->members.empty() ) return;
200
201        // Get parameters that can change layout, exiting early if none.
202        ast::vector<ast::TypeDecl> sizedParams =
203                takeSizedParams( decl->params );
204        if ( sizedParams.empty() ) return;
205
206        CodeLocation const & location = decl->location;
207
208        // Build layout function signature.
209        LayoutData layout = buildLayoutFunction(
210                location, decl, sizedParams, isInFunction(), true );
211        ast::FunctionDecl * layoutDecl = layout.function;
212        // Also return these or extract them from the parameter list?
213        ast::ObjectDecl const * sizeofParam = layout.sizeofParam;
214        ast::ObjectDecl const * alignofParam = layout.alignofParam;
215        ast::ObjectDecl const * offsetofParam = layout.offsetofParam;
216        assert( nullptr != layout.offsetofParam );
217
218        // Calculate structure layout in function body.
219        // Initialize size and alignment to 0 and 1
220        // (Will have at least one member to update size).
221        auto & kids = layoutDecl->stmts.get_and_mutate()->kids;
222        kids.emplace_back( makeOpStmt( location, "?=?",
223                derefVar( location, sizeofParam ),
224                ast::ConstantExpr::from_ulong( location, 0 )
225        ) );
226        kids.emplace_back( makeOpStmt( location, "?=?",
227                derefVar( location, alignofParam ),
228                ast::ConstantExpr::from_ulong( location, 1 )
229        ) );
230        // TODO: Polymorphic types will be out of the struct declaration scope.
231        // Should be removed by PolyGenericCalculator.
232        for ( auto const & member : enumerate( decl->members ) ) {
233                auto dwt = member.val.strict_as<ast::DeclWithType>();
234                ast::Type const * memberType = dwt->get_type();
235
236                if ( 0 < member.idx ) {
237                        // Make sure all later members have padding to align them.
238                        kids.emplace_back( makeAlignTo( location,
239                                derefVar( location, sizeofParam ),
240                                new ast::AlignofExpr( location, ast::deepCopy( memberType ) )
241                        ) );
242                }
243
244                // Place current size in the current offset index.
245                kids.emplace_back( makeOpStmt( location, "?=?",
246                        makeOp( location, "?[?]",
247                                new ast::VariableExpr( location, offsetofParam ),
248                                ast::ConstantExpr::from_ulong( location, member.idx ) ),
249                        derefVar( location, sizeofParam ) ) );
250
251                // Add member size to current size.
252                kids.emplace_back( makeOpStmt( location, "?+=?",
253                        derefVar( location, sizeofParam ),
254                        new ast::SizeofExpr( location, ast::deepCopy( memberType ) ) ) );
255
256                // Take max of member alignment and global alignment.
257                // (As align is always 2^n, this will always be a multiple of both.)
258                kids.emplace_back( makeAssignMax( location,
259                        derefVar( location, alignofParam ),
260                        new ast::AlignofExpr( location, ast::deepCopy( memberType ) ) ) );
261        }
262        // Make sure the type is end-padded to a multiple of its alignment.
263        kids.emplace_back( makeAlignTo( location,
264                derefVar( location, sizeofParam ),
265                derefVar( location, alignofParam ) ) );
266
267        declsToAddAfter.emplace_back( layoutDecl );
268}
269
270void LayoutFunctionBuilder::previsit( ast::UnionDecl const * decl ) {
271        visit_children = false;
272        // Do not generate layout function for empty tag unions.
273        if ( decl->members.empty() ) return;
274
275        // Get parameters that can change layout, exiting early if none.
276        ast::vector<ast::TypeDecl> sizedParams =
277                takeSizedParams( decl->params );
278        if ( sizedParams.empty() ) return;
279
280        CodeLocation const & location = decl->location;
281
282        // Build layout function signature.
283        LayoutData layout = buildLayoutFunction(
284                location, decl, sizedParams, isInFunction(), false );
285        ast::FunctionDecl * layoutDecl = layout.function;
286        // Also return these or extract them from the parameter list?
287        ast::ObjectDecl const * sizeofParam = layout.sizeofParam;
288        ast::ObjectDecl const * alignofParam = layout.alignofParam;
289        assert( nullptr == layout.offsetofParam );
290
291        // Calculate union layout in function body.
292        // Both are simply the maximum for union (actually align is always the
293        // LCM, but with powers of two that is also the maximum).
294        auto & kids = layoutDecl->stmts.get_and_mutate()->kids;
295        kids.emplace_back( makeOpStmt( location,
296                "?=?", derefVar( location, sizeofParam ),
297                ast::ConstantExpr::from_ulong( location, 1 )
298        ) );
299        kids.emplace_back( makeOpStmt( location,
300                "?=?", derefVar( location, alignofParam ),
301                ast::ConstantExpr::from_ulong( location, 1 )
302        ) );
303        // TODO: Polymorphic types will be out of the union declaration scope.
304        for ( auto const & member : decl->members ) {
305                auto dwt = member.strict_as<ast::DeclWithType>();
306                ast::Type const * memberType = dwt->get_type();
307
308                // Take max member size and global size.
309                kids.emplace_back( makeAssignMax( location,
310                        derefVar( location, sizeofParam ),
311                        new ast::SizeofExpr( location, ast::deepCopy( memberType ) )
312                ) );
313
314                // Take max of member alignment and global alignment.
315                kids.emplace_back( makeAssignMax( location,
316                        derefVar( location, alignofParam ),
317                        new ast::AlignofExpr( location, ast::deepCopy( memberType ) )
318                ) );
319        }
320        kids.emplace_back( makeAlignTo( location,
321                derefVar( location, sizeofParam ),
322                derefVar( location, alignofParam ) ) );
323
324        declsToAddAfter.emplace_back( layoutDecl );
325}
326
327// --------------------------------------------------------------------------
328/// Application expression transformer.
329/// * Replaces polymorphic return types with out-parameters.
330/// * Replaces call to polymorphic functions with adapter calls which handles
331///   dynamic arguments and return values.
332/// * Adds appropriate type variables to the function calls.
333struct CallAdapter final :
334                public ast::WithConstTypeSubstitution,
335                public ast::WithGuards,
336                public ast::WithShortCircuiting,
337                public ast::WithStmtsToAdd<>,
338                public ast::WithVisitorRef<CallAdapter> {
339        CallAdapter();
340
341        void previsit( ast::Decl const * decl );
342        ast::FunctionDecl const * previsit( ast::FunctionDecl const * decl );
343        void previsit( ast::TypeDecl const * decl );
344        void previsit( ast::CommaExpr const * expr );
345        ast::Expr const * postvisit( ast::ApplicationExpr const * expr );
346        ast::Expr const * postvisit( ast::UntypedExpr const * expr );
347        void previsit( ast::AddressExpr const * expr );
348        ast::Expr const * postvisit( ast::AddressExpr const * expr );
349        ast::ReturnStmt const * previsit( ast::ReturnStmt const * stmt );
350
351        void beginScope();
352        void endScope();
353private:
354        // Many helpers here use a mutable ApplicationExpr as an in/out parameter
355        // instead of using the return value, to save on mutates and free up the
356        // return value.
357
358        /// Passes extra layout arguments for sized polymorphic type parameters.
359        ast::vector<ast::Expr>::iterator passTypeVars(
360                ast::ApplicationExpr * expr,
361                ast::FunctionType const * funcType );
362        /// Wraps a function application with a new temporary for the
363        /// out-parameter return value.
364        ast::Expr const * addRetParam(
365                ast::ApplicationExpr * expr, ast::Type const * retType );
366        /// Wraps a function application returning a polymorphic type with a new
367        /// temporary for the out-parameter return value.
368        ast::Expr const * addDynRetParam(
369                ast::ApplicationExpr * expr, ast::Type const * polyType );
370        /// Modify a call so it passes the function through the correct adapter.
371        ast::Expr const * applyAdapter(
372                ast::ApplicationExpr * expr,
373                ast::FunctionType const * function );
374        /// Convert a single argument into its boxed form to pass the parameter.
375        void boxParam( ast::ptr<ast::Expr> & arg,
376                ast::Type const * formal, TypeVarMap const & exprTyVars );
377        /// Box every argument from arg forward, matching the functionType
378        /// parameter list. arg should point into expr's argument list.
379        void boxParams(
380                ast::ApplicationExpr const * expr,
381                ast::vector<ast::Expr>::iterator arg,
382                ast::FunctionType const * function,
383                const TypeVarMap & typeVars );
384        /// Adds the inferred parameters derived from the assertions of the
385        /// expression to the call.
386        void addInferredParams(
387                ast::ApplicationExpr * expr,
388                ast::vector<ast::Expr>::iterator arg,
389                ast::FunctionType const * functionType,
390                const TypeVarMap & typeVars );
391        /// Stores assignment operators from assertion list in
392        /// local map of assignment operations.
393        void passAdapters(
394                ast::ApplicationExpr * expr,
395                ast::FunctionType const * type,
396                const TypeVarMap & typeVars );
397        /// Create an adapter function based on the type of the adaptee and the
398        /// real type with the type substitutions applied.
399        ast::FunctionDecl * makeAdapter(
400                ast::FunctionType const * adaptee,
401                ast::FunctionType const * realType,
402                std::string const & mangleName,
403                TypeVarMap const & typeVars,
404                CodeLocation const & location ) const;
405        /// Replaces intrinsic operator functions with their arithmetic desugaring.
406        ast::Expr const * handleIntrinsics( ast::ApplicationExpr const * );
407        /// Inserts a new temporary variable into the current scope with an
408        /// auto-generated name.
409        ast::ObjectDecl * makeTemporary(
410                CodeLocation const & location, ast::Type const * type );
411
412        TypeVarMap scopeTypeVars;
413        ScopedMap< std::string, ast::DeclWithType const * > adapters;
414        std::map< ast::ApplicationExpr const *, ast::Expr const * > retVals;
415        ast::DeclWithType const * retval;
416        UniqueName tmpNamer;
417};
418
419/// Replaces a polymorphic type with its concrete equivalant under the
420/// current environment (returns itself if concrete).
421/// If `doClone` is set to false, will not clone interior types
422ast::Type const * replaceWithConcrete(
423                ast::Type const * type,
424                ast::TypeSubstitution const & typeSubs,
425                bool doCopy = true );
426
427/// Replaces all the type parameters of a generic type with their
428/// concrete equivalents under the current environment.
429void replaceParametersWithConcrete(
430                ast::vector<ast::Expr> & params,
431                ast::TypeSubstitution const & typeSubs ) {
432        for ( ast::ptr<ast::Expr> & paramExpr : params ) {
433                ast::TypeExpr const * param = paramExpr.as<ast::TypeExpr>();
434                assertf( param, "Aggregate parameters should be type expressions." );
435                paramExpr = ast::mutate_field( param, &ast::TypeExpr::type,
436                        replaceWithConcrete( param->type.get(), typeSubs, false ) );
437        }
438}
439
440ast::Type const * replaceWithConcrete(
441                ast::Type const * type,
442                ast::TypeSubstitution const & typeSubs,
443                bool doCopy ) {
444        if ( auto instType = dynamic_cast<ast::TypeInstType const *>( type ) ) {
445                ast::Type const * concrete = typeSubs.lookup( instType );
446                return ( nullptr != concrete ) ? concrete : instType;
447        } else if ( auto structType =
448                        dynamic_cast<ast::StructInstType const *>( type ) ) {
449                ast::StructInstType * newType =
450                        doCopy ? ast::deepCopy( structType ) : ast::mutate( structType );
451                replaceParametersWithConcrete( newType->params, typeSubs );
452                return newType;
453        } else if ( auto unionType =
454                        dynamic_cast<ast::UnionInstType const *>( type ) ) {
455                ast::UnionInstType * newType =
456                        doCopy ? ast::deepCopy( unionType ) : ast::mutate( unionType );
457                replaceParametersWithConcrete( newType->params, typeSubs );
458                return newType;
459        } else {
460                return type;
461        }
462}
463
464std::string makePolyMonoSuffix(
465                ast::FunctionType const * function,
466                TypeVarMap const & typeVars ) {
467        // If the return type or a parameter type involved polymorphic types,
468        // then the adapter will need to take those polymorphic types as pointers.
469        // Therefore, there can be two different functions with the same mangled
470        // name, so we need to further mangle the names.
471        std::stringstream name;
472        for ( auto ret : function->returns ) {
473                name << ( isPolyType( ret, typeVars ) ? 'P' : 'M' );
474        }
475        name << '_';
476        for ( auto arg : function->params ) {
477                name << ( isPolyType( arg, typeVars ) ? 'P' : 'M' );
478        }
479        return name.str();
480}
481
482std::string mangleAdapterName(
483                ast::FunctionType const * function,
484                TypeVarMap const & typeVars ) {
485        return Mangle::mangle( function, {} )
486                + makePolyMonoSuffix( function, typeVars );
487}
488
489std::string makeAdapterName( std::string const & mangleName ) {
490        return "_adapter" + mangleName;
491}
492
493void makeRetParam( ast::FunctionType * type ) {
494        ast::ptr<ast::Type> & retParam = type->returns.front();
495
496        // Make a new parameter that is a pointer to the type of the old return value.
497        retParam = new ast::PointerType( retParam.get() );
498        type->params.emplace( type->params.begin(), retParam );
499
500        // We don't need the return value any more.
501        type->returns.clear();
502}
503
504ast::FunctionType * makeAdapterType(
505                ast::FunctionType const * adaptee,
506                TypeVarMap const & typeVars ) {
507        ast::FunctionType * adapter = ast::deepCopy( adaptee );
508        if ( isDynRet( adapter, typeVars ) ) {
509                makeRetParam( adapter );
510        }
511        adapter->params.emplace( adapter->params.begin(),
512                new ast::PointerType( new ast::FunctionType( ast::VariableArgs ) )
513        );
514        return adapter;
515}
516
517CallAdapter::CallAdapter() : tmpNamer( "_temp" ) {}
518
519void CallAdapter::previsit( ast::Decl const * ) {
520        // Prevent type declaration information from leaking out.
521        GuardScope( scopeTypeVars );
522}
523
524ast::FunctionDecl const * CallAdapter::previsit( ast::FunctionDecl const * decl ) {
525        // Prevent type declaration information from leaking out.
526        GuardScope( scopeTypeVars );
527
528        if ( nullptr == decl->stmts ) {
529                return decl;
530        }
531
532        GuardValue( retval );
533
534        // Process polymorphic return value.
535        retval = nullptr;
536        ast::FunctionType const * type = decl->type;
537        if ( isDynRet( type ) && decl->linkage != ast::Linkage::C ) {
538                retval = decl->returns.front();
539
540                // Give names to unnamed return values.
541                if ( "" == retval->name ) {
542                        auto mutRet = ast::mutate( retval );
543                        mutRet->name = "_retparam";
544                        mutRet->linkage = ast::Linkage::C;
545                        retval = mutRet;
546                        decl = ast::mutate_field_index( decl,
547                                &ast::FunctionDecl::returns, 0, mutRet );
548                }
549        }
550
551        // The formal_usage/expr_id values may be off if we get them from the
552        // type, trying the declaration instead.
553        makeTypeVarMap( type, scopeTypeVars );
554
555        // Get all needed adapters from the call. We will forward them.
556        ast::vector<ast::FunctionType> functions;
557        for ( ast::ptr<ast::VariableExpr> const & assertion : type->assertions ) {
558                auto atype = assertion->result.get();
559                findFunction( atype, functions, scopeTypeVars, needsAdapter );
560        }
561
562        for ( ast::ptr<ast::Type> const & arg : type->params ) {
563                findFunction( arg, functions, scopeTypeVars, needsAdapter );
564        }
565
566        for ( auto funcType : functions ) {
567                std::string mangleName = mangleAdapterName( funcType, scopeTypeVars );
568                if ( adapters.contains( mangleName ) ) continue;
569                std::string adapterName = makeAdapterName( mangleName );
570                // TODO: The forwarding here is problematic because these
571                // declarations are not rooted anywhere in the translation unit.
572                adapters.insert(
573                        mangleName,
574                        new ast::ObjectDecl(
575                                decl->location,
576                                adapterName,
577                                new ast::PointerType(
578                                        makeAdapterType( funcType, scopeTypeVars ) ),
579                                nullptr, // init
580                                ast::Storage::Classes(),
581                                ast::Linkage::C
582                        )
583                );
584        }
585
586        return decl;
587}
588
589void CallAdapter::previsit( ast::TypeDecl const * decl ) {
590        addToTypeVarMap( decl, scopeTypeVars );
591}
592
593void CallAdapter::previsit( ast::CommaExpr const * expr ) {
594        // Attempting to find application expressions that were mutated by the
595        // copy constructor passes to use an explicit return variable, so that
596        // the variable can be reused as a parameter to the call rather than
597        // creating a new temporary variable. Previously this step was an
598        // optimization, but with the introduction of tuples and UniqueExprs,
599        // it is necessary to ensure that they use the same variable.
600        // Essentially, looking for pattern:
601        // (x=f(...), x)
602        // To compound the issue, the right side can be *x, etc.
603        // because of lvalue-returning functions
604        if ( auto assign = expr->arg1.as<ast::UntypedExpr>() ) {
605                if ( CodeGen::isAssignment( ast::getFunctionName( assign ) ) ) {
606                        assert( 2 == assign->args.size() );
607                        if ( auto app = assign->args.back().as<ast::ApplicationExpr>() ) {
608                                // First argument is assignable, so it must be an lvalue,
609                                // so it should be legal to takes its address.
610                                retVals.insert_or_assign( app, assign->args.front() );
611                        }
612                }
613        }
614}
615
616ast::Expr const * CallAdapter::postvisit( ast::ApplicationExpr const * expr ) {
617        assert( expr->func->result );
618        ast::FunctionType const * function = getFunctionType( expr->func->result );
619        assertf( function, "ApplicationExpr has non-function type %s",
620                        toCString( expr->func->result ) );
621
622        if ( auto newExpr = handleIntrinsics( expr ) ) {
623                return newExpr;
624        }
625
626        ast::ApplicationExpr * mutExpr = ast::mutate( expr );
627        ast::Expr const * ret = expr;
628
629        // TODO: This entire section should probably be refactored to do less
630        // pushing to the front/middle of a vector.
631        ptrdiff_t initArgCount = mutExpr->args.size();
632
633        TypeVarMap exprTypeVars;
634        // TODO: Should this take into account the variables already bound in
635        // scopeTypeVars ([ex] remove them from exprTypeVars)?
636        makeTypeVarMap( function, exprTypeVars );
637        auto dynRetType = isDynRet( function, exprTypeVars );
638
639        // NOTE: addDynRetParam needs to know the actual (generated) return type
640        // so it can make a temporary variable, so pass the result type form the
641        // `expr` `passTypeVars` needs to know the program-text return type ([ex]
642        // the distinction between _conc_T30 and T3(int)) concRetType may not be
643        // a good name in one or both of these places.
644        if ( dynRetType ) {
645                ast::Type const * result = mutExpr->result;
646                ast::Type const * concRetType = result->isVoid() ? nullptr : result;
647                // [Comment from before translation.]
648                // Used to use dynRetType instead of concRetType.
649                ret = addDynRetParam( mutExpr, concRetType );
650        } else if ( needsAdapter( function, scopeTypeVars )
651                        && !needsAdapter( function, exprTypeVars ) ) {
652                // Change the application so it calls the adapter rather than the
653                // passed function.
654                ret = applyAdapter( mutExpr, function );
655        }
656
657        assert( typeSubs );
658        ast::vector<ast::Expr>::iterator argIt =
659                passTypeVars( mutExpr, function );
660        addInferredParams( mutExpr, argIt, function, exprTypeVars );
661
662        argIt = mutExpr->args.begin();
663        std::advance( argIt, ( mutExpr->args.size() - initArgCount ) );
664
665        boxParams( mutExpr, argIt, function, exprTypeVars );
666        passAdapters( mutExpr, function, exprTypeVars );
667
668        return ret;
669}
670
671bool isPolyDeref( ast::UntypedExpr const * expr,
672                TypeVarMap const & typeVars,
673                ast::TypeSubstitution const * typeSubs ) {
674        if ( expr->result && isPolyType( expr->result, typeVars, typeSubs ) ) {
675                if ( auto name = expr->func.as<ast::NameExpr>() ) {
676                        if ( "*?" == name->name ) {
677                                return true;
678                        }
679                }
680        }
681        return false;
682}
683
684ast::Expr const * CallAdapter::postvisit( ast::UntypedExpr const * expr ) {
685        if ( isPolyDeref( expr, scopeTypeVars, typeSubs ) ) {
686                return expr->args.front();
687        }
688        return expr;
689}
690
691void CallAdapter::previsit( ast::AddressExpr const * ) {
692        visit_children = false;
693}
694
695ast::Expr const * CallAdapter::postvisit( ast::AddressExpr const * expr ) {
696        assert( expr->arg->result );
697        assert( !expr->arg->result->isVoid() );
698
699        bool doesNeedAdapter = false;
700        if ( auto un = expr->arg.as<ast::UntypedExpr>() ) {
701                if ( isPolyDeref( un, scopeTypeVars, typeSubs ) ) {
702                        if ( auto app = un->args.front().as<ast::ApplicationExpr>() ) {
703                                assert( app->func->result );
704                                auto function = getFunctionType( app->func->result );
705                                assert( function );
706                                doesNeedAdapter = needsAdapter( function, scopeTypeVars );
707                        }
708                }
709        }
710        // isPolyType check needs to happen before mutating expr arg,
711        // so pull it forward out of the if condition.
712        expr = ast::mutate_field( expr, &ast::AddressExpr::arg,
713                        expr->arg->accept( *visitor ) );
714        // But must happen after mutate, since argument might change
715        // (ex. intrinsic *?, ?[?]) re-evaluate above comment.
716        bool polyType = isPolyType( expr->arg->result, scopeTypeVars, typeSubs );
717        if ( polyType || doesNeedAdapter ) {
718                ast::Expr * ret = ast::mutate( expr->arg.get() );
719                ret->result = ast::deepCopy( expr->result );
720                return ret;
721        } else {
722                return expr;
723        }
724}
725
726ast::ReturnStmt const * CallAdapter::previsit( ast::ReturnStmt const * stmt ) {
727        // Since retval is set when the return type is dynamic, this function
728        // should have been converted to void return & out parameter.
729        if ( retval && stmt->expr ) {
730                assert( stmt->expr->result );
731                assert( !stmt->expr->result->isVoid() );
732                return ast::mutate_field( stmt, &ast::ReturnStmt::expr, nullptr );
733        }
734        return stmt;
735}
736
737void CallAdapter::beginScope() {
738        adapters.beginScope();
739}
740
741void CallAdapter::endScope() {
742        adapters.endScope();
743}
744
745/// Find instances of polymorphic type parameters.
746struct PolyFinder {
747        TypeVarMap const & typeVars;
748        bool result = false;
749        PolyFinder( TypeVarMap const & tvs ) : typeVars( tvs ) {}
750
751        void previsit( ast::TypeInstType const * type ) {
752                if ( isPolyType( type, typeVars ) ) result = true;
753        }
754};
755
756/// True if these is an instance of a polymorphic type parameter in the type.
757bool hasPolymorphism( ast::Type const * type, TypeVarMap const & typeVars ) {
758        return ast::Pass<PolyFinder>::read( type, typeVars );
759}
760
761ast::vector<ast::Expr>::iterator CallAdapter::passTypeVars(
762                ast::ApplicationExpr * expr,
763                ast::FunctionType const * function ) {
764        assert( typeSubs );
765        ast::vector<ast::Expr>::iterator arg = expr->args.begin();
766        // Pass size/align for type variables.
767        for ( ast::ptr<ast::TypeInstType> const & typeVar : function->forall ) {
768                if ( !typeVar->base->isComplete() ) continue;
769                ast::Type const * concrete = typeSubs->lookup( typeVar );
770                if ( !concrete ) {
771                        // Should this be an assertion?
772                        SemanticError( expr, toString( typeSubs,
773                                "\nunbound type variable: ", typeVar->typeString(),
774                                " in application " ) );
775                }
776                arg = expr->args.insert( arg,
777                        new ast::SizeofExpr( expr->location, ast::deepCopy( concrete ) ) );
778                arg++;
779                arg = expr->args.insert( arg,
780                        new ast::AlignofExpr( expr->location, ast::deepCopy( concrete ) ) );
781                arg++;
782        }
783        return arg;
784}
785
786ast::Expr const * CallAdapter::addRetParam(
787                ast::ApplicationExpr * expr, ast::Type const * retType ) {
788        // Create temporary to hold return value of polymorphic function and
789        // produce that temporary as a result using a comma expression.
790        assert( retType );
791
792        ast::Expr * paramExpr = nullptr;
793        // Try to use existing return value parameter if it exists,
794        // otherwise create a new temporary.
795        if ( retVals.count( expr ) ) {
796                paramExpr = ast::deepCopy( retVals[ expr ] );
797        } else {
798                auto newObj = makeTemporary( expr->location, ast::deepCopy( retType ) );
799                paramExpr = new ast::VariableExpr( expr->location, newObj );
800        }
801        ast::Expr * retExpr = ast::deepCopy( paramExpr );
802
803        // If the type of the temporary is not polpmorphic, box temporary by
804        // taking its address; otherwise the temporary is already boxed and can
805        // be used directly.
806        if ( !isPolyType( paramExpr->result, scopeTypeVars, typeSubs ) ) {
807                paramExpr = new ast::AddressExpr( paramExpr->location, paramExpr );
808        }
809        // Add argument to function call.
810        expr->args.insert( expr->args.begin(), paramExpr );
811        // Build a comma expression to call the function and return a value.
812        ast::CommaExpr * comma = new ast::CommaExpr(
813                expr->location, expr, retExpr );
814        comma->env = expr->env;
815        expr->env = nullptr;
816        return comma;
817}
818
819ast::Expr const * CallAdapter::addDynRetParam(
820                ast::ApplicationExpr * expr, ast::Type const * polyType ) {
821        assert( typeSubs );
822        ast::Type const * concrete = replaceWithConcrete( polyType, *typeSubs );
823        // Add out-parameter for return value.
824        return addRetParam( expr, concrete );
825}
826
827ast::Expr const * CallAdapter::applyAdapter(
828                ast::ApplicationExpr * expr,
829                ast::FunctionType const * function ) {
830        ast::Expr const * ret = expr;
831        if ( isDynRet( function, scopeTypeVars ) ) {
832                ret = addRetParam( expr, function->returns.front() );
833        }
834        std::string mangleName = mangleAdapterName( function, scopeTypeVars );
835        std::string adapterName = makeAdapterName( mangleName );
836
837        // Cast adaptee to `void (*)()`, since it may have any type inside a
838        // polymorphic function.
839        ast::Type const * adapteeType = new ast::PointerType(
840                new ast::FunctionType( ast::VariableArgs ) );
841        expr->args.insert( expr->args.begin(),
842                new ast::CastExpr( expr->location, expr->func, adapteeType ) );
843        // The result field is never set on NameExpr. / Now it is.
844        auto head = new ast::NameExpr( expr->location, adapterName );
845        head->result = ast::deepCopy( adapteeType );
846        expr->func = head;
847
848        return ret;
849}
850
851/// Cast parameters to polymorphic functions so that types are replaced with
852/// `void *` if they are type parameters in the formal type.
853/// This gets rid of warnings from gcc.
854void addCast(
855                ast::ptr<ast::Expr> & actual,
856                ast::Type const * formal,
857                TypeVarMap const & typeVars ) {
858        // Type contains polymorphism, but isn't exactly a polytype, in which
859        // case it has some real actual type (ex. unsigned int) and casting to
860        // `void *` is wrong.
861        if ( hasPolymorphism( formal, typeVars )
862                        && !isPolyType( formal, typeVars ) ) {
863                ast::Type const * newType = ast::deepCopy( formal );
864                newType = scrubTypeVars( newType, typeVars );
865                actual = new ast::CastExpr( actual->location, actual, newType );
866        }
867}
868
869void CallAdapter::boxParam( ast::ptr<ast::Expr> & arg,
870                ast::Type const * param, TypeVarMap const & exprTypeVars ) {
871        assertf( arg->result, "arg does not have result: %s", toCString( arg ) );
872        addCast( arg, param, exprTypeVars );
873        if ( !needsBoxing( param, arg->result, exprTypeVars, typeSubs ) ) {
874                return;
875        }
876        CodeLocation const & location = arg->location;
877
878        if ( arg->get_lvalue() ) {
879                // The argument expression may be CFA lvalue, but not C lvalue,
880                // so apply generalizedLvalue transformations.
881                // if ( auto var = dynamic_cast<ast::VariableExpr const *>( arg ) ) {
882                //  if ( dynamic_cast<ast::ArrayType const *>( varExpr->var->get_type() ) ){
883                //      // temporary hack - don't box arrays, because &arr is not the same as &arr[0]
884                //      return;
885                //  }
886                // }
887                arg = generalizedLvalue( new ast::AddressExpr( arg->location, arg ) );
888                if ( !ResolvExpr::typesCompatible( param, arg->result ) ) {
889                        // Silence warnings by casting boxed parameters when the actually
890                        // type does not match up with the formal type.
891                        arg = new ast::CastExpr( location, arg, ast::deepCopy( param ) );
892                }
893        } else {
894                // Use type computed in unification to declare boxed variables.
895                ast::ptr<ast::Type> newType = ast::deepCopy( param );
896                if ( typeSubs ) typeSubs->apply( newType );
897                ast::ObjectDecl * newObj = makeTemporary( location, newType );
898                auto assign = ast::UntypedExpr::createCall( location, "?=?", {
899                        new ast::VariableExpr( location, newObj ),
900                        arg,
901                } );
902                stmtsToAddBefore.push_back( new ast::ExprStmt( location, assign ) );
903                arg = new ast::AddressExpr(
904                        new ast::VariableExpr( location, newObj ) );
905        }
906}
907
908void CallAdapter::boxParams(
909                ast::ApplicationExpr const * expr,
910                ast::vector<ast::Expr>::iterator arg,
911                ast::FunctionType const * function,
912                const TypeVarMap & typeVars ) {
913        for ( auto param : function->params ) {
914                assertf( arg != expr->args.end(),
915                        "boxParams: missing argument for param %s to %s in %s",
916                        toCString( param ), toCString( function ), toCString( expr ) );
917                boxParam( *arg, param, typeVars );
918                ++arg;
919        }
920}
921
922void CallAdapter::addInferredParams(
923                ast::ApplicationExpr * expr,
924                ast::vector<ast::Expr>::iterator arg,
925                ast::FunctionType const * functionType,
926                TypeVarMap const & typeVars ) {
927        ast::vector<ast::Expr>::iterator cur = arg;
928        for ( auto assertion : functionType->assertions ) {
929                auto inferParam = expr->inferred.inferParams().find(
930                        assertion->var->uniqueId );
931                assertf( inferParam != expr->inferred.inferParams().end(),
932                        "addInferredParams missing inferred parameter: %s in: %s",
933                        toCString( assertion ), toCString( expr ) );
934                ast::ptr<ast::Expr> newExpr = ast::deepCopy( inferParam->second.expr );
935                boxParam( newExpr, assertion->result, typeVars );
936                cur = expr->args.insert( cur, newExpr.release() );
937                ++cur;
938        }
939}
940
941/// Modifies the ApplicationExpr to accept adapter functions for its
942/// assertion and parameters, declares the required adapters.
943void CallAdapter::passAdapters(
944                ast::ApplicationExpr * expr,
945                ast::FunctionType const * type,
946                const TypeVarMap & exprTypeVars ) {
947        // Collect a list of function types passed as parameters or implicit
948        // parameters (assertions).
949        ast::vector<ast::Type> const & paramList = type->params;
950        ast::vector<ast::FunctionType> functions;
951
952        for ( ast::ptr<ast::VariableExpr> const & assertion : type->assertions ) {
953                findFunction( assertion->result, functions, exprTypeVars, needsAdapter );
954        }
955        for ( ast::ptr<ast::Type> const & arg : paramList ) {
956                findFunction( arg, functions, exprTypeVars, needsAdapter );
957        }
958
959        // Parameter function types for which an appropriate adapter has been
960        // generated. We cannot use the types after applying substitutions,
961        // since two different parameter types may be unified to the same type.
962        std::set<std::string> adaptersDone;
963
964        CodeLocation const & location = expr->location;
965
966        for ( ast::ptr<ast::FunctionType> const & funcType : functions ) {
967                std::string mangleName = Mangle::mangle( funcType );
968
969                // Only attempt to create an adapter or pass one as a parameter if we
970                // haven't already done so for this pre-substitution parameter
971                // function type.
972                // The second part of the result if is if the element was inserted.
973                if ( !adaptersDone.insert( mangleName ).second ) continue;
974
975                // Apply substitution to type variables to figure out what the
976                // adapter's type should look like. (Copy to make the release safe.)
977                assert( typeSubs );
978                auto result = typeSubs->apply( ast::deepCopy( funcType ) );
979                ast::FunctionType * realType = ast::mutate( result.node.release() );
980                mangleName = Mangle::mangle( realType );
981                mangleName += makePolyMonoSuffix( funcType, exprTypeVars );
982
983                // Check if the adapter has already been created, or has to be.
984                using AdapterIter = decltype(adapters)::iterator;
985                AdapterIter adapter = adapters.find( mangleName );
986                if ( adapter == adapters.end() ) {
987                        ast::FunctionDecl * newAdapter = makeAdapter(
988                                funcType, realType, mangleName, exprTypeVars, location );
989                        std::pair<AdapterIter, bool> answer =
990                                adapters.insert( mangleName, newAdapter );
991                        adapter = answer.first;
992                        stmtsToAddBefore.push_back(
993                                new ast::DeclStmt( location, newAdapter ) );
994                }
995                assert( adapter != adapters.end() );
996
997                // Add the approprate adapter as a parameter.
998                expr->args.insert( expr->args.begin(),
999                        new ast::VariableExpr( location, adapter->second ) );
1000        }
1001}
1002
1003// Parameter and argument may be used wrong around here.
1004ast::Expr * makeAdapterArg(
1005                ast::DeclWithType const * param,
1006                ast::Type const * arg,
1007                ast::Type const * realParam,
1008                TypeVarMap const & typeVars,
1009                CodeLocation const & location ) {
1010        assert( param );
1011        assert( arg );
1012        assert( realParam );
1013        if ( isPolyType( realParam, typeVars ) && !isPolyType( arg ) ) {
1014                ast::UntypedExpr * deref = ast::UntypedExpr::createDeref(
1015                        location,
1016                        new ast::CastExpr( location,
1017                                new ast::VariableExpr( location, param ),
1018                                new ast::PointerType( ast::deepCopy( arg ) )
1019                        )
1020                );
1021                deref->result = ast::deepCopy( arg );
1022                return deref;
1023        }
1024        return new ast::VariableExpr( location, param );
1025}
1026
1027// This seems to be one of the problematic functions.
1028void addAdapterParams(
1029                ast::ApplicationExpr * adaptee,
1030                ast::vector<ast::Type>::const_iterator arg,
1031                ast::vector<ast::DeclWithType>::iterator param,
1032                ast::vector<ast::DeclWithType>::iterator paramEnd,
1033                ast::vector<ast::Type>::const_iterator realParam,
1034                TypeVarMap const & typeVars,
1035                CodeLocation const & location ) {
1036        UniqueName paramNamer( "_p" );
1037        for ( ; param != paramEnd ; ++param, ++arg, ++realParam ) {
1038                if ( "" == (*param)->name ) {
1039                        auto mutParam = (*param).get_and_mutate();
1040                        mutParam->name = paramNamer.newName();
1041                        mutParam->linkage = ast::Linkage::C;
1042                }
1043                adaptee->args.push_back(
1044                        makeAdapterArg( *param, *arg, *realParam, typeVars, location ) );
1045        }
1046}
1047
1048ast::FunctionDecl * CallAdapter::makeAdapter(
1049                ast::FunctionType const * adaptee,
1050                ast::FunctionType const * realType,
1051                std::string const & mangleName,
1052                TypeVarMap const & typeVars,
1053                CodeLocation const & location ) const {
1054        ast::FunctionType * adapterType = makeAdapterType( adaptee, typeVars );
1055        adapterType = ast::mutate( scrubTypeVars( adapterType, typeVars ) );
1056
1057        // Some of these names will be overwritten, but it gives a default.
1058        UniqueName pNamer( "_param" );
1059        UniqueName rNamer( "_ret" );
1060
1061        bool first = true;
1062
1063        ast::FunctionDecl * adapterDecl = new ast::FunctionDecl( location,
1064                makeAdapterName( mangleName ),
1065                {}, // forall
1066                {}, // assertions
1067                map_range<ast::vector<ast::DeclWithType>>( adapterType->params,
1068                                [&pNamer, &location, &first]( ast::ptr<ast::Type> const & param ) {
1069                        // [Trying to make the generated code match exactly more often.]
1070                        if ( first ) {
1071                                first = false;
1072                                return new ast::ObjectDecl( location, "_adaptee", param );
1073                        }
1074                        return new ast::ObjectDecl( location, pNamer.newName(), param );
1075                } ),
1076                map_range<ast::vector<ast::DeclWithType>>( adapterType->returns,
1077                                [&rNamer, &location]( ast::ptr<ast::Type> const & retval ) {
1078                        return new ast::ObjectDecl( location, rNamer.newName(), retval );
1079                } ),
1080                nullptr, // stmts
1081                {}, // storage
1082                ast::Linkage::C
1083        );
1084
1085        ast::DeclWithType * adapteeDecl =
1086                adapterDecl->params.front().get_and_mutate();
1087        adapteeDecl->name = "_adaptee";
1088
1089        // Do not carry over attributes to real type parameters/return values.
1090        auto mutRealType = ast::mutate( realType );
1091        for ( ast::ptr<ast::Type> & decl : mutRealType->params ) {
1092                if ( decl->attributes.empty() ) continue;
1093                auto mut = ast::mutate( decl.get() );
1094                mut->attributes.clear();
1095                decl = mut;
1096        }
1097        for ( ast::ptr<ast::Type> & decl : mutRealType->returns ) {
1098                if ( decl->attributes.empty() ) continue;
1099                auto mut = ast::mutate( decl.get() );
1100                mut->attributes.clear();
1101                decl = mut;
1102        }
1103        realType = mutRealType;
1104
1105        ast::ApplicationExpr * adapteeApp = new ast::ApplicationExpr( location,
1106                new ast::CastExpr( location,
1107                        new ast::VariableExpr( location, adapteeDecl ),
1108                        new ast::PointerType( realType )
1109                )
1110        );
1111
1112        for ( auto group : group_iterate( realType->assertions,
1113                        adapterType->assertions, adaptee->assertions ) ) {
1114                auto assertArg = std::get<0>( group );
1115                auto assertParam = std::get<1>( group );
1116                auto assertReal = std::get<2>( group );
1117                adapteeApp->args.push_back( makeAdapterArg(
1118                        assertParam->var, assertArg->var->get_type(),
1119                        assertReal->var->get_type(), typeVars, location
1120                ) );
1121        }
1122
1123        ast::vector<ast::Type>::const_iterator
1124                arg = realType->params.begin(),
1125                param = adapterType->params.begin(),
1126                realParam = adaptee->params.begin();
1127        ast::vector<ast::DeclWithType>::iterator
1128                paramDecl = adapterDecl->params.begin();
1129        // Skip adaptee parameter in the adapter type.
1130        ++param;
1131        ++paramDecl;
1132
1133        ast::Stmt * bodyStmt;
1134        // Returns void/nothing.
1135        if ( realType->returns.empty() ) {
1136                addAdapterParams( adapteeApp, arg, paramDecl, adapterDecl->params.end(),
1137                        realParam, typeVars, location );
1138                bodyStmt = new ast::ExprStmt( location, adapteeApp );
1139        // Returns a polymorphic type.
1140        } else if ( isDynType( adaptee->returns.front(), typeVars ) ) {
1141                ast::UntypedExpr * assign = new ast::UntypedExpr( location,
1142                        new ast::NameExpr( location, "?=?" ) );
1143                ast::UntypedExpr * deref = ast::UntypedExpr::createDeref( location,
1144                        new ast::CastExpr( location,
1145                                new ast::VariableExpr( location, *paramDecl++ ),
1146                                new ast::PointerType(
1147                                        ast::deepCopy( realType->returns.front() ) ) ) );
1148                assign->args.push_back( deref );
1149                addAdapterParams( adapteeApp, arg, paramDecl, adapterDecl->params.end(),
1150                        realParam, typeVars, location );
1151                assign->args.push_back( adapteeApp );
1152                bodyStmt = new ast::ExprStmt( location, assign );
1153        // Adapter for a function that returns a monomorphic value.
1154        } else {
1155                addAdapterParams( adapteeApp, arg, paramDecl, adapterDecl->params.end(),
1156                                realParam, typeVars, location );
1157                bodyStmt = new ast::ReturnStmt( location, adapteeApp );
1158        }
1159
1160        adapterDecl->stmts = new ast::CompoundStmt( location, { bodyStmt } );
1161        return adapterDecl;
1162}
1163
1164ast::Expr const * makeIncrDecrExpr(
1165                CodeLocation const & location,
1166                ast::ApplicationExpr const * expr,
1167                ast::Type const * polyType,
1168                bool isIncr ) {
1169        ast::NameExpr * opExpr =
1170                        new ast::NameExpr( location, isIncr ? "?+=?" : "?-=?" );
1171        ast::UntypedExpr * addAssign = new ast::UntypedExpr( location, opExpr );
1172        if ( auto address = expr->args.front().as<ast::AddressExpr>() ) {
1173                addAssign->args.push_back( address->arg );
1174        } else {
1175                addAssign->args.push_back( expr->args.front() );
1176        }
1177        addAssign->args.push_back( new ast::NameExpr( location,
1178                sizeofName( Mangle::mangleType( polyType ) ) ) );
1179        addAssign->result = ast::deepCopy( expr->result );
1180        addAssign->env = expr->env ? expr->env : addAssign->env;
1181        return addAssign;
1182}
1183
1184/// Handles intrinsic functions for postvisit ApplicationExpr.
1185ast::Expr const * CallAdapter::handleIntrinsics(
1186                ast::ApplicationExpr const * expr ) {
1187        auto varExpr = expr->func.as<ast::VariableExpr>();
1188        if ( !varExpr || varExpr->var->linkage != ast::Linkage::Intrinsic ) {
1189                return nullptr;
1190        }
1191        std::string const & varName = varExpr->var->name;
1192
1193        // Index Intrinsic:
1194        if ( "?[?]" == varName ) {
1195                assert( expr->result );
1196                assert( 2 == expr->args.size() );
1197
1198                ast::Type const * baseType1 =
1199                        isPolyPtr( expr->args.front()->result, scopeTypeVars, typeSubs );
1200                ast::Type const * baseType2 =
1201                        isPolyPtr( expr->args.back()->result, scopeTypeVars, typeSubs );
1202                // If neither argument is a polymorphic pointer, do nothing.
1203                if ( !baseType1 && !baseType2 ) {
1204                        return expr;
1205                }
1206                // The arguments cannot both be polymorphic pointers.
1207                assert( !baseType1 || !baseType2 );
1208                // (So exactly one of the arguments is a polymorphic pointer.)
1209
1210                CodeLocation const & location = expr->location;
1211                CodeLocation const & location1 = expr->args.front()->location;
1212                CodeLocation const & location2 = expr->args.back()->location;
1213
1214                ast::UntypedExpr * ret = new ast::UntypedExpr( location,
1215                                new ast::NameExpr( location, "?+?" ) );
1216                if ( baseType1 ) {
1217                        auto multiply = ast::UntypedExpr::createCall( location2, "?*?", {
1218                                expr->args.back(),
1219                                new ast::SizeofExpr( location1, deepCopy( baseType1 ) ),
1220                        } );
1221                        ret->args.push_back( expr->args.front() );
1222                        ret->args.push_back( multiply );
1223                } else {
1224                        assert( baseType2 );
1225                        auto multiply = ast::UntypedExpr::createCall( location1, "?*?", {
1226                                expr->args.front(),
1227                                new ast::SizeofExpr( location2, deepCopy( baseType2 ) ),
1228                        } );
1229                        ret->args.push_back( multiply );
1230                        ret->args.push_back( expr->args.back() );
1231                }
1232                ret->result = ast::deepCopy( expr->result );
1233                ret->env = expr->env ? expr->env : ret->env;
1234                return ret;
1235        // Dereference Intrinsic:
1236        } else if ( "*?" == varName ) {
1237                assert( expr->result );
1238                assert( 1 == expr->args.size() );
1239
1240                // If this isn't for a poly type, then do nothing.
1241                if ( !isPolyType( expr->result, scopeTypeVars, typeSubs ) ) {
1242                        return expr;
1243                }
1244
1245                // Remove dereference from polymorphic types since they are boxed.
1246                ast::Expr * ret = ast::deepCopy( expr->args.front() );
1247                // Fix expression type to remove pointer.
1248                ret->result = expr->result;
1249                ret->env = expr->env ? expr->env : ret->env;
1250                return ret;
1251        // Post-Increment/Decrement Intrinsics:
1252        } else if ( "?++" == varName || "?--" == varName ) {
1253                assert( expr->result );
1254                assert( 1 == expr->args.size() );
1255
1256                ast::Type const * baseType =
1257                        isPolyType( expr->result, scopeTypeVars, typeSubs );
1258                if ( nullptr == baseType ) {
1259                        return expr;
1260                }
1261                ast::Type * tempType = ast::deepCopy( expr->result );
1262                if ( typeSubs ) {
1263                        auto result = typeSubs->apply( tempType );
1264                        tempType = ast::mutate( result.node.release() );
1265                }
1266                CodeLocation const & location = expr->location;
1267                ast::ObjectDecl * newObj = makeTemporary( location, tempType );
1268                ast::VariableExpr * tempExpr =
1269                        new ast::VariableExpr( location, newObj );
1270                ast::UntypedExpr * assignExpr = new ast::UntypedExpr( location,
1271                        new ast::NameExpr( location, "?=?" ) );
1272                assignExpr->args.push_back( ast::deepCopy( tempExpr ) );
1273                if ( auto address = expr->args.front().as<ast::AddressExpr>() ) {
1274                        assignExpr->args.push_back( ast::deepCopy( address->arg ) );
1275                } else {
1276                        assignExpr->args.push_back( ast::deepCopy( expr->args.front() ) );
1277                }
1278                return new ast::CommaExpr( location,
1279                        new ast::CommaExpr( location,
1280                                assignExpr,
1281                                makeIncrDecrExpr( location, expr, baseType, "?++" == varName )
1282                        ),
1283                        tempExpr
1284                );
1285        // Pre-Increment/Decrement Intrinsics:
1286        } else if ( "++?" == varName || "--?" == varName ) {
1287                assert( expr->result );
1288                assert( 1 == expr->args.size() );
1289
1290                ast::Type const * baseType =
1291                        isPolyType( expr->result, scopeTypeVars, typeSubs );
1292                if ( nullptr == baseType ) {
1293                        return expr;
1294                }
1295                return makeIncrDecrExpr(
1296                        expr->location, expr, baseType, "++?" == varName );
1297        // Addition and Subtration Intrinsics:
1298        } else if ( "?+?" == varName || "?-?" == varName ) {
1299                assert( expr->result );
1300                assert( 2 == expr->args.size() );
1301
1302                auto baseType1 =
1303                        isPolyPtr( expr->args.front()->result, scopeTypeVars, typeSubs );
1304                auto baseType2 =
1305                        isPolyPtr( expr->args.back()->result, scopeTypeVars, typeSubs );
1306
1307                CodeLocation const & location = expr->location;
1308                CodeLocation const & location1 = expr->args.front()->location;
1309                CodeLocation const & location2 = expr->args.back()->location;
1310                // LHS op RHS -> (LHS op RHS) / sizeof(LHS)
1311                if ( baseType1 && baseType2 ) {
1312                        auto divide = ast::UntypedExpr::createCall( location, "?/?", {
1313                                expr,
1314                                new ast::SizeofExpr( location, deepCopy( baseType1 ) ),
1315                        } );
1316                        if ( expr->env ) divide->env = expr->env;
1317                        return divide;
1318                // LHS op RHS -> LHS op (RHS * sizeof(LHS))
1319                } else if ( baseType1 ) {
1320                        auto multiply = ast::UntypedExpr::createCall( location2, "?*?", {
1321                                expr->args.back(),
1322                                new ast::SizeofExpr( location1, deepCopy( baseType1 ) ),
1323                        } );
1324                        return ast::mutate_field_index(
1325                                expr, &ast::ApplicationExpr::args, 1, multiply );
1326                // LHS op RHS -> (LHS * sizeof(RHS)) op RHS
1327                } else if ( baseType2 ) {
1328                        auto multiply = ast::UntypedExpr::createCall( location1, "?*?", {
1329                                expr->args.front(),
1330                                new ast::SizeofExpr( location2, deepCopy( baseType2 ) ),
1331                        } );
1332                        return ast::mutate_field_index(
1333                                expr, &ast::ApplicationExpr::args, 0, multiply );
1334                }
1335        // Addition and Subtration Relative Assignment Intrinsics:
1336        } else if ( "?+=?" == varName || "?-=?" == varName ) {
1337                assert( expr->result );
1338                assert( 2 == expr->args.size() );
1339
1340                CodeLocation const & location1 = expr->args.front()->location;
1341                CodeLocation const & location2 = expr->args.back()->location;
1342                auto baseType = isPolyPtr( expr->result, scopeTypeVars, typeSubs );
1343                // LHS op RHS -> LHS op (RHS * sizeof(LHS))
1344                if ( baseType ) {
1345                        auto multiply = ast::UntypedExpr::createCall( location2, "?*?", {
1346                                expr->args.back(),
1347                                new ast::SizeofExpr( location1, deepCopy( baseType ) ),
1348                        } );
1349                        return ast::mutate_field_index(
1350                                expr, &ast::ApplicationExpr::args, 1, multiply );
1351                }
1352        }
1353        return expr;
1354}
1355
1356ast::ObjectDecl * CallAdapter::makeTemporary(
1357                CodeLocation const & location, ast::Type const * type ) {
1358        auto newObj = new ast::ObjectDecl( location, tmpNamer.newName(), type );
1359        stmtsToAddBefore.push_back( new ast::DeclStmt( location, newObj ) );
1360        return newObj;
1361}
1362
1363// --------------------------------------------------------------------------
1364/// Modifies declarations to accept implicit parameters.
1365/// * Move polymorphic returns in function types to pointer-type parameters.
1366/// * Adds type size and assertion parameters to parameter lists.
1367struct DeclAdapter final {
1368        ast::FunctionDecl const * previsit( ast::FunctionDecl const * decl );
1369        ast::FunctionDecl const * postvisit( ast::FunctionDecl const * decl );
1370private:
1371        void addAdapters( ast::FunctionDecl * decl, TypeVarMap & localTypeVars );
1372};
1373
1374// size/align/offset parameters may not be used, so add the unused attribute.
1375ast::ObjectDecl * makeObj(
1376                CodeLocation const & location, std::string const & name ) {
1377        return new ast::ObjectDecl( location, name,
1378                makeSizeAlignType(),
1379                nullptr, ast::Storage::Classes(), ast::Linkage::C, nullptr,
1380                { new ast::Attribute( "unused" ) } );
1381}
1382
1383ast::FunctionDecl const * DeclAdapter::previsit( ast::FunctionDecl const * decl ) {
1384        TypeVarMap localTypeVars;
1385        makeTypeVarMap( decl, localTypeVars );
1386
1387        auto mutDecl = mutate( decl );
1388
1389        // Move polymorphic return type to parameter list.
1390        if ( isDynRet( mutDecl->type ) ) {
1391                auto ret = strict_dynamic_cast<ast::ObjectDecl *>(
1392                        mutDecl->returns.front().get_and_mutate() );
1393                ret->set_type( new ast::PointerType( ret->type ) );
1394                mutDecl->params.insert( mutDecl->params.begin(), ret );
1395                mutDecl->returns.erase( mutDecl->returns.begin() );
1396                ret->init = nullptr;
1397        }
1398
1399        // Add size/align and assertions for type parameters to parameter list.
1400        ast::vector<ast::DeclWithType> inferredParams;
1401        ast::vector<ast::DeclWithType> layoutParams;
1402        for ( ast::ptr<ast::TypeDecl> & typeParam : mutDecl->type_params ) {
1403                auto mutParam = mutate( typeParam.get() );
1404                // Add all size and alignment parameters to parameter list.
1405                if ( mutParam->isComplete() ) {
1406                        ast::TypeInstType paramType( mutParam );
1407                        std::string paramName = Mangle::mangleType( &paramType );
1408
1409                        auto sizeParam = makeObj( typeParam->location, sizeofName( paramName ) );
1410                        layoutParams.emplace_back( sizeParam );
1411
1412                        auto alignParam = makeObj( typeParam->location, alignofName( paramName ) );
1413                        layoutParams.emplace_back( alignParam );
1414                }
1415                // Assertions should be stored in the main list.
1416                assert( mutParam->assertions.empty() );
1417                typeParam = mutParam;
1418        }
1419        for ( ast::ptr<ast::DeclWithType> & assert : mutDecl->assertions ) {
1420                // Assertion parameters may not be used in body,
1421                // pass along with unused attribute.
1422                assert.get_and_mutate()->attributes.push_back(
1423                        new ast::Attribute( "unused" ) );
1424                inferredParams.push_back( assert );
1425        }
1426        mutDecl->assertions.clear();
1427
1428        // Prepend each argument group. From last group to first. addAdapters
1429        // does do the same, it just does it itself and see all other parameters.
1430        spliceBegin( mutDecl->params, inferredParams );
1431        spliceBegin( mutDecl->params, layoutParams );
1432        addAdapters( mutDecl, localTypeVars );
1433
1434        // Now have to update the type to match the declaration.
1435        ast::FunctionType * type = new ast::FunctionType(
1436                mutDecl->type->isVarArgs, mutDecl->type->qualifiers );
1437        for ( auto type_param : mutDecl->type_params ) {
1438                type->forall.emplace_back( new ast::TypeInstType( type_param ) );
1439        }
1440        for ( auto param : mutDecl->params ) {
1441                type->params.emplace_back( param->get_type() );
1442        }
1443        for ( auto retval : mutDecl->returns ) {
1444                type->returns.emplace_back( retval->get_type() );
1445        }
1446        mutDecl->type = type;
1447
1448        return mutDecl;
1449}
1450
1451ast::FunctionDecl const * DeclAdapter::postvisit(
1452                ast::FunctionDecl const * decl ) {
1453        ast::FunctionDecl * mutDecl = mutate( decl );
1454        if ( !mutDecl->returns.empty() && mutDecl->stmts
1455                        // Intrinsic functions won't be using the _retval so no need to
1456                        // generate it.
1457                        && mutDecl->linkage != ast::Linkage::Intrinsic
1458                        // Remove check for prefix once thunks properly use ctor/dtors.
1459                        && !isPrefix( mutDecl->name, "_thunk" )
1460                        && !isPrefix( mutDecl->name, "_adapter" ) ) {
1461                assert( 1 == mutDecl->returns.size() );
1462                ast::DeclWithType const * retval = mutDecl->returns.front();
1463                if ( "" == retval->name ) {
1464                        retval = ast::mutate_field(
1465                                retval, &ast::DeclWithType::name, "_retval" );
1466                        mutDecl->returns.front() = retval;
1467                }
1468                auto stmts = mutDecl->stmts.get_and_mutate();
1469                stmts->kids.push_front( new ast::DeclStmt( retval->location, retval ) );
1470                ast::DeclWithType * newRet = ast::deepCopy( retval );
1471                mutDecl->returns.front() = newRet;
1472        }
1473        // Errors should have been caught by this point, remove initializers from
1474        // parameters to allow correct codegen of default arguments.
1475        for ( ast::ptr<ast::DeclWithType> & param : mutDecl->params ) {
1476                if ( auto obj = param.as<ast::ObjectDecl>() ) {
1477                        param = ast::mutate_field( obj, &ast::ObjectDecl::init, nullptr );
1478                }
1479        }
1480        return mutDecl;
1481}
1482
1483void DeclAdapter::addAdapters(
1484                ast::FunctionDecl * mutDecl, TypeVarMap & localTypeVars ) {
1485        ast::vector<ast::FunctionType> functions;
1486        for ( ast::ptr<ast::DeclWithType> & arg : mutDecl->params ) {
1487                ast::Type const * type = arg->get_type();
1488                type = findAndReplaceFunction( type, functions, localTypeVars, needsAdapter );
1489                arg.get_and_mutate()->set_type( type );
1490        }
1491        std::set<std::string> adaptersDone;
1492        for ( ast::ptr<ast::FunctionType> const & func : functions ) {
1493                std::string mangleName = mangleAdapterName( func, localTypeVars );
1494                if ( adaptersDone.find( mangleName ) != adaptersDone.end() ) {
1495                        continue;
1496                }
1497                std::string adapterName = makeAdapterName( mangleName );
1498                // The adapter may not actually be used, so make sure it has unused.
1499                mutDecl->params.insert( mutDecl->params.begin(), new ast::ObjectDecl(
1500                        mutDecl->location, adapterName,
1501                        new ast::PointerType( makeAdapterType( func, localTypeVars ) ),
1502                        nullptr, {}, {}, nullptr,
1503                        { new ast::Attribute( "unused" ) } ) );
1504                adaptersDone.insert( adaptersDone.begin(), mangleName );
1505        }
1506}
1507
1508// --------------------------------------------------------------------------
1509// TODO: Ideally, there would be no floating nodes at all.
1510/// Corrects the floating nodes created in CallAdapter.
1511struct RewireAdapters final : public ast::WithGuards {
1512        ScopedMap<std::string, ast::ObjectDecl const *> adapters;
1513        void beginScope() { adapters.beginScope(); }
1514        void endScope() { adapters.endScope(); }
1515        void previsit( ast::FunctionDecl const * decl );
1516        ast::VariableExpr const * previsit( ast::VariableExpr const * expr );
1517};
1518
1519void RewireAdapters::previsit( ast::FunctionDecl const * decl ) {
1520        GuardScope( adapters );
1521        for ( ast::ptr<ast::DeclWithType> const & param : decl->params ) {
1522                if ( auto objectParam = param.as<ast::ObjectDecl>() ) {
1523                        adapters.insert( objectParam->name, objectParam );
1524                }
1525        }
1526}
1527
1528ast::VariableExpr const * RewireAdapters::previsit(
1529                ast::VariableExpr const * expr ) {
1530        // If the node is not floating, we can skip.
1531        if ( expr->var->isManaged() ) return expr;
1532        auto it = adapters.find( expr->var->name );
1533        assertf( it != adapters.end(), "Could not correct floating node." );
1534        return ast::mutate_field( expr, &ast::VariableExpr::var, it->second );
1535}
1536
1537// --------------------------------------------------------------------------
1538/// Inserts code to access polymorphic layout inforation.
1539/// * Replaces member and size/alignment/offsetof expressions on polymorphic
1540///   generic types with calculated expressions.
1541/// * Replaces member expressions for polymorphic types with calculated
1542///   add-field-offset-and-dereference.
1543/// * Calculates polymorphic offsetof expressions from offset array.
1544/// * Inserts dynamic calculation of polymorphic type layouts where needed.
1545struct PolyGenericCalculator final :
1546                public ast::WithConstTypeSubstitution,
1547                public ast::WithDeclsToAdd<>,
1548                public ast::WithGuards,
1549                public ast::WithStmtsToAdd<>,
1550                public ast::WithVisitorRef<PolyGenericCalculator> {
1551        PolyGenericCalculator();
1552
1553        void previsit( ast::FunctionDecl const * decl );
1554        void previsit( ast::TypedefDecl const * decl );
1555        void previsit( ast::TypeDecl const * decl );
1556        ast::Decl const * postvisit( ast::TypeDecl const * decl );
1557        ast::StructDecl const * previsit( ast::StructDecl const * decl );
1558        ast::UnionDecl const * previsit( ast::UnionDecl const * decl );
1559        ast::DeclStmt const * previsit( ast::DeclStmt const * stmt );
1560        ast::Expr const * postvisit( ast::MemberExpr const * expr );
1561        void previsit( ast::AddressExpr const * expr );
1562        ast::Expr const * postvisit( ast::AddressExpr const * expr );
1563        ast::Expr const * postvisit( ast::SizeofExpr const * expr );
1564        ast::Expr const * postvisit( ast::AlignofExpr const * expr );
1565        ast::Expr const * postvisit( ast::OffsetofExpr const * expr );
1566        ast::Expr const * postvisit( ast::OffsetPackExpr const * expr );
1567
1568        void beginScope();
1569        void endScope();
1570private:
1571        /// Makes a new variable in the current scope with the given name,
1572        /// type and optional initializer.
1573        ast::ObjectDecl * makeVar(
1574                        CodeLocation const & location, std::string const & name,
1575                        ast::Type const * type, ast::Init const * init = nullptr );
1576        /// Returns true if the type has a dynamic layout;
1577        /// such a layout will be stored in appropriately-named local variables
1578        /// when the function returns.
1579        bool findGeneric( CodeLocation const & location, ast::Type const * );
1580        /// Adds type parameters to the layout call; will generate the
1581        /// appropriate parameters if needed.
1582        void addSTypeParamsToLayoutCall(
1583                ast::UntypedExpr * layoutCall,
1584                const ast::vector<ast::Type> & otypeParams );
1585        /// Change the type of generic aggregate members to char[].
1586        void mutateMembers( ast::AggregateDecl * aggr );
1587        /// Returns the calculated sizeof expression for type, or nullptr for use
1588        /// C sizeof().
1589        ast::Expr const * genSizeof( CodeLocation const &, ast::Type const * );
1590        /// Enters a new scope for type-variables,
1591        /// adding the type variables from the provided type.
1592        void beginTypeScope( ast::Type const * );
1593
1594        /// The type variables and polymorphic parameters currently in scope.
1595        TypeVarMap scopeTypeVars;
1596        /// Set of generic type layouts known in the current scope,
1597        /// indexed by sizeofName.
1598        ScopedSet<std::string> knownLayouts;
1599        /// Set of non-generic types for which the offset array exists in the
1600        /// current scope, indexed by offsetofName.
1601        ScopedSet<std::string> knownOffsets;
1602        /// Namer for VLA (variable length array) buffers.
1603        UniqueName bufNamer;
1604        /// If the argument of an AddressExpr is MemberExpr, it is stored here.
1605        ast::MemberExpr const * addrMember = nullptr;
1606};
1607
1608PolyGenericCalculator::PolyGenericCalculator() :
1609        knownLayouts(), knownOffsets(), bufNamer( "_buf" )
1610{}
1611
1612/// Converts polymorphic type into a suitable monomorphic representation.
1613/// Currently: __attribute__((aligned(8) )) char[size_T];
1614ast::Type * polyToMonoType( CodeLocation const & location,
1615                ast::Type const * declType ) {
1616        auto charType = new ast::BasicType( ast::BasicType::Char );
1617        auto size = new ast::NameExpr( location,
1618                sizeofName( Mangle::mangleType( declType ) ) );
1619        auto aligned = new ast::Attribute( "aligned",
1620                { ast::ConstantExpr::from_int( location, 8 ) } );
1621        auto ret = new ast::ArrayType( charType, size,
1622                ast::VariableLen, ast::DynamicDim, ast::CV::Qualifiers() );
1623        ret->attributes.push_back( aligned );
1624        return ret;
1625}
1626
1627void PolyGenericCalculator::previsit( ast::FunctionDecl const * decl ) {
1628        GuardScope( *this );
1629        beginTypeScope( decl->type );
1630}
1631
1632void PolyGenericCalculator::previsit( ast::TypedefDecl const * decl ) {
1633        assertf( false, "All typedef declarations should be removed." );
1634        beginTypeScope( decl->base );
1635}
1636
1637void PolyGenericCalculator::previsit( ast::TypeDecl const * decl ) {
1638        addToTypeVarMap( decl, scopeTypeVars );
1639}
1640
1641ast::Decl const * PolyGenericCalculator::postvisit(
1642                ast::TypeDecl const * decl ) {
1643        ast::Type const * base = decl->base;
1644        if ( nullptr == base ) return decl;
1645
1646        // Add size/align variables for opaque type declarations.
1647        ast::TypeInstType inst( decl->name, decl );
1648        std::string typeName = Mangle::mangleType( &inst );
1649        ast::Type * layoutType = new ast::BasicType(
1650                ast::BasicType::LongUnsignedInt );
1651
1652        ast::ObjectDecl * sizeDecl = new ast::ObjectDecl( decl->location,
1653                sizeofName( typeName ), layoutType,
1654                new ast::SingleInit( decl->location,
1655                        new ast::SizeofExpr( decl->location, deepCopy( base ) )
1656                )
1657        );
1658        ast::ObjectDecl * alignDecl = new ast::ObjectDecl( decl->location,
1659                alignofName( typeName ), layoutType,
1660                new ast::SingleInit( decl->location,
1661                        new ast::AlignofExpr( decl->location, deepCopy( base ) )
1662                )
1663        );
1664
1665        // Ensure that the initializing sizeof/alignof exprs are properly mutated.
1666        sizeDecl->accept( *visitor );
1667        alignDecl->accept( *visitor );
1668
1669        // A little trick to replace this with two declarations.
1670        // Adding after makes sure that there is no conflict with adding stmts.
1671        declsToAddAfter.push_back( alignDecl );
1672        return sizeDecl;
1673}
1674
1675ast::StructDecl const * PolyGenericCalculator::previsit(
1676                ast::StructDecl const * decl ) {
1677        auto mutDecl = mutate( decl );
1678        mutateMembers( mutDecl );
1679        return mutDecl;
1680}
1681
1682ast::UnionDecl const * PolyGenericCalculator::previsit(
1683                ast::UnionDecl const * decl ) {
1684        auto mutDecl = mutate( decl );
1685        mutateMembers( mutDecl );
1686        return mutDecl;
1687}
1688
1689ast::DeclStmt const * PolyGenericCalculator::previsit( ast::DeclStmt const * stmt ) {
1690        ast::ObjectDecl const * decl = stmt->decl.as<ast::ObjectDecl>();
1691        if ( !decl || !findGeneric( decl->location, decl->type ) ) {
1692                return stmt;
1693        }
1694
1695        // Change initialization of a polymorphic value object to allocate via a
1696        // variable-length-array (alloca cannot be safely used in loops).
1697        ast::ObjectDecl * newBuf = new ast::ObjectDecl( decl->location,
1698                bufNamer.newName(),
1699                polyToMonoType( decl->location, decl->type ),
1700                nullptr, {}, ast::Linkage::C
1701        );
1702        stmtsToAddBefore.push_back( new ast::DeclStmt( stmt->location, newBuf ) );
1703
1704        // If the object has a cleanup attribute, the clean-up should be on the
1705        // buffer, not the pointer. [Perhaps this should be lifted?]
1706        auto matchAndMove = [newBuf]( ast::ptr<ast::Attribute> & attr ) {
1707                if ( "cleanup" == attr->name ) {
1708                        newBuf->attributes.push_back( attr );
1709                        return true;
1710                }
1711                return false;
1712        };
1713
1714        auto mutDecl = mutate( decl );
1715
1716        // Forally, side effects are not safe in this function. But it works.
1717        erase_if( mutDecl->attributes, matchAndMove );
1718
1719        mutDecl->init = new ast::SingleInit( decl->location,
1720                new ast::VariableExpr( decl->location, newBuf ) );
1721
1722        return ast::mutate_field( stmt, &ast::DeclStmt::decl, mutDecl );
1723}
1724
1725/// Checks if memberDecl matches the decl from an aggregate.
1726bool isMember( ast::DeclWithType const * memberDecl, ast::Decl const * decl ) {
1727        // No matter the field, if the name is different it is not the same.
1728        if ( memberDecl->name != decl->name ) {
1729                return false;
1730        }
1731
1732        if ( memberDecl->name.empty() ) {
1733                // Plan-9 Field: Match on unique_id.
1734                return ( memberDecl->uniqueId == decl->uniqueId );
1735        }
1736
1737        ast::DeclWithType const * declWithType =
1738                strict_dynamic_cast<ast::DeclWithType const *>( decl );
1739
1740        if ( memberDecl->mangleName.empty() || declWithType->mangleName.empty() ) {
1741                // Tuple-Element Field: Expect neither had mangled name;
1742                // accept match on simple name (like field_2) only.
1743                assert( memberDecl->mangleName.empty() );
1744                assert( declWithType->mangleName.empty() );
1745                return true;
1746        }
1747
1748        // Ordinary Field: Use full name to accommodate overloading.
1749        return ( memberDecl->mangleName == declWithType->mangleName );
1750}
1751
1752/// Finds the member in the base list that matches the given declaration;
1753/// returns its index, or -1 if not present.
1754long findMember( ast::DeclWithType const * memberDecl,
1755                const ast::vector<ast::Decl> & baseDecls ) {
1756        for ( auto pair : enumerate( baseDecls ) ) {
1757                if ( isMember( memberDecl, pair.val.get() ) ) {
1758                        return pair.idx;
1759                }
1760        }
1761        return -1;
1762}
1763
1764/// Returns an index expression into the offset array for a type.
1765ast::Expr * makeOffsetIndex( CodeLocation const & location,
1766                ast::Type const * objectType, long i ) {
1767        std::string name = offsetofName( Mangle::mangleType( objectType ) );
1768        return ast::UntypedExpr::createCall( location, "?[?]", {
1769                new ast::NameExpr( location, name ),
1770                ast::ConstantExpr::from_ulong( location, i ),
1771        } );
1772}
1773
1774ast::Expr const * PolyGenericCalculator::postvisit(
1775                ast::MemberExpr const * expr ) {
1776        // Only mutate member expressions for polymorphic types.
1777        ast::Type const * objectType = hasPolyBase(
1778                expr->aggregate->result, scopeTypeVars
1779        );
1780        if ( !objectType ) return expr;
1781        // Ensure layout for this type is available.
1782        // The boolean result is ignored.
1783        findGeneric( expr->location, objectType );
1784
1785        // Replace member expression with dynamically-computed layout expression.
1786        ast::Expr * newMemberExpr = nullptr;
1787        if ( auto structType = dynamic_cast<ast::StructInstType const *>( objectType ) ) {
1788                long offsetIndex = findMember( expr->member, structType->base->members );
1789                if ( -1 == offsetIndex ) return expr;
1790
1791                // Replace member expression with pointer to struct plus offset.
1792                ast::UntypedExpr * fieldLoc = new ast::UntypedExpr( expr->location,
1793                                new ast::NameExpr( expr->location, "?+?" ) );
1794                ast::Expr * aggr = deepCopy( expr->aggregate );
1795                aggr->env = nullptr;
1796                fieldLoc->args.push_back( aggr );
1797                fieldLoc->args.push_back(
1798                        makeOffsetIndex( expr->location, objectType, offsetIndex ) );
1799                fieldLoc->result = deepCopy( expr->result );
1800                newMemberExpr = fieldLoc;
1801        // Union members are all at offset zero, so just use the aggregate expr.
1802        } else if ( dynamic_cast<ast::UnionInstType const *>( objectType ) ) {
1803                ast::Expr * aggr = deepCopy( expr->aggregate );
1804                aggr->env = nullptr;
1805                aggr->result = deepCopy( expr->result );
1806                newMemberExpr = aggr;
1807        } else {
1808                return expr;
1809        }
1810        assert( newMemberExpr );
1811
1812        // Must apply the generic substitution to the member type to handle cases
1813        // where the member is a generic parameter subsituted by a known concrete
1814        // type. [ex]
1815        //      forall( T ) struct Box { T x; }
1816        //      forall( T ) void f() {
1817        //              Box( T * ) b; b.x;
1818        //      }
1819        // TODO: expr->result should be exactly expr->member->get_type() after
1820        // substitution, so it doesn't seem like it should be necessary to apply
1821        // the substitution manually. For some reason this is not currently the
1822        // case. This requires more investigation.
1823        ast::ptr<ast::Type> memberType = deepCopy( expr->member->get_type() );
1824        ast::TypeSubstitution sub = genericSubstitution( objectType );
1825        sub.apply( memberType );
1826
1827        // Not all members of a polymorphic type are themselves of a polymorphic
1828        // type; in this cas the member expression should be wrapped and
1829        // dereferenced to form an lvalue.
1830        if ( !isPolyType( memberType, scopeTypeVars ) ) {
1831                auto ptrCastExpr = new ast::CastExpr( expr->location, newMemberExpr,
1832                        new ast::PointerType( memberType ) );
1833                auto derefExpr = ast::UntypedExpr::createDeref( expr->location,
1834                        ptrCastExpr );
1835                newMemberExpr = derefExpr;
1836        }
1837
1838        return newMemberExpr;
1839}
1840
1841void PolyGenericCalculator::previsit( ast::AddressExpr const * expr ) {
1842        GuardValue( addrMember ) = expr->arg.as<ast::MemberExpr>();
1843}
1844
1845ast::Expr const * PolyGenericCalculator::postvisit(
1846                ast::AddressExpr const * expr ) {
1847        // arg has to have been a MemberExpr and has been mutated.
1848        if ( nullptr == addrMember || expr->arg == addrMember ) {
1849                return expr;
1850        }
1851        ast::UntypedExpr const * untyped = expr->arg.as<ast::UntypedExpr>();
1852        if ( !untyped || getFunctionName( untyped ) != "?+?" ) {
1853                return expr;
1854        }
1855        // MemberExpr was converted to pointer + offset; and it is not valid C to
1856        // take the address of an addition, so strip away the address-of.
1857        // It also preserves the env value.
1858        return ast::mutate_field( expr->arg.get(), &ast::Expr::env, expr->env );
1859}
1860
1861ast::Expr const * PolyGenericCalculator::postvisit(
1862                ast::SizeofExpr const * expr ) {
1863        ast::Type const * type = expr->type ? expr->type : expr->expr->result;
1864        ast::Expr const * gen = genSizeof( expr->location, type );
1865        return ( gen ) ? gen : expr;
1866}
1867
1868ast::Expr const * PolyGenericCalculator::postvisit(
1869                ast::AlignofExpr const * expr ) {
1870        ast::Type const * type = expr->type ? expr->type : expr->expr->result;
1871        if ( findGeneric( expr->location, type ) ) {
1872                return new ast::NameExpr( expr->location,
1873                        alignofName( Mangle::mangleType( type ) ) );
1874        } else {
1875                return expr;
1876        }
1877}
1878
1879ast::Expr const * PolyGenericCalculator::postvisit(
1880                ast::OffsetofExpr const * expr ) {
1881        ast::Type const * type = expr->type;
1882        if ( !findGeneric( expr->location, type ) ) return expr;
1883
1884        // Structures replace offsetof expression with an index into offset array.
1885        if ( auto structType = dynamic_cast<ast::StructInstType const *>( type ) ) {
1886                long offsetIndex = findMember( expr->member, structType->base->members );
1887                if ( -1 == offsetIndex ) return expr;
1888
1889                return makeOffsetIndex( expr->location, type, offsetIndex );
1890        // All union members are at offset zero.
1891        } else if ( dynamic_cast<ast::UnionInstType const *>( type ) ) {
1892                return ast::ConstantExpr::from_ulong( expr->location, 0 );
1893        } else {
1894                return expr;
1895        }
1896}
1897
1898ast::Expr const * PolyGenericCalculator::postvisit(
1899                ast::OffsetPackExpr const * expr ) {
1900        ast::StructInstType const * type = expr->type;
1901
1902        // Pull offset back from generated type information.
1903        if ( findGeneric( expr->location, type ) ) {
1904                return new ast::NameExpr( expr->location,
1905                        offsetofName( Mangle::mangleType( type ) ) );
1906        }
1907
1908        std::string offsetName = offsetofName( Mangle::mangleType( type ) );
1909        // Use the already generated offsets for this type.
1910        if ( knownOffsets.contains( offsetName ) ) {
1911                return new ast::NameExpr( expr->location, offsetName );
1912        }
1913
1914        knownOffsets.insert( offsetName );
1915
1916        auto baseMembers = type->base->members;
1917        ast::Type const * offsetType = new ast::BasicType(
1918                ast::BasicType::LongUnsignedInt );
1919
1920        // Build initializer list for offset array.
1921        ast::vector<ast::Init> inits;
1922        for ( ast::ptr<ast::Decl> & member : baseMembers ) {
1923                auto memberDecl = member.as<ast::DeclWithType>();
1924                assertf( memberDecl, "Requesting offset of non-DWT member: %s",
1925                        toCString( member ) );
1926                inits.push_back( new ast::SingleInit( expr->location,
1927                        new ast::OffsetofExpr( expr->location,
1928                                deepCopy( type ),
1929                                memberDecl
1930                        )
1931                ) );
1932        }
1933
1934        auto offsetArray = makeVar( expr->location, offsetName,
1935                new ast::ArrayType(
1936                        offsetType,
1937                        ast::ConstantExpr::from_ulong( expr->location, baseMembers.size() ),
1938                        ast::FixedLen,
1939                        ast::DynamicDim
1940                ),
1941                new ast::ListInit( expr->location, std::move( inits ) )
1942        );
1943
1944        return new ast::VariableExpr( expr->location, offsetArray );
1945}
1946
1947void PolyGenericCalculator::beginScope() {
1948        knownLayouts.beginScope();
1949        knownOffsets.beginScope();
1950}
1951
1952void PolyGenericCalculator::endScope() {
1953        knownOffsets.endScope();
1954        knownLayouts.endScope();
1955}
1956
1957ast::ObjectDecl * PolyGenericCalculator::makeVar(
1958                CodeLocation const & location, std::string const & name,
1959                ast::Type const * type, ast::Init const * init ) {
1960        ast::ObjectDecl * ret = new ast::ObjectDecl( location, name, type, init );
1961        stmtsToAddBefore.push_back( new ast::DeclStmt( location, ret ) );
1962        return ret;
1963}
1964
1965/// Returns true if any of the otype parameters have a dynamic layout; and
1966/// puts all otype parameters in the output list.
1967bool findGenericParams(
1968                ast::vector<ast::Type> & out,
1969                ast::vector<ast::TypeDecl> const & baseParams,
1970                ast::vector<ast::Expr> const & typeParams ) {
1971        bool hasDynamicLayout = false;
1972
1973        for ( auto pair : group_iterate( baseParams, typeParams ) ) {
1974                auto baseParam = std::get<0>( pair );
1975                auto typeParam = std::get<1>( pair );
1976                if ( !baseParam->isComplete() ) continue;
1977                ast::TypeExpr const * typeExpr = typeParam.as<ast::TypeExpr>();
1978                assertf( typeExpr, "All type parameters should be type expressions." );
1979
1980                ast::Type const * type = typeExpr->type.get();
1981                out.push_back( type );
1982                if ( isPolyType( type ) ) hasDynamicLayout = true;
1983        }
1984
1985        return hasDynamicLayout;
1986}
1987
1988bool PolyGenericCalculator::findGeneric(
1989                CodeLocation const & location, ast::Type const * type ) {
1990        type = replaceTypeInst( type, typeSubs );
1991
1992        if ( auto inst = dynamic_cast<ast::TypeInstType const *>( type ) ) {
1993                // Assumes that getting put in the scopeTypeVars includes having the
1994                // layout variables set.
1995                if ( scopeTypeVars.contains( *inst ) ) {
1996                        return true;
1997                }
1998        } else if ( auto inst = dynamic_cast<ast::StructInstType const *>( type ) ) {
1999                // Check if this type already has a layout generated for it.
2000                std::string typeName = Mangle::mangleType( type );
2001                if ( knownLayouts.contains( typeName ) ) return true;
2002
2003                // Check if any type parameters have dynamic layout;
2004                // If none do, this type is (or will be) monomorphized.
2005                ast::vector<ast::Type> sizedParams;
2006                if ( !findGenericParams( sizedParams,
2007                                inst->base->params, inst->params ) ) {
2008                        return false;
2009                }
2010
2011                // Insert local variables for layout and generate call to layout
2012                // function.
2013                // Done early so as not to interfere with the later addition of
2014                // parameters to the layout call.
2015                knownLayouts.insert( typeName );
2016                ast::Type const * layoutType = makeSizeAlignType();
2017
2018                int memberCount = inst->base->members.size();
2019                if ( 0 == memberCount ) {
2020                        // All empty structures have the same layout (size 1, align 1).
2021                        makeVar( location,
2022                                sizeofName( typeName ), layoutType,
2023                                new ast::SingleInit( location,
2024                                                ast::ConstantExpr::from_ulong( location, 1 ) ) );
2025                        makeVar( location,
2026                                alignofName( typeName ), ast::deepCopy( layoutType ),
2027                                new ast::SingleInit( location,
2028                                                ast::ConstantExpr::from_ulong( location, 1 ) ) );
2029                        // Since 0-length arrays are forbidden in C, skip the offset array.
2030                } else {
2031                        ast::ObjectDecl const * sizeofVar = makeVar( location,
2032                                sizeofName( typeName ), deepCopy( layoutType ), nullptr );
2033                        ast::ObjectDecl const * alignofVar = makeVar( location,
2034                                alignofName( typeName ), deepCopy( layoutType ), nullptr );
2035                        ast::ObjectDecl const * offsetofVar = makeVar( location,
2036                                offsetofName( typeName ),
2037                                new ast::ArrayType(
2038                                        layoutType,
2039                                        ast::ConstantExpr::from_int( location, memberCount ),
2040                                        ast::FixedLen,
2041                                        ast::DynamicDim
2042                                ),
2043                                nullptr
2044                        );
2045
2046                        // Generate call to layout function.
2047                        ast::UntypedExpr * layoutCall = new ast::UntypedExpr( location,
2048                                new ast::NameExpr( location, layoutofName( inst->base ) ),
2049                                {
2050                                        new ast::AddressExpr(
2051                                                new ast::VariableExpr( location, sizeofVar ) ),
2052                                        new ast::AddressExpr(
2053                                                new ast::VariableExpr( location, alignofVar ) ),
2054                                        new ast::VariableExpr( location, offsetofVar ),
2055                                } );
2056
2057                        addSTypeParamsToLayoutCall( layoutCall, sizedParams );
2058
2059                        stmtsToAddBefore.emplace_back(
2060                                new ast::ExprStmt( location, layoutCall ) );
2061                }
2062
2063                return true;
2064        } else if ( auto inst = dynamic_cast<ast::UnionInstType const *>( type ) ) {
2065                // Check if this type already has a layout generated for it.
2066                std::string typeName = Mangle::mangleType( type );
2067                if ( knownLayouts.contains( typeName ) ) return true;
2068
2069                // Check if any type parameters have dynamic layout;
2070                // If none do, this type is (or will be) monomorphized.
2071                ast::vector<ast::Type> sizedParams;
2072                if ( !findGenericParams( sizedParams,
2073                                inst->base->params, inst->params ) ) {
2074                        return false;
2075                }
2076
2077                // Insert local variables for layout and generate call to layout
2078                // function.
2079                // Done early so as not to interfere with the later addition of
2080                // parameters to the layout call.
2081                knownLayouts.insert( typeName );
2082                ast::Type const * layoutType = makeSizeAlignType();
2083
2084                ast::ObjectDecl * sizeofVar = makeVar( location,
2085                        sizeofName( typeName ), layoutType );
2086                ast::ObjectDecl * alignofVar = makeVar( location,
2087                        alignofName( typeName ), ast::deepCopy( layoutType ) );
2088
2089                ast::UntypedExpr * layoutCall = new ast::UntypedExpr( location,
2090                        new ast::NameExpr( location, layoutofName( inst->base ) ),
2091                        {
2092                                new ast::AddressExpr(
2093                                        new ast::VariableExpr( location, sizeofVar ) ),
2094                                new ast::AddressExpr(
2095                                        new ast::VariableExpr( location, alignofVar ) ),
2096                        } );
2097
2098                addSTypeParamsToLayoutCall( layoutCall, sizedParams );
2099
2100                stmtsToAddBefore.emplace_back(
2101                        new ast::ExprStmt( location, layoutCall ) );
2102
2103                return true;
2104        }
2105        return false;
2106}
2107
2108void PolyGenericCalculator::addSTypeParamsToLayoutCall(
2109                ast::UntypedExpr * layoutCall,
2110                const ast::vector<ast::Type> & otypeParams ) {
2111        CodeLocation const & location = layoutCall->location;
2112        ast::vector<ast::Expr> & args = layoutCall->args;
2113        for ( ast::ptr<ast::Type> const & param : otypeParams ) {
2114                if ( findGeneric( location, param ) ) {
2115                        // Push size/align vars for a generic parameter back.
2116                        std::string paramName = Mangle::mangleType( param );
2117                        args.emplace_back(
2118                                new ast::NameExpr( location, sizeofName( paramName ) ) );
2119                        args.emplace_back(
2120                                new ast::NameExpr( location, alignofName( paramName ) ) );
2121                } else {
2122                        args.emplace_back(
2123                                new ast::SizeofExpr( location, ast::deepCopy( param ) ) );
2124                        args.emplace_back(
2125                                new ast::AlignofExpr( location, ast::deepCopy( param ) ) );
2126                }
2127        }
2128}
2129
2130void PolyGenericCalculator::mutateMembers( ast::AggregateDecl * aggr ) {
2131        std::set<std::string> genericParams;
2132        for ( ast::ptr<ast::TypeDecl> const & decl : aggr->params ) {
2133                genericParams.insert( decl->name );
2134        }
2135        for ( ast::ptr<ast::Decl> & decl : aggr->members ) {
2136                auto field = decl.as<ast::ObjectDecl>();
2137                if ( nullptr == field ) continue;
2138
2139                ast::Type const * type = replaceTypeInst( field->type, typeSubs );
2140                auto typeInst = dynamic_cast<ast::TypeInstType const *>( type );
2141                if ( nullptr == typeInst ) continue;
2142
2143                // Do not try to monoporphize generic parameters.
2144                if ( scopeTypeVars.contains( ast::TypeEnvKey( *typeInst ) ) &&
2145                                !genericParams.count( typeInst->name ) ) {
2146                        // Polymorphic aggregate members should be converted into
2147                        // monomorphic members. Using char[size_T] here respects
2148                        // the expected sizing rules of an aggregate type.
2149                        decl = ast::mutate_field( field, &ast::ObjectDecl::type,
2150                                polyToMonoType( field->location, field->type ) );
2151                }
2152        }
2153}
2154
2155ast::Expr const * PolyGenericCalculator::genSizeof(
2156                CodeLocation const & location, ast::Type const * type ) {
2157        if ( auto * array = dynamic_cast<ast::ArrayType const *>( type ) ) {
2158                // Generate calculated size for possibly generic array.
2159                ast::Expr const * sizeofBase = genSizeof( location, array->base );
2160                if ( nullptr == sizeofBase ) return nullptr;
2161                ast::Expr const * dim = array->dimension;
2162                return makeOp( location, "?*?", sizeofBase, dim );
2163        } else if ( findGeneric( location, type ) ) {
2164                // Generate calculated size for generic type.
2165                return new ast::NameExpr( location, sizeofName(
2166                                Mangle::mangleType( type ) ) );
2167        } else {
2168                return nullptr;
2169        }
2170}
2171
2172void PolyGenericCalculator::beginTypeScope( ast::Type const * type ) {
2173        GuardScope( scopeTypeVars );
2174        makeTypeVarMap( type, scopeTypeVars );
2175}
2176
2177// --------------------------------------------------------------------------
2178/// Removes unneeded or incorrect type information.
2179/// * Replaces initialization of polymorphic values with alloca.
2180/// * Replaces declaration of dtype/ftype with appropriate void expression.
2181/// * Replaces sizeof expressions of polymorphic types with a variable.
2182/// * Strips fields from generic structure declarations.
2183struct Eraser final :
2184                public ast::WithGuards {
2185        void guardTypeVarMap( ast::Type const * type ) {
2186                GuardScope( scopeTypeVars );
2187                makeTypeVarMap( type, scopeTypeVars );
2188        }
2189
2190        ast::ObjectDecl const * previsit( ast::ObjectDecl const * decl );
2191        ast::FunctionDecl const * previsit( ast::FunctionDecl const * decl );
2192        ast::TypedefDecl const * previsit( ast::TypedefDecl const * decl );
2193        ast::StructDecl const * previsit( ast::StructDecl const * decl );
2194        ast::UnionDecl const * previsit( ast::UnionDecl const * decl );
2195        void previsit( ast::TypeDecl const * decl );
2196        void previsit( ast::PointerType const * type );
2197        void previsit( ast::FunctionType const * type );
2198public:
2199        TypeVarMap scopeTypeVars;
2200};
2201
2202ast::ObjectDecl const * Eraser::previsit( ast::ObjectDecl const * decl ) {
2203        guardTypeVarMap( decl->type );
2204        return scrubAllTypeVars( decl );
2205}
2206
2207ast::FunctionDecl const * Eraser::previsit( ast::FunctionDecl const * decl ) {
2208        guardTypeVarMap( decl->type );
2209        return scrubAllTypeVars( decl );
2210}
2211
2212ast::TypedefDecl const * Eraser::previsit( ast::TypedefDecl const * decl ) {
2213        guardTypeVarMap( decl->base );
2214        return scrubAllTypeVars( decl );
2215}
2216
2217/// Strips the members from a generic aggregate.
2218template<typename node_t>
2219node_t const * stripGenericMembers( node_t const * decl ) {
2220        if ( decl->params.empty() ) return decl;
2221        auto mutDecl = ast::mutate( decl );
2222        mutDecl->members.clear();
2223        return mutDecl;
2224}
2225
2226ast::StructDecl const * Eraser::previsit( ast::StructDecl const * decl ) {
2227        return stripGenericMembers( decl );
2228}
2229
2230ast::UnionDecl const * Eraser::previsit( ast::UnionDecl const * decl ) {
2231        return stripGenericMembers( decl );
2232}
2233
2234void Eraser::previsit( ast::TypeDecl const * decl ) {
2235        addToTypeVarMap( decl, scopeTypeVars );
2236}
2237
2238void Eraser::previsit( ast::PointerType const * type ) {
2239        guardTypeVarMap( type );
2240}
2241
2242void Eraser::previsit( ast::FunctionType const * type ) {
2243        guardTypeVarMap( type );
2244}
2245
2246} // namespace
2247
2248// --------------------------------------------------------------------------
2249void box( ast::TranslationUnit & translationUnit ) {
2250        ast::Pass<LayoutFunctionBuilder>::run( translationUnit );
2251        ast::Pass<CallAdapter>::run( translationUnit );
2252        ast::Pass<DeclAdapter>::run( translationUnit );
2253        ast::Pass<RewireAdapters>::run( translationUnit );
2254        ast::Pass<PolyGenericCalculator>::run( translationUnit );
2255        ast::Pass<Eraser>::run( translationUnit );
2256}
2257
2258} // namespace GenPoly
2259
2260// Local Variables: //
2261// tab-width: 4 //
2262// mode: c++ //
2263// compile-command: "make install" //
2264// End: //
Note: See TracBrowser for help on using the repository browser.