source: src/GenPoly/Box.cpp @ 07293ad

Last change on this file since 07293ad was 53f4b55, checked in by Andrew Beach <ajbeach@…>, 2 months ago

Remove the untyped constructor for (typed) OffsetofExpr?. The one time it was used may not need to create a typed expression but we have all the information to do so.

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