summaryrefslogblamecommitdiff
path: root/sources/scalac/ast/TreeGen.java
blob: ac99d4f58bd8b4e372ab287a3c381a9f14e61e95 (plain) (tree)
1
2
3
4
5
6
7
8
9
10



                                                                          

                                                                          

       

                   




                       

                                                        
  

                                               
   
                                                            
 

                                                                              
 

                                 
 

                                          
 
                           
                                  
 

                                                                              
 



                                     
 
                                     





                                                     









                                                                              

     





                                                                 
 






                                                       

     


                                                     

     




                                                              

     






                                                                              

     



                                                                       

     



                                                  

     



                                                   

     



                                                       

     



                                                     

     



                                                  

     



                                                   

     



                                                    

     


                                                                              

     






















                                                                    
         

     






                                                                           

     









                                                                              

     


                                                            

     





                                                                      

     










                                                                   
 







                                                           

     







                                                             

     







































                                                                              
       

                                                                              

                                              
                                                                
                     

     



                                                                  




                                                           

     



                                                                  
       
                                                                   
                       




                                                                  

     



                                                                     
       

                                                            

     


                                                                   
       






                                                                              
     

                                                                               

     


                                                                   
       




                                                                               

     


                                                                      
       

                                                                  
     

                                                                     

     



                                                                            
     

                                                              
     





                                                                       

     


                                                                   
       

                                                         
     

                                                
     

                                                         
     

                                                

     












                                                                     
     

                                                       

     










                                                                                                                             
     

                                               

     


                                                                     
     

                                 

     

                                                                              
 


                                                                              
     

                                                       

     






                                                     

     


                                                                    

     




                                                                  
     

                                              

     











                                                                              


                                                      








                                                                     
     

                                       

     




                                                                 
     

                                               

     

                                                                              
 






                                                             

     

























                                                                             

     


                                                                   

     


                                                                    

     

                                                                   
                                    


                                                                         
                                    
                                                                            

     










                                                                      

     


                                                               
       





                                                                        

     
































                                                                    

     








                                                        

     


                                                                              
 

                                                                              
 




                                                                               
     

                                                                         

     





                                                                              

     
 



                                                                                       

     








                                                                              

                                           
       

                                                                                

























                                                                              


                                                          

                                                               
                                                                          
                                        
                                                                          

                                                                         
                                                       

                                                



                                                 

                                                                


                                                                   
                                                  

     
 

                                                                                      

                                                               



                                                                          
                                        
                                                                          





                                                                                


                                                                   
                                                  










                                                                                  
                       
                        
                                                                 

                                                                           


                                      

                                                                          


                                                                                       



                                                                  

                     
                                     

             
                              
     




                                                                  
                                                                     





                                                                       
                                                                     


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

// $Id$

package scalac.ast;

import scalac.*;
import scalac.symtab.*;
import scalac.util.*;
import Tree.*;

/**
 * This class provides method to build attributed trees.
 *
 * @author     Martin Odersky, Christine Roeckl
 * @version    1.0
 */
public class TreeGen implements Kinds, Modifiers, TypeTags {

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

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

    /** The global definitions */
    private final Definitions definitions;

    /** The tree factory */
    public final TreeFactory make;

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

    /** Initializes this instance. */
    public TreeGen(Global global) {
	this(global, global.make);
    }

    /** Initializes this instance. */
    public TreeGen(Global global, TreeFactory make) {
        this.global = global;
	this.definitions = global.definitions;
        this.make = make;
    }

    //########################################################################
    // Public Methods - Building types

    /** Builds type references corresponding to given symbols. */
    public Tree[] mkTypeRefs(int pos, Symbol[] syms) {
        if (syms.length == 0) return Tree.EMPTY_ARRAY;
        Tree[] trees = new Tree[syms.length];
        for (int i = 0; i < trees.length; i++)
            trees[i] = mkTypeRef(pos, syms[i]);
	return trees;
    }

