source: src/GenPoly/InstantiateGeneric.cpp @ 048dde4

Last change on this file since 048dde4 was a21aaff, checked in by Andrew Beach <ajbeach@…>, 3 weeks ago

Syncronized getPrintName with mangleName. Ideally there would be some common function to call but I'm not sure where it would go.

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