source: src/GenPoly/InstantiateGenericNew.cpp @ 01865fb

ADTast-experimentalpthread-emulation
Last change on this file since 01865fb was 01865fb, checked in by Thierry Delisle <tdelisle@…>, 20 months ago

New pass mixin now has 1 use

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