    /** Builds a type reference corresponding to given symbol. */
    public Tree mkTypeRef(int pos, Symbol sym) {
        assert sym.kind == TYPE: Debug.show(sym);
	sym.flags |= ACCESSED;
	return mkType(pos, sym.nextType());
    }

    /** Builds trees corresponding to given types. */
    public Tree[] mkTypes(int pos, Type[] types) {
        if (types.length == 0) return Tree.EMPTY_ARRAY;
        Tree[] trees = new Tree[types.length];
        for (int i = 0; i < trees.length; i++)
            trees[i] = mkType(pos, types[i]);
        return trees;
    }

    /** Builds a tree corresponding to given type. */
    public Tree mkType(int pos, Type type) {
	return TypeTerm(pos, type);
    }

    /** Builds a TypeTerm node corresponding to given type. */
    public TypeTerm TypeTerm(int pos, Type type) {
        TypeTerm tree = make.TypeTerm(pos);
        tree.setType(type);
        return tree;
    }

    //########################################################################
    // Public Methods - Building constants

    /** Builds a unit literal. */
    public Tree mkUnitLit(int pos) {
        return make.Block(pos, Tree.EMPTY_ARRAY).
            setType(definitions.UNIT_TYPE);
    }

    /** Builds a boolean literal. */
    public Tree mkBooleanLit(int pos, boolean value) {
        return make.Literal(pos, value ? Boolean.TRUE : Boolean.FALSE).
            setType(definitions.BOOLEAN_TYPE);
    }

    /** Builds a byte literal. */
    public Tree mkByteLit(int pos, byte value) {
        return make.Literal(pos, new Byte(value)).
            setType(definitions.BYTE_TYPE);
    }

    /** Builds a short literal. */
    public Tree mkShortLit(int pos, short value) {
        return make.Literal(pos, new Short(value)).
            setType(definitions.SHORT_TYPE);
    }

    /** Builds a character literal. */
    public Tree mkCharLit(int pos, char value) {
        return make.Literal(pos, new Character(value)).
            setType(definitions.CHAR_TYPE);
    }

    /** Builds an integer literal */
    public Tree mkIntLit(int pos, int value) {
        return make.Literal(pos, new Integer(value)).
            setType(definitions.INT_TYPE);
    }

    /** Builds a long literal. */
    public Tree mkLongLit(int pos, long value) {
        return make.Literal(pos, new Long(value)).
            setType(definitions.LONG_TYPE);
    }

    /** Builds a float literal. */
    public Tree mkFloatLit(int pos, float value) {
        return make.Literal(pos, new Float(value)).
            setType(definitions.FLOAT_TYPE);
    }

    /** Builds a double literal. */
    public Tree mkDoubleLit(int pos, double value) {
        return make.Literal(pos, new Double(value)).
            setType(definitions.DOUBLE_TYPE);
    }

    /** Builds a string literal. */
    public Tree mkStringLit(int pos, String value) {
        return make.Literal(pos, value).setType(definitions.JAVA_STRING_TYPE);
    }

    /** Builds a null literal. */
    public Tree mkNullLit(int pos) {
        return Ident(pos, definitions.NULL);
    }

    /** Builds a zero literal. */
    public Tree mkZeroLit(int pos) {
        return Ident(pos, definitions.ZERO);
    }

    /** Builds a default zero value according to given type tag. */
    public Tree mkDefaultValue(int pos, int tag) {
        switch (tag) {
        case UNIT   : return mkUnitLit(pos);
        case BOOLEAN: return mkBooleanLit(pos, false);
        case BYTE   : return mkByteLit(pos, (byte)0);
        case SHORT  : return mkShortLit(pos, (short)0);
        case CHAR   : return mkCharLit(pos, '\0');
        case INT    : return mkIntLit(pos, 0);
        case LONG   : return mkLongLit(pos, 0l);
        case FLOAT  : return mkFloatLit(pos, 0f);
        case DOUBLE : return mkDoubleLit(pos, 0d);
        default     : throw Debug.abort("unknown type tag: " + tag);
        }
    }

