source: src/GenPoly/InstantiateGenericNew.cpp @ b2ddaf3

ADTast-experimental
Last change on this file since b2ddaf3 was e01eb4a, checked in by Andrew Beach <ajbeach@…>, 20 months ago

Moved some functions from InitTweak? to Inspect.

  • Property mode set to 100644
File size: 23.8 KB
Line 
1//
2// Cforall Version 1.0.0 Copyright (C) 2016 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// InstantiateGenericNew.cpp --
8//
9// Author           : Andrew Beach
10// Created On       : Tue Aug 16 10:51:00 2022
11// Last Modified By : Andrew Beach
12// Last Modified On : Tue Sep 13 16:03:00 2022
13// Update Count     : 0
14//
15
16#include "InstantiateGeneric.h"
17
18#include <cassert>                     // for assertf, assert
19#include <set>                         // for set
20#include <utility>                     // for move, pair
21#include <vector>                      // for vector
22
23#include "AST/Copy.hpp"                // for deepCopy
24#include "AST/Create.hpp"              // for asForward
25#include "AST/Inspect.hpp"             // for getFunction
26#include "AST/Pass.hpp"                // for Pass, WithGuard, WithShortCi...
27#include "AST/TranslationUnit.hpp"     // for TranslationUnit
28#include "CodeGen/OperatorTable.h"     // for isAssignment
29#include "Common/ScopedMap.h"          // for ScopedMap
30#include "Common/UniqueName.h"         // for UniqueName
31#include "GenPoly/GenPoly.h"           // for isPolyType, typesPolyCompatible
32#include "GenPoly/ScrubTyVars.h"       // for scrubAll
33#include "ResolvExpr/typeops.h"        // for typesCompatible
34
35namespace GenPoly {
36
37namespace {
38
39// Utilities:
40
41using type_vector = std::vector< ast::ptr< ast::TypeExpr > >;
42
43/// Abstracts type equality for a list of parameter types.
44struct TypeList {
45        TypeList() : params() {}
46        TypeList( std::vector< ast::ptr< ast::Type > > const & params ) :
47                params( params ) {}
48        TypeList( std::vector< ast::ptr< ast::Type > > && params ) :
49                params( std::move( params ) ) {}
50        TypeList( TypeList const & that ) : params( that.params ) {}
51        TypeList( TypeList && that ) : params( std::move( that.params ) ) {}
52
53        TypeList( std::vector< ast::ptr< ast::TypeExpr > > const & exprs ) :
54                        params() {
55                for ( auto expr : exprs ) {
56                        params.emplace_back( ast::deepCopy( expr->type ) );
57                }
58        }
59
60        TypeList & operator=( TypeList const & that ) {
61                params = that.params;
62                return *this;
63        }
64
65        TypeList & operator=( TypeList && that ) {
66                params = std::move( that.params );
67                return *this;
68        }
69
70        bool operator==( TypeList const & that ) const {
71                if ( params.size() != that.params.size() ) {
72                        return false;
73                }
74
75                for ( auto it = params.begin(), jt = that.params.begin() ;
76                                it != params.end() ; ++it, ++jt ) {
77                        if ( !typesPolyCompatible( it->get(), jt->get() ) ) {
78                                return false;
79                        }
80                }
81                return true;
82        }
83
84        std::vector<ast::ptr<ast::Type>> params;
85};
86
87/// Maps a key and a TypeList to a valuue. Also supports scoping.
88class InstantiationMap final {
89        /// Wraps value for a specific (AggregateDecl, TypeList) combination.
90        using Instantiation = std::pair<TypeList, ast::ptr<ast::AggregateDecl>>;
91        /// List of TypeLists paired with the appropriate values.
92        using ValueList = std::vector<Instantiation>;
93        /// Underlying map type; maps keys to a linear list of corresponding
94        /// TypeLists and values.
95        using InnerMap = ScopedMap<ast::ptr<ast::AggregateDecl>, ValueList>;
96
97        InnerMap data;
98public:
99        void beginScope() { data.beginScope(); }
100        void endScope() { data.endScope(); }
101
102        /// Gets the value for the (declaration, type list) pair,
103        /// returns null if no such value exists.
104        ast::AggregateDecl const * lookup(
105                        ast::AggregateDecl const * key, type_vector const & params ) const {
106                // This type repackaging is used for the helpers.
107                ast::ptr<ast::AggregateDecl> ptr = key;
108                TypeList typeList( params );
109
110                // Scan scopes for matches to the key.
111                for ( auto insts = data.find( key ) ;
112                                insts != data.end() ; insts = data.findNext( insts, ptr )) {
113                        for ( auto inst = insts->second.rbegin() ;
114                                        inst != insts->second.rend() ; ++inst ) {
115                                if ( inst->first == typeList ) {
116                                        return inst->second;
117                                }
118                        }
119                }
120                return nullptr;
121        }
122
123        /// Adds a value for a (key, type list) pair to the current scope.
124        void insert( ast::AggregateDecl const * key, type_vector const & params,
125                        ast::AggregateDecl const * value ) {
126                auto it = data.findAt( data.currentScope(), key );
127                if ( it == data.end() ) {
128                        data.insert( key, ValueList( 1,
129                                Instantiation( TypeList( params ), value ) ) );
130                } else {
131                        it->second.emplace_back(
132                                Instantiation( TypeList( params ), value ) );
133                }
134        }
135};
136
137/// Possible options for a given specialization of a generic type.
138enum class GenericType {
139        /// Concrete instatiation based solely on {d,f}type-to-void conversions.
140        dtypeStatic,
141        /// Concrete instatiation requiring at least one parameters type.
142        concrete,
143        /// No concrete instantiation.
144        dynamic
145};
146
147GenericType & operator|=( GenericType & gt, const GenericType & ht ) {
148        if ( gt < ht ) gt = ht;
149        return gt;
150}
151
152bool isDtypeStatic( std::vector<ast::ptr<ast::TypeDecl>> const & baseParams ) {
153        return std::all_of( baseParams.begin(), baseParams.end(),
154                []( ast::TypeDecl const * td ){ return !td->isComplete(); }
155        );
156}
157
158/// Makes substitutions of params into baseParams; returns dtypeStatic if
159/// there is a concrete instantiation based only on {d,f}type-to-void
160/// conversions, concrete if there is a concrete instantiation requiring at
161/// least one parameter type, and dynamic if there is no concrete instantiation.
162GenericType makeSubstitutions(
163                std::vector<ast::ptr<ast::TypeExpr>> & out,
164                std::vector<ast::ptr<ast::TypeDecl>> const & baseParams,
165                std::vector<ast::ptr<ast::Expr>> const & params ) {
166        GenericType gt = GenericType::dtypeStatic;
167
168        // Substitute concrete types for given parameters,
169        // using incomplete types for placeholders.
170        auto baseParam = baseParams.begin();
171        auto param = params.begin();
172        for ( ; baseParam != baseParams.end() && param != params.end() ;
173                        ++baseParam, ++param ) {
174                ast::TypeExpr const * paramExpr = param->as<ast::TypeExpr>();
175                assertf( paramExpr, "Aggregate parameters should be type expressions." );
176
177                if ( (*baseParam)->isComplete() ) {
178                        // Substitute parameter for complete (otype or sized dtype) type.
179                        if ( isPolyType( paramExpr->type ) ) {
180                                // Substitute polymorphic parameter type in to generic type.
181                                out.push_back( ast::deepCopy( paramExpr ) );
182                                gt = GenericType::dynamic;
183                        } else {
184                                // Normalize possibly dtype-static parameter type.
185                                out.emplace_back( new ast::TypeExpr( paramExpr->location,
186                                        scrubAllTypeVars( ast::deepCopy( paramExpr->type ) ) ) );
187                                gt |= GenericType::concrete;
188                        }
189                } else switch ( (*baseParam)->kind ) {
190                case ast::TypeDecl::Dtype:
191                        // Here, pretend that any incomplete dtype is `void`.
192                        out.emplace_back( new ast::TypeExpr( paramExpr->location,
193                                new ast::VoidType() ) );
194                        break;
195                case ast::TypeDecl::Ftype:
196                        // Here, pretend that any ftype is `void (*)(void)`.
197                        out.emplace_back( new ast::TypeExpr( paramExpr->location,
198                                new ast::FunctionType() ) );
199                        break;
200                case ast::TypeDecl::Ttype:
201                        assertf( false, "Ttype parameters are not currently allowed as parameters to generic types." );
202                        break;
203                default:
204                        assertf( false, "Unhandled type parameter kind" );
205                        break;
206                }
207        }
208
209        assertf( baseParam == baseParams.end(), "Base Parameters not exausted." );
210        assertf( param == params.end(), "Type parameters not exausted." );
211        return gt;
212}
213
214/// Substitutes types of members according to baseParams => typeSubs,
215/// returning the result in a new vector.
216std::vector<ast::ptr<ast::Decl>> substituteMembers(
217                std::vector<ast::ptr<ast::Decl>> const & members,
218                std::vector<ast::ptr<ast::TypeDecl>> const & baseParams,
219                std::vector<ast::ptr<ast::TypeExpr>> const & typeSubs ) {
220        std::vector<ast::ptr<ast::Decl>> out;
221        ast::TypeSubstitution subs( baseParams, typeSubs );
222        for ( ast::ptr<ast::Decl> const & member : members ) {
223                // Create a manual copy to avoid in-place mutation.
224                // If being a PureVisitor is decided to be part of apply's interface,
225                // then we can actually skip this step as it will never mutate in-
226                // place. (Then we don't need the extra guard to free temp value.)
227                ast::ptr<ast::Decl> copy = ast::deepCopy( member.get() );
228                auto result = subs.apply( copy.get() );
229                out.emplace_back( result.node );
230        }
231        return out;
232}
233
234/// Substitutes types of members according to baseParams => typeSubs,
235/// modifying them in-place.
236void substituteMembersHere(
237                std::vector<ast::ptr<ast::Decl>> & members,
238                std::vector<ast::ptr<ast::TypeDecl>> const & baseParams,
239                std::vector<ast::ptr<ast::TypeExpr>> const & typeSubs ) {
240        ast::TypeSubstitution subs( baseParams, typeSubs );
241        for ( ast::ptr<ast::Decl> & member : members ) {
242                // The member must be mutated in place to avoid breaking
243                assert( member->unique() );
244
245                auto field = member.strict_as<ast::ObjectDecl>();
246                auto result = subs.apply( field->type.get() );
247                auto copy = ast::mutate_field(
248                        field, &ast::ObjectDecl::type, result.node );
249
250                // I'm not kidding, it is very important.
251                assert( copy == member.get() );
252        }
253}
254
255/// Strips the instances' type parameters.
256void stripInstParams( ast::BaseInstType * inst ) {
257        inst->params.clear();
258}
259
260bool isGenericType( ast::Type const * type ) {
261        if ( auto inst = dynamic_cast<ast::StructInstType const *>( type ) ) {
262                return !inst->params.empty();
263        } else if ( auto inst = dynamic_cast<ast::UnionInstType const *>( type ) ) {
264                return !inst->params.empty();
265        } else {
266                return false;
267        }
268}
269
270// The Passes:
271
272struct FixDtypeStatic final :
273                public ast::WithGuards,
274                public ast::WithVisitorRef<FixDtypeStatic>,
275                public ast::WithShortCircuiting,
276                public ast::WithStmtsToAdd<> {
277        ast::ApplicationExpr const * previsit( ast::ApplicationExpr const * expr );
278        void previsit( ast::AddressExpr const * expr );
279
280        ast::Expr const * postvisit( ast::MemberExpr const * expr );
281private:
282        template<typename Aggr>
283        ast::Expr const * fixMemberExpr(
284                Aggr const * inst, ast::MemberExpr const * memberExpr );
285
286        ast::Expr const * fixMemberExpr(
287                std::vector<ast::ptr<ast::TypeDecl>> const & baseParams,
288                ast::MemberExpr const * memberExpr );
289
290        bool isLValueArg = false;
291};
292
293ast::ApplicationExpr const * FixDtypeStatic::previsit(
294                ast::ApplicationExpr const * expr ) {
295        GuardValue( isLValueArg ) = false;
296        ast::Decl const * function = ast::getFunction( expr );
297        if ( ast::Linkage::Intrinsic != function->linkage
298                        || !CodeGen::isAssignment( function->name ) ) {
299                return expr;
300        }
301
302        // Explicity visit children because only the first element must be a
303        // C lvalue (normally, it can only send info to both or neither).
304        visit_children = false;
305        expr = mutate_field( expr, &ast::ApplicationExpr::env,
306                maybe_accept( expr->env.get(), *visitor ) );
307        expr = mutate_field( expr, &ast::ApplicationExpr::result,
308                maybe_accept( expr->result.get(), *visitor ) );
309        expr = mutate_field( expr, &ast::ApplicationExpr::func,
310                maybe_accept( expr->func.get(), *visitor ) );
311        isLValueArg = true;
312        for ( unsigned i = 0; i < expr->args.size(); ++i ) {
313                ast::Expr const * newExpr = expr->args[i]->accept( *visitor );
314                // This is declared here for lifetime reasons.
315                ast::ptr<ast::CastExpr> cast;
316                if ( newExpr != expr->args[i].get() &&
317                                (cast = dynamic_cast<ast::CastExpr const *>( newExpr )) ) {
318                        newExpr = cast->arg.get();
319                }
320                expr = mutate_field_index( expr, &ast::ApplicationExpr::args,
321                        i, newExpr );
322                isLValueArg = false;
323        }
324        return expr;
325}
326
327void FixDtypeStatic::previsit( ast::AddressExpr const * ) {
328        // The argument of an address expression (`&`) must be a C lvalue.
329        GuardValue( isLValueArg ) = true;
330}
331
332ast::Expr const * FixDtypeStatic::postvisit( ast::MemberExpr const * expr ) {
333        ast::ptr<ast::Type> const & type = expr->aggregate->result;
334        if ( !isGenericType( type ) ) {
335                return expr;
336        } else if ( auto inst = type.as<ast::StructInstType>() ) {
337                return fixMemberExpr( inst, expr );
338        } else if ( auto inst = type.as<ast::UnionInstType>() ) {
339                return fixMemberExpr( inst, expr );
340        }
341        return expr;
342}
343
344template<typename Aggr>
345ast::Expr const * FixDtypeStatic::fixMemberExpr(
346                Aggr const * inst, ast::MemberExpr const * memberExpr ) {
347        return fixMemberExpr( inst->base->params, memberExpr );
348}
349
350ast::Expr const * FixDtypeStatic::fixMemberExpr(
351                std::vector<ast::ptr<ast::TypeDecl>> const & baseParams,
352                ast::MemberExpr const * memberExpr ) {
353        // Need to cast dtype-static member expressions to their actual type
354        // before the actual type type is erased.
355        // NOTE: The casts here have the third argument (isGenerated) set to
356        // ExplicitCast so that they casts persist until Box, where they are needed.
357
358        if ( !isDtypeStatic( baseParams ) ||
359                        ResolvExpr::typesCompatible(
360                                memberExpr->result,
361                                memberExpr->member->get_type(), ast::SymbolTable() ) ) {
362                return memberExpr;
363        }
364
365        // Type of member and type of expression differ.
366        ast::Type const * concType = ast::deepCopy( memberExpr->result );
367        CodeLocation const & location = memberExpr->location;
368        if ( isLValueArg ) {
369                // The result must be a C lvalue expression. So make a new reference
370                // variable with the correct actual type to replace the
371                // member expression.
372                //   forall(T &)
373                //   struct Ptr {
374                //     T * x;
375                //   };
376                //   Ptr(int) p;
377                //   int i;
378                //   p.x = &i;
379                // becomes
380                //   int *& _dtype_static_member_0 = (int **)&p.x;
381                //   _dtype_static_member_0 = &i;
382                static UniqueName tmpNamer( "_dtype_static_member_" );
383                ast::Expr * init = new ast::CastExpr( location,
384                        new ast::AddressExpr( location, memberExpr ),
385                        new ast::PointerType( ast::deepCopy( concType ) ),
386                        ast::ExplicitCast
387                );
388                ast::ObjectDecl * tmp = new ast::ObjectDecl( location,
389                        tmpNamer.newName(),
390                        new ast::ReferenceType( concType ),
391                        new ast::SingleInit( location, init ),
392                        ast::Storage::Classes(),
393                        ast::Linkage::C
394                );
395                stmtsToAddBefore.push_back( new ast::DeclStmt( location, tmp ) );
396                return new ast::VariableExpr( location, tmp );
397        } else {
398                // Here, it can simply add a cast to actual types.
399                return new ast::CastExpr( location,
400                        memberExpr,
401                        concType,
402                        ast::ExplicitCast
403                );
404        }
405}
406
407struct GenericInstantiator final :
408                public ast::WithCodeLocation,
409                public ast::WithConstTypeSubstitution,
410                public ast::WithDeclsToAdd<>,
411                public ast::WithGuards,
412                public ast::WithVisitorRef<GenericInstantiator>
413{
414        /// Map of (generic type, parameter list) pairs
415        /// to concrete type instantiations.
416        InstantiationMap instantiations;
417        /// Set of types which are dtype-only generic
418        /// (and therefore have static layout).
419        std::set<ast::AggregateDecl const *> dtypeStatics;
420        /// Namer for concrete types.
421        UniqueName typeNamer;
422        /// Should not make use of type environment to replace types of function
423        /// parameter and return values.
424        bool inFunctionType = false;
425        /// Index of current member, used to recreate MemberExprs with the
426        /// member from an instantiation.
427        int memberIndex = -1;
428
429        GenericInstantiator() :
430                instantiations(), dtypeStatics(), typeNamer("_conc_") {}
431
432        ast::Type const * postvisit( ast::StructInstType const * inst );
433        ast::Type const * postvisit( ast::UnionInstType const * inst );
434
435        void previsit( ast::MemberExpr const * expr );
436        ast::Expr const * postvisit( ast::MemberExpr const * expr );
437        ast::Expr const * postvisit( ast::Expr const * expr );
438        void previsit( ast::ParseNode const * node );
439
440        void previsit( ast::FunctionType const * ) {
441                GuardValue( inFunctionType ) = true;
442        }
443        void beginScope() {
444                instantiations.beginScope();
445        }
446        void endScope() {
447                instantiations.endScope();
448        }
449private:
450        /// Wrap instantiation lookup for structures.
451        ast::StructDecl const * lookup(
452                ast::StructInstType const * inst, type_vector const & typeSubs ) const;
453        /// Wrap instantiation lookup for unions.
454        ast::UnionDecl const * lookup(
455                ast::UnionInstType const * inst, type_vector const & typeSubs ) const;
456        /// Wrap instantiation insertion for structures.
457        void insert( ast::StructInstType const * inst,
458                type_vector const & typeSubs, ast::StructDecl const * decl );
459        /// Wrap instantiation insertion for unions.
460        void insert( ast::UnionInstType const * inst,
461                type_vector const & typeSubs, ast::UnionDecl const * decl );
462
463        void replaceParametersWithConcrete( std::vector<ast::ptr<ast::Expr>> & params );
464        ast::Type const * replaceWithConcrete( ast::Type const * type, bool doClone );
465
466        template<typename AggrDecl>
467        ast::Type const * fixInstType( ast::SueInstType<AggrDecl> const * inst );
468
469        /// Strips a dtype-static aggregate decl of its type parameters,
470        /// marks it as stripped.
471        void stripDtypeParams( ast::AggregateDecl * base,
472                std::vector<ast::ptr<ast::TypeDecl>> & baseParams,
473                std::vector<ast::ptr<ast::TypeExpr>> const & typeSubs );
474};
475
476// I think this and the UnionInstType can be made into a template function.
477ast::Type const * GenericInstantiator::postvisit(
478                ast::StructInstType const * inst ) {
479        return fixInstType( inst );
480}
481
482ast::Type const * GenericInstantiator::postvisit(
483                ast::UnionInstType const * inst ) {
484        return fixInstType( inst );
485}
486
487template<typename AggrDecl>
488ast::Type const * GenericInstantiator::fixInstType(
489                ast::SueInstType<AggrDecl> const * inst ) {
490        assert( location );
491
492        // There is nothing to mutate if the params are empty.
493        if ( inst->params.empty() ) return inst;
494
495        // Need to replace type variables to ensure that generic types are
496        // instantiated for the return values of polymorphic functions (in
497        // particular, for thunks, because they are not [currently] copy
498        // constructed).
499        // (This used to be run only on structures, but I believe both need it.)
500        inst = strict_dynamic_cast<ast::SueInstType<AggrDecl> const *>(
501                replaceWithConcrete( inst, false ) );
502
503        // Check for an already-instantiatiated dtype-static type.
504        if ( dtypeStatics.find( inst->base ) != dtypeStatics.end() ) {
505                auto mutInst = ast::mutate( inst );
506                stripInstParams( mutInst );
507                return mutInst;
508        }
509
510        // Check if the type can be concretely instantiated;
511        // and put substitutions in typeSubs.
512        assertf( inst->base, "Base data-type has parameters." );
513        std::vector<ast::ptr<ast::TypeExpr>> typeSubs;
514        GenericType gt = makeSubstitutions( typeSubs, inst->base->params, inst->params );
515        switch ( gt ) {
516        case GenericType::dtypeStatic:
517        {
518                auto mutInst = ast::mutate( inst );
519                assert( mutInst->base->unique() );
520                auto mutBase = mutInst->base.get_and_mutate();
521                stripDtypeParams( mutBase, mutBase->params, typeSubs );
522                stripInstParams( mutInst );
523                return mutInst;
524        }
525        case GenericType::concrete:
526        {
527                // Make concrete instantiation of generic type.
528                AggrDecl const * concDecl = lookup( inst, typeSubs );
529                if ( !concDecl ) {
530                        // Set concDecl to new type, insert type declaration
531                        // into statements to add.
532                        AggrDecl * newDecl = new AggrDecl( *location,
533                                typeNamer.newName( inst->name )
534                        );
535                        newDecl->body = inst->base->body;
536                        newDecl->members = substituteMembers(
537                                inst->base->members,
538                                inst->base->params,
539                                typeSubs
540                        );
541
542                        // Forward declare before recursion. (TODO: Only when needed, #199.)
543                        insert( inst, typeSubs, newDecl );
544                        if ( AggrDecl const * forwardDecl = ast::asForward( newDecl ) ) {
545                                declsToAddBefore.push_back( forwardDecl );
546                        }
547                        // Recursively instantiate members:
548                        concDecl = strict_dynamic_cast<AggrDecl const *>(
549                                newDecl->accept( *visitor ) );
550                        // Must occur before declaration is added so
551                        // that member instantiation appear first.
552                        declsToAddBefore.push_back( concDecl );
553                }
554                return new ast::SueInstType<AggrDecl>( concDecl, inst->qualifiers );
555        }
556        case GenericType::dynamic:
557                // Do nothing.
558        default:
559                // Should never happen.
560                return inst;
561        }
562}
563
564void GenericInstantiator::previsit( ast::MemberExpr const * expr ) {
565        GuardValue( location ) = &expr->location;
566        GuardValue( memberIndex ) = -1;
567        // Only run on expressions where the field being accessed is generic.
568        if ( isGenericType( expr->aggregate->result ) ) {
569                // Find the location of the member:
570                ast::AggregateDecl const * aggr =
571                        expr->aggregate->result.strict_as<ast::BaseInstType>()->aggr();
572                std::vector<ast::ptr<ast::Decl>> const & members = aggr->members;
573                auto it = std::find( members.begin(), members.end(), expr->member );
574                memberIndex = std::distance( members.begin(), it );
575                assertf( memberIndex < (int)members.size(), "Could not find member %s in generic type %s.", toString( expr->member ).c_str(), toString( expr->aggregate ).c_str() );
576        }
577}
578
579ast::Expr const * GenericInstantiator::postvisit(
580                ast::MemberExpr const * expr ) {
581        if ( memberIndex == -1 ) {
582                return expr;
583        }
584
585        // Using the location from the generic type, find the member
586        // in the instantiation and rebuild the member expression.
587        ast::AggregateDecl const * aggr =
588                expr->aggregate->result.strict_as<ast::BaseInstType>()->aggr();
589        assertf( memberIndex < (int)aggr->members.size(), "Instantiation somehow has fewer members than the generic type." );
590        ast::Decl const * member = *std::next( aggr->members.begin(), memberIndex );
591        assertf( member->name == expr->member->name, "Instantiation has different member order than the generic type. %s / %s", toString( member ).c_str(), toString( expr->member ).c_str() );
592        auto field = strict_dynamic_cast< ast::DeclWithType const * >( member );
593        ast::MemberExpr * ret = new ast::MemberExpr( expr->location,
594                field,
595                ast::deepCopy( expr->aggregate )
596        );
597        // For pointer decay:
598        ret->result = ResolvExpr::adjustExprType(
599                ret->result,
600                ast::TypeEnvironment(),
601                ast::SymbolTable()
602        );
603        ret->env = expr->env;
604        return ret;
605}
606
607ast::Expr const * GenericInstantiator::postvisit( ast::Expr const * expr ) {
608        // We are not modifying env on MemberExpr, but that seems to work.
609        if ( expr->env ) {
610                auto newEnv = expr->env->accept( *visitor );
611                expr = ast::mutate_field( expr, &ast::Expr::env, newEnv );
612        }
613        return expr;
614}
615
616void GenericInstantiator::previsit( ast::ParseNode const * node ) {
617        GuardValue( location ) = &node->location;
618}
619
620ast::StructDecl const * GenericInstantiator::lookup(
621                ast::StructInstType const * inst,
622                type_vector const & typeSubs ) const {
623        auto ret = instantiations.lookup( inst->base, typeSubs );
624        return strict_dynamic_cast<ast::StructDecl const *, nullptr>( ret );
625}
626
627ast::UnionDecl const * GenericInstantiator::lookup(
628                ast::UnionInstType const * inst,
629                type_vector const & typeSubs ) const {
630        auto ret = instantiations.lookup( inst->base, typeSubs );
631        return strict_dynamic_cast<ast::UnionDecl const *, nullptr>( ret );
632}
633
634void GenericInstantiator::insert( ast::StructInstType const * inst,
635                type_vector const & typeSubs, ast::StructDecl const * decl ) {
636        instantiations.insert( inst->base, typeSubs, decl );
637}
638
639void GenericInstantiator::insert( ast::UnionInstType const * inst,
640                type_vector const & typeSubs, ast::UnionDecl const * decl ) {
641        instantiations.insert( inst->base, typeSubs, decl );
642}
643
644void GenericInstantiator::replaceParametersWithConcrete(
645                std::vector<ast::ptr<ast::Expr>> & params ) {
646        for ( ast::ptr<ast::Expr> & param : params ) {
647                auto paramType = param.as<ast::TypeExpr>();
648                assertf( paramType, "Aggregate parameters should be type expressions." );
649                auto type = replaceWithConcrete( paramType->type, false );
650                param = ast::mutate_field( paramType, &ast::TypeExpr::type, type );
651        }
652}
653
654ast::Type const * GenericInstantiator::replaceWithConcrete(
655                ast::Type const * type, bool doClone ) {
656        if ( auto inst = dynamic_cast<ast::TypeInstType const *>( type ) ) {
657                if ( typeSubs && !inFunctionType ) {
658                        ast::Type const * concType = typeSubs->lookup( inst );
659                        return ast::deepCopy( ( concType ) ? concType : inst );
660                }
661        } else if ( auto inst = dynamic_cast<ast::StructInstType const *>( type ) ) {
662                auto mut = ( doClone ) ? ast::deepCopy( inst ) : ast::mutate( inst );
663                replaceParametersWithConcrete( mut->params );
664                return mut;
665        } else if ( auto inst = dynamic_cast<ast::UnionInstType const *>( type ) ) {
666                auto mut = ( doClone ) ? ast::deepCopy( inst ) : ast::mutate( inst );
667                replaceParametersWithConcrete( mut->params );
668                return mut;
669        }
670        return type;
671}
672
673void GenericInstantiator::stripDtypeParams(
674                ast::AggregateDecl * base,
675                std::vector<ast::ptr<ast::TypeDecl>> & baseParams,
676                std::vector<ast::ptr<ast::TypeExpr>> const & typeSubs ) {
677        substituteMembersHere( base->members, baseParams, typeSubs );
678
679        baseParams.clear();
680
681        dtypeStatics.insert( base );
682}
683
684} // namespace
685
686void instantiateGeneric( ast::TranslationUnit & translationUnit ) {
687        ast::Pass<FixDtypeStatic>::run( translationUnit );
688        ast::Pass<GenericInstantiator>::run( translationUnit );
689}
690
691} // namespace GenPoly
692
693// Local Variables: //
694// tab-width: 4 //
695// mode: c++ //
696// compile-command: "make install" //
697// End: //
Note: See TracBrowser for help on using the repository browser.