summaryrefslogblamecommitdiff
path: root/sources/scalac/transformer/ExpandMixins.java
blob: de5cbc9c51a7665c8acd44b2dd14930bf78803c0 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11










                                                                          
                        



                         
                            






                                
                                












                                          
 

                                                                              
 

                                 
 

                              
 

                               
 

                                             
 

                                             
 

                                              
 
                                          
                                            
 

                                                             
 

                                                     
 

                                                            
 







                                                                              
                                                             
                                                                     
                                                              
                                     



                                                                      


                                                             

     


                                                                              

                                                                     



                                                                            
                                                                 
                                           
                                                                           
                                                                 

                                                                        
                                                                

                                                        

                                                                   
                                                           
                                                                              

                      
                
                                                                     


         




                                                          
                                            
                                                                    




                                                                                             


                                             
          

                                                            
                                                                    
                                                                          

                        

     

                                                                              
 
                                                                               




                                                                
         
                                 



                                                                          
                                                              
         

     
                                                            















                                                                              
         




                                                                       
         


                                                                
                                                             
                    




                                                                          
                                                                          
                      


             
 



































                                                                           
                           

                                            











                                                                                                                                     
                                                                              
 
/*     ____ ____  ____ ____  ______                                     *\
**    / __// __ \/ __// __ \/ ____/    SOcos COmpiles Scala             **
**  __\_ \/ /_/ / /__/ /_/ /\_ \       (c) 2002, LAMP/EPFL              **
** /_____/\____/\___/\____/____/                                        **
\*                                                                      */

// $OldId: ExpandMixins.java,v 1.24 2002/11/11 16:08:50 schinz Exp $
// $Id$

package scalac.transformer;

import java.util.Arrays;
import java.util.Map;
import java.util.HashMap;
import java.util.Set;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Iterator;

import scalac.Global;
import scalac.ast.Tree;
import scalac.ast.Tree.Template;
import scalac.ast.TreeList;
import scalac.ast.TreeGen;
import scalac.ast.GenTreeCloner;
import scalac.ast.TreeSymbolCloner;
import scalac.ast.Transformer;
import scalac.symtab.Modifiers;
import scalac.symtab.Scope;
import scalac.symtab.Scope.SymbolIterator;
import scalac.symtab.Symbol;
import scalac.symtab.SymbolCloner;
import scalac.symtab.SymbolSubstTypeMap;
import scalac.symtab.Type;
import scalac.util.Name;
import scalac.util.Debug;

public class ClassExpander {

    //########################################################################
    // Private Fields

    /** The global environment */
    private final Global global;

    /** A tree generator */
    private final TreeGen gen;

    /** The expanding class */
    private final Symbol clasz;

    /** The parents of the expanding class */
    private final Type[] parents;

    /** The members of the expanding class */
    private final Scope members;

    /** The template of the expanding class */
    private final Template template;

    /** The body of the expanding class */
    private final LinkedList/*<Tree>*/ body;

    /** The type map to apply to inlined symbols and trees */
    private final SymbolSubstTypeMap map;

    /** The symbol cloner to clone inlined symbols */
    private final SymbolCloner cloner;

    /** The state of this class (used to prevent misuses) */
    private int state;

    //########################################################################
    // Public Constructors

    public ClassExpander(Global global, Symbol clasz, Template template) {
        this.global = global;
        this.gen = global.treeGen;
        this.clasz = clasz;
        this.parents = Type.cloneArray(clasz.parents());
        this.members = clasz.members(); // !!! .cloneScope();
        this.template = gen.Template(template.pos, template.symbol(),
            Tree.cloneArray(template.parents), template.body);
        this.body = new LinkedList();
        this.map = new SymbolSubstTypeMap();
        this.cloner = new SymbolCloner(
            global.freshNameCreator, new HashMap(), map.getSymbols());
        this.state = parents.length;

        this.mixinMemberCloner = new MixinMemberCloner(this);
        this.superFixer = new SuperFixer(global);
    }

    //########################################################################
    // Public Methods

    // !!! remove this.parents
    /** Inlines the ith mixin with given type, interface and body. */
    public void inlineMixin(int i, Type type, Symbol iface, Template impl) {
        assert 0 < i && i < state : "state = " + state + ", i = " + i;
        switch (parents[i]) {
        case TypeRef(Type prefix, Symbol mixin, Type[] args):
            // relpace "This/Super(mixin)" by "This/Super(clasz)"
            map.insertSymbol(mixin, clasz);
            // owner of inlined value parameters and constructor is "clasz"
            cloner.owners.put(mixin.primaryConstructor(), clasz);
            // map mixin type parameters to mixin type arguments
            map.insertType(type.symbol().typeParams(), type.typeArgs());
            Tree.Apply constr = (Tree.Apply)template.parents[i];
            Symbol[] vparams = mixin.valueParams();
            inlineMixinVParams(vparams, constr.args, 0);
            createMixedInMemberSymbols(mixin.nextInfo().members());
            inlineMixedInCode(impl, vparams.length);
            parents[i] = Type.TypeRef(prefix, iface, args);
            template.parents[i] = gen.mkPrimaryConstr(constr.pos, parents[i]);
            state = i;
            return;
        default:
            throw Debug.abort("invalid base class type", parents[i]);
        }
    }