    /** Builds a default zero value according to given type. */
    public Tree mkDefaultValue(int pos, Type type) {
	if (type.isSubType(definitions.ANYREF_TYPE)) return mkNullLit(pos);
        switch (type.unbox()) {
        case UnboxedType(int tag): return mkDefaultValue(pos, tag);
        }
        return mkZeroLit(pos);
    }

    //########################################################################
    // Public Methods - Building references

    /** Builds references corresponding to given symbols. */
    public Tree[] mkRefs(int pos, Symbol[] syms) {
        if (syms.length == 0) return Tree.EMPTY_ARRAY;
        Tree[] trees = new Tree[syms.length];
        for (int i = 0; i < trees.length; i++)
            trees[i] = mkRef(pos, syms[i]);
	return trees;
    }

    /** Builds a reference corresponding to given symbol. */
    public Tree mkRef(int pos, Symbol sym) {
	return mkRef(pos, sym.owner().thisType(), sym);
    }

    /** Builds a reference corresponding to given prefix & symbol. */
    public Tree mkRef(int pos, Type pre, Symbol sym) {
	if (pre.isSameAs(Type.localThisType) || pre.symbol().isRoot())
	    return Ident(pos, sym);
	else
	    return Select(pos, mkStableId(pos, pre), sym);
    }

    /** Builds a reference corresponding to given stable prefix. */
    public Tree mkStableId(int pos, Type pre) {
        switch (pre.expandModuleThis()) {
	case ThisType(Symbol sym):
	    return This(pos, sym);
        case SingleType(Type pre1, Symbol sym):
	    return mkRef(pos, pre1, sym);
        default:
            throw Debug.abort("illegal case", pre);
        }
    }

    /** Builds a This node corresponding to given class. */
    public This This(int pos, Symbol clazz) {
        assert clazz.isClass(): Debug.show(clazz);
        This tree = make.This(pos, clazz);
        global.nextPhase();
        tree.setType(clazz.thisType());
        global.prevPhase();
        return tree;
    }

    /** Builds a Super node corresponding to given class. */
    public Super Super(int pos, Symbol clazz) {
        assert clazz.isClass(): Debug.show(clazz);
        Super tree = make.Super(pos, clazz, TypeNames.EMPTY);
        global.nextPhase();
        tree.setType(clazz.thisType());
        global.prevPhase();
        return tree;
    }

    /** Builds an Ident node corresponding to given symbol. */
    public Ident Ident(int pos, Symbol sym) {
        assert sym.isTerm(): Debug.show(sym);
	sym.flags |= ACCESSED;
	Ident tree = make.Ident(pos, sym);
        global.nextPhase();
	if (sym.isStable())
            tree.setType(Type.singleType(sym.owner().thisType(), sym));
        else
            tree.setType(sym.type());
        global.prevPhase();
        return tree;
    }

    /**
     * Builds a Select node corresponding to given symbol selected
     * from given qualifier.
     */
    public Select Select(int pos, Tree qual, Symbol sym) {
	assert sym.isTerm(): Debug.show(sym);
	sym.flags |= ACCESSED | SELECTOR;
	Select tree = make.Select(pos, sym, qual);
        global.nextPhase();
	if (sym.isStable() && qual.type.isStable())
            tree.setType(Type.singleType(qual.type, sym));
        else
            tree.setType(qual.type.memberType(sym));
        global.prevPhase();
        return tree;
    }
    public Select Select(Tree qual, Symbol sym) {
	return Select(qual.pos, qual, sym);
    }

    //########################################################################
    // Public Methods - Building applications

    /**
     * Builds calls to primary constructors of given types with given
     * value arguments.
     */
    public Tree[] mkPrimaryConstrs(int pos, Type[] types, Tree[][] vargs) {
        assert types.length == vargs.length: Debug.show(types, " -- ", vargs);
        Tree[] trees = new Tree[types.length];
        for (int i = 0; i < trees.length; i++)
            trees[i] = mkPrimaryConstr(pos, types[i], vargs[i]);
        return trees;
    }

