summaryrefslogblamecommitdiff
path: root/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
blob: f0eafea67efb3c244b474c524900b6f67471cc2e (plain) (tree)
1
2
3
4
5
6
7
8
9
10






                                    
                                           

                          



                                                                              

                                                                            

                                                                                 










                                                                         
                                                                                                   
 
                                                                        

                                                                       


                                                                                    

                                                                                  

                                                                           



                          
                                                           
                                     

                                          

                                                                              
                             
                                             

                            

                             





                                                                  











                                                                                                                    
                                               
                              
                               



                                                                              
                                                                                                              

                                                                                                           
                                                         
                                                                                       

                                                                             
                                     
                                                                                                                


                                                  

                                                        



                                                                              
                                                                           

                   





                                                                               


                             












                                                              

   
/* NSC -- new scala compiler
 * Copyright 2005 LAMP/EPFL
 * @author
 */
// $Id$
package scala.tools.nsc.typechecker;

import scala.collection.mutable.ListBuffer;
import nsc.symtab.Flags._;

/** This phase adds super accessors for all super calls that
 *  either appear in a trait or have as a target a member of some outer class.
 *  It also replaces references to parameter accessors with aliases by super
 *  references to these aliases.
 *  The phase also checks that symbols accessed from super are not abstract,
 *  or are overridden by an abstract override.
 *  Finally, the phase also mangles the names of class-members which are private
 *  up to an enclosing non-package class, in order to avoid overriding conflicts.
 */
abstract class SuperAccessors extends transform.Transform {
  // inherits abstract value `global' and class `Phase' from Transform

  import global._;
  import posAssigner.atPos;
  import typer.typed;

  /** the following two members override abstract members in Transform */
  val phaseName: String = "superaccessors";

  protected def newTransformer(unit: CompilationUnit): Transformer = new SuperAccTransformer(unit);

  class SuperAccTransformer(unit: CompilationUnit) extends Transformer {
    private var validCurrentOwner = true;
    private var accDefs: List[Pair[Symbol, ListBuffer[Tree]]] = List();

    private def accDefBuf(clazz: Symbol) = accDefs.dropWhile(._1.!=(clazz)).head._2;

    private def transformArgs(args: List[Tree], formals: List[Type]) = {
      if (!formals.isEmpty && formals.last.symbol == definitions.ByNameParamClass)
        ((args take (formals.length - 1) map transform) :::
         withInvalidOwner { args drop (formals.length - 1) map transform })
      else
        args map transform
    }

    override def transform(tree: Tree): Tree = tree match {
      case ClassDef(_, _, _, _, _) =>
        val decls = tree.symbol.info.decls
        for (val sym <- decls.toList) {
          if (sym.privateWithin.isClass && !sym.privateWithin.isModuleClass &&
              !sym.hasFlag(EXPANDEDNAME)) {
            decls.unlink(sym)
            sym.expandName(sym.privateWithin)
            decls.enter(sym)
          }
        }
        super.transform(tree)
      case Template(parents, body) =>
	val ownAccDefs = new ListBuffer[Tree];
	accDefs = Pair(currentOwner, ownAccDefs) :: accDefs;
	val body1 = transformTrees(body);
	accDefs = accDefs.tail;
	copy.Template(tree, parents, ownAccDefs.toList ::: body1);
      case Select(qual @ This(_), name) =>
        val sym = tree.symbol;
 	if ((sym hasFlag PARAMACCESSOR) && (sym.alias != NoSymbol)) {
          val result = typed {
            Select(
              Super(qual.symbol, nme.EMPTY.toTypeName/*qual.symbol.info.parents.head.symbol.name*/) setPos qual.pos,
              sym.alias) setPos tree.pos
          }
	  if (settings.debug.value)
	    System.out.println("alias replacement: " + tree + " ==> " + result);//debug
          transform(result)
        } else tree
      case Select(sup @ Super(_, mix), name) =>
        val sym = tree.symbol;
	val clazz = sup.symbol;
        if (sym hasFlag DEFERRED) {
	  val member = sym.overridingSymbol(clazz);
	  if (mix != nme.EMPTY.toTypeName || member == NoSymbol ||
	      !((member hasFlag ABSOVERRIDE) && member.isIncompleteIn(clazz)))
	    unit.error(tree.pos, ""+sym+sym.locationString+" is accessed from super. It may not be abstract "+
                                 "unless it is overridden by a member declared `abstract' and `override'");
        }
	if (tree.isTerm && mix == nme.EMPTY.toTypeName &&
	    (clazz.isTrait || clazz != currentOwner.enclClass || !validCurrentOwner)) {
	  val supername = nme.superName(sym.name);
	  var superAcc = clazz.info.decl(supername).suchThat(.alias.==(sym));
	  if (superAcc == NoSymbol) {
	    if (settings.debug.value) log("add super acc " + sym + sym.locationString + " to `" + clazz);//debug
            superAcc =
              clazz.newMethod(tree.pos, supername)
		.setFlag(SUPERACCESSOR | PRIVATE)
		.setInfo(clazz.thisType.memberType(sym))
		.setAlias(sym)
            clazz.info.decls enter superAcc;
	    accDefBuf(clazz) += typed(DefDef(superAcc, vparamss => EmptyTree))
	  }
	  atPos(sup.pos) {
	    Select(gen.mkAttributedThis(clazz), superAcc) setType tree.tpe;
	  }
	} else tree
      case Apply(fn, args) =>
        copy.Apply(tree, transform(fn), transformArgs(args, fn.tpe.paramTypes))
      case Function(vparams, body) =>
        withInvalidOwner {
          copy.Function(tree, vparams, transform(body))
        }
      case _ =>
        super.transform(tree)
    }

    override def atOwner[A](owner: Symbol)(trans: => A): A = {
      if (owner.isClass) validCurrentOwner = true;
      super.atOwner(owner)(trans)
    }

    private def withInvalidOwner[A](trans: => A): A = {
      val prevValidCurrentOwner = validCurrentOwner;
      validCurrentOwner = false;
      val result = trans;
      validCurrentOwner = prevValidCurrentOwner;
      result
    }
  }
}