source: src/GenPoly/BoxNew.cpp @ 3c4003b9

Last change on this file since 3c4003b9 was 3c4003b9, checked in by Andrew Beach <ajbeach@…>, 7 months ago

Box pass Eraser now removes the polymorphic arguments now that the functions are no longer actually polymorphic.

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