    /**
     * Builds calls to primary constructors of given types with no
     * value arguments.
     */
    public Tree[] mkPrimaryConstrs(int pos, Type[] types) {
        Tree[] trees = new Tree[types.length];
        for (int i = 0; i < trees.length; i++)
            trees[i] = mkPrimaryConstr(pos, types[i]);
        return trees;
    }

    /**
     * Builds a call to the primary constructor of given type with
     * given value arguments. Missing type arguments are extracted
     * from the given type.
     */
    public Tree mkPrimaryConstr(int pos, Type type, Tree[] vargs) {
	switch (type) {
	case TypeRef(Type pre, Symbol clazz, Type[] targs):
            return mkPrimaryConstr(pos, pre, clazz, targs, vargs);
	default:
	    throw Debug.abort("invalid type", type);
	}
    }

    /**
     * Builds a call to the primary constructor of given type with no
     * value arguments. Missing type arguments are extracted from the
     * given type.
     */
    public Tree mkPrimaryConstr(int pos, Type type) {
        return mkPrimaryConstr(pos, type, Tree.EMPTY_ARRAY);
    }

    /**
     * Builds a call to the primary constructor of given class with
     * given type and value arguments.
     */
    public Tree mkPrimaryConstr(int pos, Type pre, Symbol clazz, Type[] targs,
        Tree[] vargs)
    {
        global.nextPhase();
        Symbol constr = clazz.primaryConstructor();
        global.prevPhase();
        return mkApply(mkRef(pos, constr), targs, vargs);
    }
    public Tree mkPrimaryConstr(int pos, Symbol clazz,Type[]targs,Tree[]vargs){
        return mkPrimaryConstr(pos,clazz.owner().thisType(),clazz,targs,vargs);
    }

    /**
     * Builds a call to the primary constructor of given class with
     * given type arguments and no value arguments.
     */
    public Tree mkPrimaryConstr(int pos, Type pre, Symbol clazz, Type[] targs){
        return mkPrimaryConstr(pos, pre, clazz, targs, Tree.EMPTY_ARRAY);
    }
    public Tree mkPrimaryConstr(int pos, Symbol clazz, Type[] targs) {
        return mkPrimaryConstr(pos, clazz.owner().thisType(), clazz, targs);
    }

    /**
     * Builds a call to the primary constructor of given class with no
     * type and value arguments.
     */
    public Tree mkPrimaryConstr(int pos, Type pre, Symbol clazz) {
        return mkPrimaryConstr(pos, pre, clazz, Type.EMPTY_ARRAY);
    }
    public Tree mkPrimaryConstr(int pos, Symbol clazz) {
        return mkPrimaryConstr(pos, clazz.owner().thisType(), clazz);
    }

    /** Builds an application with given function and arguments. */
    public Tree mkApply(int pos, Tree fn, Type[] targs, Tree[] vargs) {
        if (targs.length != 0) fn = TypeApply(pos, fn, mkTypes(pos, targs));
        return Apply(pos, fn, vargs);
    }
    public Tree mkApply(Tree fn, Type[] targs, Tree[] vargs) {
        return mkApply(fn.pos, fn, targs, vargs);
    }
    public Tree mkApply(int pos, Tree fn, Tree[] targs, Tree[] vargs) {
        if (targs.length != 0) fn = TypeApply(pos, fn, targs);
        return Apply(pos, fn, vargs);
    }
    public Tree mkApply(Tree fn, Tree[] targs, Tree[] vargs) {
        return mkApply(fn.pos, fn, targs, vargs);
    }

    /**
     * Builds an application with given function and type arguments
     * and with no value arguments.
     */
    public Tree mkApply(int pos, Tree fn, Type[] targs) {
        return mkApply(pos, fn, targs, Tree.EMPTY_ARRAY);
    }
    public Tree mkApply(Tree fn, Type[] targs) {
        return mkApply(fn.pos, fn, targs);
    }
    public Tree mkApply(int pos, Tree fn, Tree[] targs) {
        return mkApply(pos, fn, targs, Tree.EMPTY_ARRAY);
    }
    public Tree mkApply(Tree fn, Tree[] targs) {
        return mkApply(fn.pos, fn, targs);
    }