    public Template getTemplate() {
        assert 0 < state : "state = " + state;
        Transformer superFixer = new Transformer(global) {
            public Tree transform(Tree tree) {
                switch (tree) {
                case Select(Super(_, _), _):
                    Symbol symbol = map.lookupSymbol(tree.symbol());
                    if (symbol != null) {
                        Tree qualifier = gen.This(tree.pos, clasz);
                assert qualifier.type().baseType(symbol.owner()) != Type.NoType: tree; // !!!
                        return gen.Select(qualifier, symbol);
                    }
                }
                return super.transform(tree);
            }
        };
        body.addAll(Arrays.asList(this.superFixer.transform(
superFixer.transform(template.body))));
        template.body = (Tree[])body.toArray(new Tree[body.size()]);
        // !!! *1 fix ExpandMixinsPhase.transformInfo and remove next line
        state = 0;
        return template;
    }

    //########################################################################
    // Private Methods

    private void inlineMixinVParams(Symbol[] params, Tree[] args, int fstPos) {
        for (int i = 0; i < params.length; i++) {
            Symbol member = cloner.cloneSymbol(params[i], true);
            member.flags &= ~Modifiers.PARAM;
            member.flags |= Modifiers.PRIVATE;
            members.enter(member);
        }
        // !!! remove double loop
        // We need two loops because parameters may appear in their types.
        for (int i = 0; i < params.length; i++) {
            Symbol member = map.lookupSymbol(params[i]);
            member.setType(map.apply(member.type()));
            body.add(fstPos + i, gen.ValDef(member, args[i]));
        }
    }

    private void createMixedInMemberSymbols(Scope symbols) {
        // The map names is used to implement an all or nothing
        // strategy for overloaded symbols.
        Map/*<Name,Name>*/ names = new HashMap();
        for (SymbolIterator i = symbols.iterator(true); i.hasNext();) {
            Symbol member = i.next();
            Name name = (Name)names.get(member.name);
            boolean shadowed = name == null &&
                members.lookup(member.name) != Symbol.NONE;
            Symbol clone = cloner.cloneSymbol(member, shadowed);
            if (name != null)
                clone.name = name;
            else
                names.put(member.name, clone.name);
            if (clone.name != member.name) clone.flags &= ~Modifiers.OVERRIDE;
            clone.setType(clone.type().cloneTypeNoSubst(cloner));
            members.enterOrOverload(clone);
        }
        // We need two loops because members may appear in their types.
        for (SymbolIterator i = symbols.iterator(true); i.hasNext();) {
            Symbol member = map.lookupSymbol(i.next());
            if (member == null) continue;
            member.setType(map.applyParams(member.type()));
        }
    }

    private void inlineMixedInCode(Template mixin, int fstPos) {
        cloner.owners.put(mixin.symbol(), template.symbol());
        int pos = 0;
        for (int i = 0; i < mixin.body.length; i++) {
            Tree tree = mixin.body[i];
            // Inline local code and members whose symbol has been cloned.
            if (!tree.definesSymbol() ||
                map.lookupSymbol(tree.symbol()) != null) {
                body.add(fstPos + pos, mixinMemberCloner.transform(tree));
                ++pos;
            }
        }
    }

    private final GenTreeCloner mixinMemberCloner;

    private class MixinMemberCloner extends GenTreeCloner {
        public MixinMemberCloner(ClassExpander expander) {
            super(expander.global, expander.map, expander.cloner);
        }

        public Symbol getSymbolFor(Tree tree) {
            switch (tree) {
            case Select(Super(_, _), _):
                // !!! check
                global.nextPhase();
                Symbol symbol = tree.symbol().overridingSymbol(parents[0]);
                global.prevPhase();
                assert !symbol.isNone(): tree;
                return symbol;
            case Super(_, _):
            case This(_):
                return clasz;
            default:
                return super.getSymbolFor(tree);
            }
        }

    }

    private final Transformer superFixer;

    private class SuperFixer extends Transformer {
        private final Type parent;

        public SuperFixer(Global global) {
            super(global);
            this.parent = clasz.parents()[0];
        }
        public Tree transform(Tree tree) {
            switch (tree) {
            case ClassDef(_, _, _, _, _, _):
                return tree;
            case Select(Super(_, _), _):
                Tree qualifier = ((Tree.Select)tree).qualifier;
                qualifier = gen.Super(qualifier.pos, clasz);
                Symbol symbol = tree.symbol().overridingSymbol(parent);
                assert !symbol.isNone(): tree + " -- " + parent  + " -- " + Debug.show(clasz.parents()) + " -- " + Debug.show(clasz);
                return gen.Select(tree.pos, qualifier, symbol);
            default:
                return super.transform(tree);
            }
        }
    }

    //########################################################################
}