source: src/ResolvExpr/TypeEnvironment.cc @ 982f95d

new-env
Last change on this file since 982f95d was 982f95d, checked in by Aaron Moss <a3moss@…>, 6 years ago

Start of new environment implementation; terribly broken

  • Property mode set to 100644
File size: 14.6 KB
Line 
1//
2// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
3//
4// The contents of this file are covered under the licence agreement in the
5// file "LICENCE" distributed with Cforall.
6//
7// TypeEnvironment.cc --
8//
9// Author           : Richard C. Bilson
10// Created On       : Sun May 17 12:19:47 2015
11// Last Modified By : Peter A. Buhr
12// Last Modified On : Sun May 17 12:23:36 2015
13// Update Count     : 3
14//
15
16#include <cassert>                     // for assert
17#include <algorithm>                   // for copy, set_intersection
18#include <iterator>                    // for ostream_iterator, insert_iterator
19#include <utility>                     // for pair, move
20
21#include "Common/InternedString.h"     // for interned_string
22#include "Common/PassVisitor.h"        // for PassVisitor<GcTracer>
23#include "Common/utility.h"            // for maybeClone
24#include "SymTab/Indexer.h"            // for Indexer
25#include "SynTree/GcTracer.h"          // for PassVisitor<GcTracer>
26#include "SynTree/Type.h"              // for Type, FunctionType, Type::Fora...
27#include "SynTree/TypeSubstitution.h"  // for TypeSubstitution
28#include "TypeEnvironment.h"
29#include "Unify.h"                     // for unifyInexact
30
31namespace ResolvExpr {
32        void printAssertionSet( const AssertionSet &assertions, std::ostream &os, int indent ) {
33                for ( AssertionSet::const_iterator i = assertions.begin(); i != assertions.end(); ++i ) {
34                        i->first->print( os, indent );
35                        if ( i->second.isUsed ) {
36                                os << "(used)";
37                        } else {
38                                os << "(not used)";
39                        } // if
40                } // for
41        }
42
43        void printOpenVarSet( const OpenVarSet &openVars, std::ostream &os, int indent ) {
44                os << std::string( indent, ' ' );
45                for ( OpenVarSet::const_iterator i = openVars.begin(); i != openVars.end(); ++i ) {
46                        os << i->first << "(" << i->second << ") ";
47                } // for
48        }
49
50#if 0
51        void EqvClass::initialize( const EqvClass &src, EqvClass &dest ) {
52                dest.vars = src.vars;
53                dest.type = maybeClone( src.type );
54                dest.allowWidening = src.allowWidening;
55                dest.data = src.data;
56        }
57
58        EqvClass::EqvClass() : vars(), type( 0 ), allowWidening( true ), data() {}
59
60        EqvClass::EqvClass( std::vector<interned_string>&& vs, BoundType&& bound )
61                : vars( vs.begin(), vs.end() ), type( maybeClone( bound.type ) ),
62                  allowWidening( bound.allowWidening ), data( bound.data ) {}
63
64        EqvClass::EqvClass( const EqvClass &other ) {
65                initialize( other, *this );
66        }
67
68        EqvClass &EqvClass::operator=( const EqvClass &other ) {
69                if ( this == &other ) return *this;
70                initialize( other, *this );
71                return *this;
72        }
73
74        void EqvClass::print( std::ostream &os, Indenter indent ) const {
75                os << "( ";
76                std::copy( vars.begin(), vars.end(), std::ostream_iterator< std::string >( os, " " ) );
77                os << ")";
78                if ( type ) {
79                        os << " -> ";
80                        type->print( os, indent+1 );
81                } // if
82                if ( ! allowWidening ) {
83                        os << " (no widening)";
84                } // if
85                os << std::endl;
86        }
87
88        const EqvClass* TypeEnvironment::lookup( const std::string &var ) const {
89                for ( std::list< EqvClass >::const_iterator i = env.begin(); i != env.end(); ++i ) {
90                        if ( i->vars.find( var ) != i->vars.end() ) {
91///       std::cout << var << " is in class ";
92///       i->print( std::cout );
93                                return &*i;
94                        }
95///     std::cout << var << " is not in class ";
96///     i->print( std::cout );
97                } // for
98                return nullptr;
99        }
100#endif
101
102        std::pair<interned_string, interned_string> TypeEnvironment::mergeClasses( 
103                        interned_string root1, interned_string root2 ) {
104                // merge classes
105                Classes* newClasses = classes->merge( root1, root2 );
106
107                // determine new root
108                assertf(classes->get_mode() == Classes::REMFROM, "classes updated to REMFROM by merge");
109                auto ret = std::make_pair( classes->get_root(), classes->get_child );
110               
111                // finalize classes
112                classes = newClasses;
113                return ret;
114        }
115
116        ClassRef TypeEnvironment::lookup( interned_string var ) const {
117                interned_string root = classes->find_or_default( var, nullptr );
118                if ( root ) return { this, root };
119                else return { nullptr, var };
120        }
121
122        bool tyVarCompatible( const TypeDecl::Data & data, Type *type ) {
123                switch ( data.kind ) {
124                  case TypeDecl::Dtype:
125                        // to bind to an object type variable, the type must not be a function type.
126                        // if the type variable is specified to be a complete type then the incoming
127                        // type must also be complete
128                        // xxx - should this also check that type is not a tuple type and that it's not a ttype?
129                        return ! isFtype( type ) && (! data.isComplete || type->isComplete() );
130                  case TypeDecl::Ftype:
131                        return isFtype( type );
132                  case TypeDecl::Ttype:
133                        // ttype unifies with any tuple type
134                        return dynamic_cast< TupleType * >( type ) || Tuples::isTtype( type );
135                } // switch
136                return false;
137        }
138
139        bool TypeEnvironment::bindVar( TypeInstType* typeInst, Type* bindTo, 
140                        const TypeDecl::Data& data, AssertionSet& need, AssertionSet& have, 
141                        const OpenVarSet& openVars, WidenMode widenMode, const SymTab::Indexer& indexer ) {
142                // remove references from other, so that type variables can only bind to value types
143                bindTo = bindTo->stripReferences();
144               
145                auto tyVar = openVars.find( typeInst->get_name() );
146                assert( tyVar != openVars.end() );
147                if ( ! tyVarCompatible( tyVar->second, other ) ) return false;
148
149                if ( occurs( bindTo, typeInst->get_name(), *this ) ) return false;
150
151                if ( ClassRef curClass = lookup( typeInst->get_name() ) ) {
152                        BoundType curData = curClass.get_bound();
153                        if ( curData.type ) {
154                                Type* common = nullptr;
155                                // attempt to unify equivalence class type (which needs its qualifiers restored)
156                                // with the target type
157                                Type* newType = curData.type->clone();
158                                newType->get_qualifiers() = typeInst->get_qualifiers();
159                                if ( unifyInexact( newType, bindTo, *this, need, have, openVars, 
160                                                widenMode & WidenMode{ curData.allowWidening, true }, indexer, common ) ) {
161                                        if ( common ) {
162                                                // update bound type to common type
163                                                common->get_qualifiers() = Type::Qualifiers{};
164                                                curData.type = common;
165                                                bindings = bindings->set( curClass.update_root(), curData );
166                                        }
167                                        return true;
168                                } else return false;
169                        } else {
170                                // update bound type to other type
171                                curData.type = bindTo->clone();
172                                curData.type->get_qualifiers() = Type::Qualifiers{};
173                                curData.allowWidening = widenMode.widenFirst && widenMode.widenSecond;
174                                bindings = bindings->set( curClass.get_root(), curData );
175                        }
176                } else {
177                        // make new class consisting entirely of this variable
178                        BoundType curData{ bindTo->clone(), widenMode.first && widenMode.second, data };
179                        curData.type->get_qualifiers() = Type::Qualifiers{};
180                        classes = classes->add( curClass.get_root() );
181                        bindings = bindings->set( curClass.get_root(), curData );
182                }
183                return true;
184        }
185       
186        bool TypeEnvironment::bindVarToVar( TypeInstType* var1, TypeInstType* var2, 
187                        const TypeDecl::Data& data, AssertionSet& need, AssertionSet& have, 
188                        const OpenVarSet& openVars, WidenMode widenMode, const SymTab::Indexer& indexer ) {
189                ClassRef class1 = env.lookup( var1->get_name() );
190                ClassRef class2 = env.lookup( var2->get_name() );
191               
192                // exit early if variables already bound together
193                if ( class1 && class2 && class1 == class2 ) {
194                        BoundType data1 = class1.get_bound();
195                        // narrow the binding if needed
196                        if ( data1.allowWidening && widenMode.first != widenMode.second ) {
197                                data1.allowWidening = false;
198                                bindings = bindings->set( class1.get_root(), data1 );
199                        }
200                        return true;
201                }
202
203                BoundType data1 = class1 ? class1.get_bound() : BoundType{};
204                BoundType data2 = class2 ? class2.get_bound() : BoundType{};
205
206                bool widen1 = data1.allowWidening && widenMode.widenFirst;
207                bool widen2 = data2.allowWidening && widenMode.widenSecond;
208
209                if ( data1.type && data2.type ) {
210                        // attempt to unify bound classes
211                        Type* common = nullptr;
212                        if ( unifyInexact( data1.type->clone(), data2.type->clone(), *this, need, have, 
213                                        openVars, WidenMode{ widen1, widen2 }, indexer, common ) ) {
214                                // merge type variables
215                                interned_string root = mergeClasses( class1.update_root(), class2.update_root() );
216                                // update bindings
217                                data1.allowWidening = widen1 && widen2;
218                                if ( common ) {
219                                        common->get_qualifiers() = Type::Qualifiers{};
220                                        data1.type = common;
221                                }
222                                bindings = bindings->set( root, data1 );
223                        } else return false;
224                } else if ( class1 && class2 ) {
225                        // both classes exist, only one bound -- merge type variables
226                        auto merged = mergeClasses( class1.get_root(), class2.get_root() );
227                        // remove subordinate binding
228                        bindings = bindings->erase( merged.second );
229                        // update root binding (narrow widening as needed, or set new binding for changed root)
230                        if ( data1.type ) {
231                                if ( data1.allowWidening != widen1 ) {
232                                        data1.allowWidening = widen1;
233                                        bindings = bindings->set( merged.first, data1 );
234                                } else if ( merged.first == class2.get_root() ) {
235                                        bindings = bindings->set( merged.first, data1 );
236                                }
237                        } else /* if ( data2.type ) */ {
238                                if ( data2.allowWidening != widen2 ) {
239                                        data2.allowWidening = widen2;
240                                        bindings = bindings->set( root, data2 );
241                                } else if ( merged.first == class1.get_root() ) {
242                                        bindings = bindings->set( merged.first, data2 );
243                                }
244                        }
245                } else if ( class1 ) {
246                        // add unbound var2 to class1
247                        classes = classes->add( class2.get_root() );
248                        auto merged = mergeClasses( class1.get_root(), class2.get_root() );
249                        // update bindings (narrow as needed, or switch binding to root)
250                        if ( merged.first == class2.get_root() ) {
251                                data1.allowWidening = widen1;
252                                bindings = bindings->erase( merged.second )->set( merged.first, data1 );
253                        } else if ( data1.allowWidening != widen1 ) {
254                                bindings = bindings->set( merged.first, data1 );
255                        }
256                } else if ( class2 ) {
257                        // add unbound var1 to class1
258                        classes = classes->add( class1.get_root() );
259                        auto merged = mergeClasses( class1.get_root(), class2.get_root() );
260                        // update bindings (narrow as needed, or switch binding to root)
261                        if ( merged.first == class1.get_root() ) {
262                                data2.allowWidening = widen2;
263                                bindings = bindings->erase( merged.second )->set( merged.first, data2 );
264                        } else if ( data2.allowWidening != widen2 ) {
265                                bindings = bindings->set( merged.first, data2 );
266                        }
267                } else {
268                        // make new class with pair of unbound vars
269                        classes = classes->add( class1.get_root() )->add( class2.get_root() );
270                        auto merged = mergeClasses( class1.get_root(), class2.get_root() );
271                        bindings = bindings->set( merged.first, BoundType{ nullptr, widen1 && widen2, data } );
272                }
273                return true;
274        }
275
276#if !1
277        /// Removes any class from env that intersects eqvClass
278        void filterOverlappingClasses( std::list<EqvClass> &env, const EqvClass &eqvClass ) {
279                for ( auto i = env.begin(); i != env.end(); ) {
280                        auto next = i;
281                        ++next;
282                        std::set<std::string> intersection;
283                        std::set_intersection( i->vars.begin(), i->vars.end(), eqvClass.vars.begin(), eqvClass.vars.end(), 
284                                std::inserter( intersection, intersection.begin() ) );
285                        if ( ! intersection.empty() ) { env.erase( i ); }
286                        i = next;
287                }
288        }
289
290        void TypeEnvironment::add( const EqvClass &eqvClass ) {
291                filterOverlappingClasses( env, eqvClass );
292                env.push_back( eqvClass );
293        }
294
295        void TypeEnvironment::add( EqvClass &&eqvClass ) {
296                filterOverlappingClasses( env, eqvClass );
297                env.push_back( std::move(eqvClass) );
298        }
299
300        void TypeEnvironment::add( const Type::ForallList &tyDecls ) {
301                for ( Type::ForallList::const_iterator i = tyDecls.begin(); i != tyDecls.end(); ++i ) {
302                        EqvClass newClass;
303                        newClass.vars.insert( (*i)->get_name() );
304                        newClass.data = TypeDecl::Data{ (*i) };
305                        env.push_back( newClass );
306                } // for
307        }
308
309        void TypeEnvironment::add( const TypeSubstitution & sub ) {
310                EqvClass newClass;
311                for ( auto p : sub ) {
312                        newClass.vars.insert( p.first );
313                        newClass.type = p.second->clone();
314                        newClass.allowWidening = false;
315                        // Minimal assumptions. Not technically correct, but might be good enough, and
316                        // is the best we can do at the moment since information is lost in the
317                        // transition to TypeSubstitution
318                        newClass.data = TypeDecl::Data{ TypeDecl::Dtype, false };
319                        add( newClass );
320                }
321        }
322
323        void TypeEnvironment::makeSubstitution( TypeSubstitution &sub ) const {
324                for ( std::list< EqvClass >::const_iterator theClass = env.begin(); theClass != env.end(); ++theClass ) {
325                        for ( std::set< std::string >::const_iterator theVar = theClass->vars.begin(); theVar != theClass->vars.end(); ++theVar ) {
326///       std::cerr << "adding " << *theVar;
327                                if ( theClass->type ) {
328///         std::cerr << " bound to ";
329///         theClass->type->print( std::cerr );
330///         std::cerr << std::endl;
331                                        sub.add( *theVar, theClass->type );
332                                } else if ( theVar != theClass->vars.begin() ) {
333                                        TypeInstType *newTypeInst = new TypeInstType( Type::Qualifiers(), *theClass->vars.begin(), theClass->data.kind == TypeDecl::Ftype );
334///         std::cerr << " bound to variable " << *theClass->vars.begin() << std::endl;
335                                        sub.add( *theVar, newTypeInst );
336                                } // if
337                        } // for
338                } // for
339///   std::cerr << "input env is:" << std::endl;
340///   print( std::cerr, 8 );
341///   std::cerr << "sub is:" << std::endl;
342///   sub.print( std::cerr, 8 );
343                sub.normalize();
344        }
345
346        void TypeEnvironment::print( std::ostream &os, Indenter indent ) const {
347                for ( std::list< EqvClass >::const_iterator i = env.begin(); i != env.end(); ++i ) {
348                        i->print( os, indent );
349                } // for
350        }
351
352        std::list< EqvClass >::iterator TypeEnvironment::internal_lookup( const std::string &var ) {
353                for ( std::list< EqvClass >::iterator i = env.begin(); i != env.end(); ++i ) {
354                        if ( i->vars.find( var ) == i->vars.end() ) {
355                                return i;
356                        } // if
357                } // for
358                return env.end();
359        }
360
361        void TypeEnvironment::simpleCombine( const TypeEnvironment &second ) {
362                env.insert( env.end(), second.env.begin(), second.env.end() );
363        }
364
365        void TypeEnvironment::extractOpenVars( OpenVarSet &openVars ) const {
366                for ( std::list< EqvClass >::const_iterator eqvClass = env.begin(); eqvClass != env.end(); ++eqvClass ) {
367                        for ( std::set< std::string >::const_iterator var = eqvClass->vars.begin(); var != eqvClass->vars.end(); ++var ) {
368                                openVars[ *var ] = eqvClass->data;
369                        } // for
370                } // for
371        }
372
373        void TypeEnvironment::addActual( const TypeEnvironment& actualEnv, OpenVarSet& openVars ) {
374                for ( const EqvClass& c : actualEnv ) {
375                        EqvClass c2 = c;
376                        c2.allowWidening = false;
377                        for ( const std::string& var : c2.vars ) {
378                                openVars[ var ] = c2.data;
379                        }
380                        env.push_back( std::move(c2) );
381                }
382        }
383
384        std::ostream & operator<<( std::ostream & out, const TypeEnvironment & env ) {
385                env.print( out );
386                return out;
387        }
388#endif
389
390        PassVisitor<GcTracer> & operator<<( PassVisitor<GcTracer> & gc, const TypeEnvironment & env ) {
391                for ( ClassRef c : env ) {
392                        maybeAccept( c.get_bound().type, gc );
393                }
394                return gc;
395        }
396} // namespace ResolvExpr
397
398// Local Variables: //
399// tab-width: 4 //
400// mode: c++ //
401// compile-command: "make install" //
402// End: //
Note: See TracBrowser for help on using the repository browser.