    /** Builds a TypeApply node with given function and arguments. */
    public TypeApply TypeApply(int pos, Tree fn, Tree[] targs) {
        switch (fn.type) {
        case PolyType(Symbol[] tparams, Type result):
            TypeApply tree = make.TypeApply(pos, fn, targs);
            assert tparams.length == targs.length: tree;
            global.nextPhase();
            tree.setType(result.subst(tparams, Tree.typeOf(targs)));
            global.prevPhase();
            return tree;
        default:
            throw Debug.abort("illegal case", fn.type);
        }
    }
    public TypeApply TypeApply(Tree fn, Tree[] targs) {
      return TypeApply(fn.pos, fn, targs);
    }

    /** Builds an Apply node with given function and arguments. */
    public Apply Apply(int pos, Tree fn, Tree[] vargs) {
        switch (fn.type) {
        case Type.MethodType(Symbol[] vparams, Type result):
            Apply tree = make.Apply(pos, fn, vargs);
            // !!! assert vparams.length == vargs.length: tree + " --- " + Debug.show(vparams) + " --- " + Debug.show(vargs);
            tree.setType(result);
            return tree;
        default:
            throw Debug.abort("illegal case", fn);
        }
    }
    public Apply Apply(Tree fn, Tree[] vargs) {
        return Apply(fn.pos, fn, vargs);
    }

    /** Builds an Apply node with given function and no arguments. */
    public Apply Apply(int pos, Tree fn) {
        return Apply(pos, fn, Tree.EMPTY_ARRAY);
    }
    public Apply Apply(Tree fn) {
        return Apply(fn.pos, fn);
    }

    //########################################################################
    // Public Methods - Building expressions

    /** Builds a cast with given value and type. */
    public Tree mkAsInstanceOf(int pos, Tree value, Type type) {
        return mkApply(pos, Select(value, definitions.AS), new Type[] {type});
    }
    public Tree mkAsInstanceOf(Tree value, Type type) {
        return mkAsInstanceOf(value.pos, value, type);
    }

    /** Builds a Block node with given statements. */
    public Tree Block(int pos, Tree[] stats) {
        Block tree = make.Block(pos, stats);
        tree.setType(stats.length == 0
            ? definitions.UNIT_TYPE
            : stats[stats.length - 1].type);
	return tree;
    }

    /** Builds a Block node with given non-empty statements list. */
    public Tree Block(Tree[] stats) {
	return Block(stats[0].pos, stats);
    }

    /** Builds an Assign node corresponding to "<lhs> = <rhs>". */
    public Assign Assign(int pos, Tree lhs, Tree rhs) {
        Assign tree = make.Assign(pos, lhs, rhs);
        tree.setType(definitions.UNIT_TYPE);
        return tree;
    }
    public Assign Assign(Tree lhs, Tree rhs) {
        return Assign(lhs.pos, lhs, rhs);
    }

    /** Builds an If node with given condition and branches. */
    public If If(int pos, Tree cond, Tree thenpart, Tree elsepart) {
	If tree = make.If(pos, cond, thenpart, elsepart);
        global.nextPhase();
        if (thenpart.type.isSameAs(elsepart.type))
            tree.setType(thenpart.type);
        else
            tree.setType(Type.lub(new Type[] {thenpart.type, elsepart.type}));
        global.prevPhase();
        return tree;
    }
    public If If(Tree cond, Tree thenpart, Tree elsepart) {
	return If(cond.pos, cond, thenpart, elsepart);
    }

    /** Builds a New node corresponding to "new <constr>". */
    public Tree New(int pos, Tree constr) {
        Symbol local = localDummy(pos, Symbol.NONE); // !!!
	Template templ = make.Template(
            pos, local, new Tree[]{constr}, Tree.EMPTY_ARRAY); // !!!
	templ.setType(constr.type);
	New tree = make.New(pos, templ);
        tree.setType(constr.type);
        return tree;
    }
    public Tree New(Tree constr) {
        return New(constr.pos, constr);
    }

