summaryrefslogtreecommitdiff
path: root/sources/scala/tools/nsc/typechecker/Contexts.scala
blob: 65e8b0925d935f25c3a5183243183e55520192ed (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
/* NSC -- new scala compiler
 * Copyright 2005 LAMP/EPFL
 * @author  Martin Odersky
 */
// $Id$
package scala.tools.nsc.typechecker;

import scala.tools.util.Position;

class Contexts: Analyzer {
  import global._;

  val NoContext = new Context {
    override def imports: List[ImportInfo] = List();
  }

  val startContext = {
    import definitions._;
    var sc = NoContext.make(
      Template(List(), List()) setSymbol NoSymbol setType NoType,
      definitions.RootClass,
      definitions.RootClass.info.decls);
    def addImport(pkg: Symbol): unit = {
      val impTree = Import(gen.mkGlobalRef(pkg), List(Pair(nme.WILDCARD, null)))
        setSymbol NoSymbol.newImport(Position.NOPOS).setInfo(pkg.tpe)
        setType NoType;
      sc = sc.make(
	Template(List(), List(impTree)) setSymbol NoSymbol setType NoType, sc.owner, sc.scope)
    }
    if (!settings.noimports.value) {
      addImport(JavaLangPackage);
      addImport(ScalaPackage);
      if (!settings.nopredefs.value)
	addImport(PredefModule);
    }
    sc
  }

  class Context {
    var unit: CompilationUnit = _;
    var tree: Tree = _;                     // Tree associated with this context
    var owner: Symbol = _;                  // The current owner
    var scope: Scope = _;                   // The current scope
    var outer: Context = _;                 // The next outer context
    var enclClass: Context = _;             // The next outer context whose tree is a
                                            // template or package definition
    var variance: int = _;                  // Variance relative to enclosing class.
    private var _undetparams: List[Symbol] = List(); // Undetermined type parameters
    var depth: int = 0;

    def undetparams = _undetparams;
    def undetparams_=(ps: List[Symbol]) = {
      System.out.println("undetparams = " + ps);
      _undetparams = ps
    }

    def make(unit: CompilationUnit, tree: Tree, owner: Symbol, scope: Scope): Context = {
      val c = new Context();
      c.unit = unit;
      c.tree = tree;
      c.owner = owner;
      c.scope = scope;
      c.enclClass = tree match {
        case Template(_, _) | PackageDef(_, _) => c
        case _ => this.enclClass
      }
      c.variance = this.variance;
      c.depth = this.depth + 1;
      c.outer = this;
      c
    }

    def make(unit: CompilationUnit): Context =
      make(unit, EmptyTree, this.owner, this.scope);

    def make(tree: Tree, owner: Symbol, scope: Scope): Context =
      make(this.unit, tree, owner, scope);

    def makeNewScope(tree: Tree, owner: Symbol): Context =
      make(tree, owner, new Scope(this.scope));

    def make(tree: Tree, owner: Symbol): Context =
      make(tree, owner, this.scope);

    def make(tree: Tree): Context =
      make(tree, this.owner);

    def outerContext(clazz: Symbol): Context = {
      var c = this;
      while (c != NoContext && c.owner != clazz) c = c.outer.enclClass;
      c
    }

    def isLocal(): boolean = tree match {
      case Block(_,_) => true
      case PackageDef(_, _) => false
      case EmptyTree => false
      case _ => outer.isLocal()
    }

    override def toString(): String = {
      if (this == NoContext) "NoContext";
      else tree.toString() + "\n:: " + outer.toString()
    }

    private var importsCache: List[ImportInfo] = null;

    def imports: List[ImportInfo] = {
      def collectImports(stats: List[Tree]): List[ImportInfo] = stats match {
        case Nil => outer.imports
        case (imp @ Import(_, _)) :: rest => new ImportInfo(imp, depth) :: collectImports(rest)
        case _ :: rest => collectImports(rest)
      }
      if (importsCache == null) {
        importsCache = tree match {
          case PackageDef(_, stats) => collectImports(stats)
          case Template(_, stats) => collectImports(stats)
          case Block(stats, _) => collectImports(stats)
          case _ => outer.imports
        }
      }
      importsCache
    }
  }

  class ImportInfo(val tree: Import, val depth: int) {

    /** Is name imported explicitly, not via wildcard? */
    def isExplicitImport(name: Name): boolean =
      tree.selectors exists (._2.==(name.toTermName));

    /** The symbol with name `name' imported from import clause `tree'.
     */
    def importedSymbol(name: Name): Symbol = {
      var result: Symbol = NoSymbol;
      var renamed = false;
      var selectors = tree.selectors;
      while (selectors != Nil && result == NoSymbol) {
        if (selectors.head._2 == name.toTermName)
	  result = tree.expr.symbol.info.member(
            if (name.isTypeName) selectors.head._1.toTypeName else selectors.head._1);
        else if (selectors.head._1 == name.toTermName)
          renamed = true
        else if (selectors.head._1 == nme.WILDCARD && !renamed)
          result = tree.expr.symbol.info.member(name);
        selectors = selectors.tail
      }
      result
    }

    override def toString() = tree.toString();
  }
}