source: src/GenPoly/Box.cpp @ d63746f

Last change on this file since d63746f was be4335b, checked in by Andrew Beach <ajbeach@…>, 8 months ago

The remaining improvements I had planned for the Box pass are either very hard or (on reflection) of questionable value, and none are required. Cleans up some loose threads before I may move on.

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