    /** Builds a Typed nodes with given value and type. */
    public Typed Typed(int pos, Tree value, Type type) {
        Typed tree = make.Typed(pos, value, TypeTerm(pos, type));
        tree.setType(type);
        return tree;
    }
    public Typed Typed(Tree value, Type type) {
        return Typed(value.pos, value, type);
    }

    //########################################################################
    // Public Methods - Building definitions

    /** Builds the type parameter section of given symbol. */
    public AbsTypeDef[] mkTypeParamsOf(Symbol sym) {
        Symbol[] tparams = sym.nextTypeParams();
        AbsTypeDef[] trees = new AbsTypeDef[tparams.length];
        for (int i = 0; i < tparams.length; i++)
            trees[i] = mkTypeParam(tparams[i]);
        return trees;
    }

    /** Builds the value parameter section of given symbol. */
    public ValDef[][] mkParamsOf(Symbol sym) {
        global.nextPhase();
        if (sym.isClass()) sym = sym.primaryConstructor();
        Type type = sym.type();
        global.prevPhase();
        ValDef[][] treess = Tree.ValDef_EMPTY_ARRAY_ARRAY;
        while (true) {
            switch (type) {
            case PolyType(_, Type result):
                type = result;
                continue;
            case MethodType(Symbol[] vparams, Type result):
                ValDef[] trees = new ValDef[vparams.length];
                for (int i = 0; i < vparams.length; i++)
                    trees[i] = mkParam(vparams[i]);
                ValDef[][] array = new ValDef[treess.length + 1][];
                for (int i = 0; i < treess.length; i++) array[i] = treess[i];
                array[treess.length] = trees;
                treess = array;
                type = result;
                continue;
            default:
                return treess;
            }
        }
    }

    /** Builds the type parameter corresponding to given symbol. */
    public AbsTypeDef mkTypeParam(Symbol sym) {
	return AbsTypeDef(sym);
    }

    /** Builds the value parameter corresponding to given symbol. */
    public ValDef mkParam(Symbol sym) {
	return ValDef(sym, Tree.Empty);
    }

    /** Builds a definition for given interface with given body. */
    public Tree mkInterfaceDef(Symbol clazz, Tree[] body) {
	Global.instance.nextPhase();
        clazz.info(); // needed until isInterface() triggers flag updates
        assert clazz.isInterface(): Debug.show(clazz);
	Type[] parents = clazz.parents();
	Global.instance.prevPhase();
        return ClassDef_(clazz, mkPrimaryConstrs(clazz.pos, parents), body);
    }

    /** Builds a ClassDef node for given class with given template. */
    public ClassDef ClassDef(Symbol clazz, Template template) {
        ClassDef tree = make.ClassDef(
            clazz.pos,
            clazz,
            mkTypeParamsOf(clazz),
            mkParamsOf(clazz),
            Tree.Empty,
            template);
        tree.setType(definitions.UNIT_TYPE);
        return tree;
    }

    /**
     * Builds a ClassDef node for given class with given parent
     * constructors, local symbol and body.
     */
    public ClassDef ClassDef(Symbol clazz, Tree[] constrs, Symbol local,
        Tree[] body)
    {
        Template templ = make.Template(local.pos, local, constrs, body);
        templ.setType(clazz.nextInfo()); // !!!
        return ClassDef(clazz, templ);
    }

    /** Builds a ValDef node for given symbol and with given rhs. */
    public ValDef ValDef(Symbol sym, Tree rhs) {
	ValDef tree = make.ValDef(
            sym.pos,
            sym,
            TypeTerm(sym.pos, sym.nextType()),
            rhs);
        tree.setType(definitions.UNIT_TYPE);
        return tree;
    }

    /** Builds a DefDef node for given symbol with given body. */
    public DefDef DefDef(Symbol sym, Tree body) {
        DefDef tree = make.DefDef(
            sym.pos,
            sym,
            mkTypeParamsOf(sym),
            mkParamsOf(sym),
            TypeTerm(sym.pos, sym.nextType().resultType()),
            body);
        tree.setType(definitions.UNIT_TYPE);
        return tree;
    }

    /** Builds an AbsTypeDef node for given symbol. */
    public AbsTypeDef AbsTypeDef(Symbol sym) {
	AbsTypeDef tree = make.AbsTypeDef(
	    sym.pos,
            sym,
            TypeTerm(sym.pos, sym.nextInfo()),
            TypeTerm(sym.pos, sym.loBound()));
        tree.setType(definitions.UNIT_TYPE);
        return tree;
    }

    /** Builds an AliasTypeDef node for given symbol. */
    public AliasTypeDef AliasTypeDef(Symbol sym) {
	AliasTypeDef tree = make.AliasTypeDef(
	    sym.pos,
	    sym,
            mkTypeParamsOf(sym),
	    TypeTerm(sym.pos, sym.nextInfo()));
        tree.setType(definitions.UNIT_TYPE);
        return tree;
    }

    //########################################################################
    //########################################################################
    //########################################################################

    //########################################################################
    // !!! to add

    /** Builds a Template node with given symbol, parents and body. */
    public Template Template(int pos, Symbol local, Tree[]parents, Tree[]body){
        Template tree = make.Template(pos, local, parents, body);
        tree.setType(Type.NoType);
        return tree;
    }
    public Template Template(Symbol local, Tree[] parents, Tree[] body) {
        return Template(local.pos, local, parents, body);
    }


    //########################################################################
    // !!! to remove

    public ClassDef ClassDef_(Symbol clazz, Tree[] constrs, Tree[] body) {
	return ClassDef(clazz, constrs, localDummy(clazz.pos, clazz), body);
    }


    public Tree Select__(Tree qual, Name name) {
	Symbol sym = qual.type.lookup(name);
	assert (sym.kind != NONE && sym != Symbol.ERROR) : name + " from " + qual.type;
	return Select(qual, sym);
    }

    //########################################################################
    // !!! not yet reviewed

    /** Create a dummy symbol to be used for templates.
     */
    public Symbol localDummy(int pos, Symbol owner) {
	return new TermSymbol(pos, Names.LOCAL(owner), owner, 0)
	    .setInfo(Type.NoType);
    }

    /** Build the expansion of (() => expr)
     */
    public Tree mkUnitFunction(Tree expr, Type type, Symbol owner) {
	return mkFunction(expr.pos, Tree.ValDef_EMPTY_ARRAY, expr, type, owner);
    }

    /** Build the expansion of ((vparams_1, ..., vparams_n) => body)
     *  with result type `restype', where `owner' is the previous owner
     *  of `body'.
     *  This is:
     *    { class $anon() extends scala.Object with
     *                            scala.Function_N[T_1, ..., T_n, restype] {
     *        def apply(vparams_1, ..., vparams_n) = body1
     *      }
     *	    new $anon()
     *    }
     *  where
     *    vparams_i: T_i
     *    `body1' results from `body' by changing owner of all defined
     *    symbols in `body' from `owner' to the apply method.
     */
    public Tree mkFunction(int pos, ValDef[] vparams, Tree body, Type restype,
			   Symbol owner) {
	int n = vparams.length;
	Symbol[] params = new Symbol[n];
	Type[] argtypes = new Type[n];
	for (int i = 0; i < n; i++) {
	    params[i] = vparams[i].symbol();
	    argtypes[i] = params[i].type();
	}
        Type[] parentTypes = {
            definitions.OBJECT_TYPE,
            definitions.functionType(argtypes, restype) };
	ClassSymbol clazz = new ClassSymbol(
	    pos, Names.ANON_CLASS_NAME.toTypeName(), owner, 0);
        clazz.setInfo(Type.compoundType(parentTypes, new Scope(), clazz));
	clazz.allConstructors().setInfo(
	    Type.MethodType(Symbol.EMPTY_ARRAY, clazz.typeConstructor()));

	Symbol applyMeth = new TermSymbol(pos, Names.apply, clazz, FINAL)
	    .setInfo(Type.MethodType(params, restype));
	clazz.info().members().enter(applyMeth);

	for (int i = 0; i < params.length; i++) {
	    params[i].setOwner(applyMeth);
	}
	changeOwner(body, owner, applyMeth);
        Tree[] parentTrees = mkPrimaryConstrs(pos, parentTypes);
        Tree[] memberTrees = { DefDef(applyMeth, body) };
        Tree classDef = ClassDef_(clazz, parentTrees, memberTrees);
	Tree alloc = New(pos, mkPrimaryConstr(pos, clazz))
            .setType(parentTypes[1]); // !!!
	return Block(new Tree[]{classDef, alloc});
    }


    public Tree mkPartialFunction(int pos, Tree applyVisitor, Tree isDefinedAtVisitor,
				  Type pattype, Type restype, Symbol owner) {
	ClassSymbol clazz = new ClassSymbol(
	    pos, Names.ANON_CLASS_NAME.toTypeName(), owner, 0);
        Type[] parentTypes = {
            definitions.OBJECT_TYPE,
            definitions.partialFunctionType(pattype, restype)};
	clazz.setInfo(Type.compoundType(parentTypes, new Scope(), clazz));
	clazz.allConstructors().setInfo(
	    Type.MethodType(Symbol.EMPTY_ARRAY, clazz.typeConstructor()));
        Tree[] parentTrees = mkPrimaryConstrs(pos, parentTypes);
        Tree[] memberTrees = {
            makeVisitorMethod(pos, Names.apply, applyVisitor,
                              pattype, restype, clazz, owner),
            makeVisitorMethod(pos, Names.isDefinedAt, isDefinedAtVisitor,
                              pattype, definitions.BOOLEAN_TYPE, clazz, owner)};
        Tree classDef = ClassDef_(clazz, parentTrees, memberTrees);
	Tree alloc = New(pos, mkPrimaryConstr(pos, clazz))
	    .setType(parentTypes[1]); // !!!
	return Block(new Tree[]{classDef, alloc});
    }
    //where
	private Tree makeVisitorMethod(int pos, Name name, Tree visitor,
				       Type pattype, Type restype,
				       Symbol clazz, Symbol prevOwner) {
	    Symbol meth = new TermSymbol(pos, name, clazz, FINAL);
	    Symbol param = new TermSymbol(pos, Name.fromString("x$"), meth, PARAM)
		.setInfo(pattype);
	    meth.setInfo(Type.MethodType(new Symbol[]{param}, restype));
	    clazz.info().members().enter(meth);
	    changeOwner(visitor, prevOwner, meth);
	    Tree body =
		mkApply(
                    Select(Ident(pos, param), definitions.MATCH),
                    new Tree[]{mkType(pos, pattype), mkType(pos, restype)},
                    new Tree[]{visitor});
	    return DefDef(meth, body);
	}

    /** Change owner of all defined symbols from `prevOwner' to `newOwner'
     */
    public void changeOwner(Tree tree, final Symbol prevOwner, final Symbol newOwner) {
	Traverser lifter = new Traverser() {
	    public void traverse(Tree tree) {
		if (TreeInfo.isDefinition(tree)) {
		    Symbol sym = tree.symbol();
                    if (sym != null && sym.owner() == prevOwner) {
			sym.setOwner(newOwner);
                    }
		}
		super.traverse(tree);
	    }
	};
	lifter.traverse(tree);
    }

    /** Build a postfix function application
     */
    public Tree postfixApply(Tree obj, Tree fn, Symbol owner) {
	if (TreeInfo.isPureExpr(obj) || TreeInfo.isPureExpr(fn)) {
	    return Apply(Select__(fn, Names.apply), new Tree[]{obj});
	} else {
	    Name tmpname = global.freshNameCreator.newName("tmp", '$');
	    Symbol tmp = new TermSymbol(
		obj.pos, tmpname, owner, SYNTHETIC | FINAL)
		.setInfo(obj.type);
	    Tree tmpdef = ValDef(tmp, obj);
	    Tree expr = postfixApply(Ident(obj.pos, tmp), fn, owner);
	    return Block(new Tree[]{tmpdef, expr});
	}
    }
}