root/trunk/ProjectFortress/src/com/sun/fortress/scala_src/typechecker/STypeChecker.scala @ 3834

Revision 3834, 72.8 KB (checked in by sukyoungryu, 6 months ago)

[type checker] Fixed small things in the Scala type checker. Moved three tests from not_working_static_tests to compiler_tests.

Line 
1/*******************************************************************************
2    Copyright 2009 Sun Microsystems, Inc.,
3    4150 Network Circle, Santa Clara, California 95054, U.S.A.
4    All rights reserved.
5
6    U.S. Government Rights - Commercial software.
7    Government users are subject to the Sun Microsystems, Inc. standard
8    license agreement and applicable provisions of the FAR and its supplements.
9
10    Use is subject to license terms.
11
12    This distribution may include materials developed by third parties.
13
14    Sun, Sun Microsystems, the Sun logo and Java are trademarks or registered
15    trademarks of Sun Microsystems, Inc. in the U.S. and other countries.
16 ******************************************************************************/
17
18package com.sun.fortress.scala_src.typechecker
19
20import _root_.java.util.{List => JavaList}
21import _root_.java.util.{Map => JavaMap}
22import _root_.java.util.{HashMap => JavaHashMap}
23import _root_.java.util.{Set => JavaSet}
24import edu.rice.cs.plt.tuple.{Option => JavaOption}
25import edu.rice.cs.plt.collect.EmptyRelation
26import edu.rice.cs.plt.collect.IndexedRelation
27import edu.rice.cs.plt.collect.Relation
28import edu.rice.cs.plt.collect.UnionRelation
29import com.sun.fortress.compiler.IndexBuilder
30import com.sun.fortress.compiler.disambiguator.ExprDisambiguator.HierarchyHistory
31import com.sun.fortress.compiler.index.CompilationUnitIndex
32import com.sun.fortress.compiler.index.{FunctionalMethod => JavaFunctionalMethod}
33import com.sun.fortress.compiler.index.Method
34import com.sun.fortress.compiler.index.ObjectTraitIndex
35import com.sun.fortress.compiler.index.ProperTraitIndex
36import com.sun.fortress.compiler.index.TraitIndex
37import com.sun.fortress.compiler.index.TypeConsIndex
38import com.sun.fortress.compiler.typechecker.TypeNormalizer
39import com.sun.fortress.compiler.typechecker.StaticTypeReplacer
40import com.sun.fortress.compiler.typechecker.TypeAnalyzer
41import com.sun.fortress.compiler.typechecker.TypeEnv
42import com.sun.fortress.compiler.Types
43import com.sun.fortress.exceptions.InterpreterBug.bug
44import com.sun.fortress.exceptions.StaticError
45import com.sun.fortress.exceptions.StaticError.errorMsg
46import com.sun.fortress.exceptions.TypeError
47import com.sun.fortress.nodes._
48import com.sun.fortress.nodes_util.NodeFactory
49import com.sun.fortress.nodes_util.ExprFactory
50import com.sun.fortress.nodes_util.NodeUtil
51import com.sun.fortress.nodes_util.OprUtil
52import com.sun.fortress.scala_src.typechecker.ScalaConstraintUtil._
53import com.sun.fortress.scala_src.nodes._
54import com.sun.fortress.scala_src.useful.ASTGenHelper._
55import com.sun.fortress.scala_src.useful.ErrorLog
56import com.sun.fortress.scala_src.useful.Lists._
57import com.sun.fortress.scala_src.useful.Options._
58import com.sun.fortress.scala_src.useful.Sets._
59import com.sun.fortress.scala_src.useful.SExprUtil._
60import com.sun.fortress.scala_src.useful.STypesUtil._
61import com.sun.fortress.useful.HasAt
62import com.sun.fortress.useful.NI
63
64/* Quesitons
65 */
66/* Invariants
67 * 1. If a subexpression does not have any inferred type,
68 *    type checking the subexpression failed.
69 */
70object STypeCheckerFactory {
71  def make(current: CompilationUnitIndex, traits: TraitTable, env: TypeEnv,
72           analyzer: TypeAnalyzer) =
73    new STypeChecker(current, traits, env, analyzer, new ErrorLog())
74  def make(current: CompilationUnitIndex, traits: TraitTable, env: TypeEnv,
75           analyzer: TypeAnalyzer, errors: ErrorLog) =
76    new STypeChecker(current, traits, env, analyzer, errors)
77}
78
79class STypeChecker(current: CompilationUnitIndex, traits: TraitTable,
80                   env: TypeEnv, analyzer: TypeAnalyzer, errors: ErrorLog) {
81
82  private var labelExitTypes: JavaMap[Id, JavaOption[JavaSet[Type]]] =
83    new JavaHashMap[Id, JavaOption[JavaSet[Type]]]()
84
85  private def addSelf(self_type: Type) =
86    extend(List[LValue](NodeFactory.makeLValue("self", self_type)))
87
88  private def extend(newEnv: TypeEnv, newAnalyzer: TypeAnalyzer) =
89    STypeCheckerFactory.make(current, traits, newEnv, newAnalyzer, errors)
90
91  private def extend(bindings: List[LValue]) =
92    STypeCheckerFactory.make(current, traits,
93                             env.extendWithLValues(toJavaList(bindings)),
94                             analyzer, errors)
95
96  private def extend(sparams: List[StaticParam], where: Option[WhereClause]) =
97    STypeCheckerFactory.make(current, traits,
98                             env.extendWithStaticParams(sparams),
99                             analyzer.extend(sparams, where), errors)
100
101  private def extend(sparams: List[StaticParam], params: Option[List[Param]],
102                     where: Option[WhereClause]) = params match {
103    case Some(ps) =>
104      STypeCheckerFactory.make(current, traits,
105                               env.extendWithParams(ps).extendWithStaticParams(sparams),
106                               analyzer.extend(sparams, where), errors)
107    case None =>
108      STypeCheckerFactory.make(current, traits,
109                               env.extendWithStaticParams(sparams),
110                               analyzer.extend(sparams, where), errors)
111  }
112
113  private def extendWithFunctions(methods: Relation[IdOrOpOrAnonymousName, JavaFunctionalMethod]) =
114    STypeCheckerFactory.make(current, traits, env.extendWithFunctions(methods),
115                             analyzer, errors)
116
117  private def extendWithMethods(methods: Relation[IdOrOpOrAnonymousName, Method]) =
118    STypeCheckerFactory.make(current, traits, env.extendWithMethods(methods),
119                             analyzer, errors)
120
121  private def extendWithout(declSite: Node, names: JavaSet[Id]) =
122    STypeCheckerFactory.make(current, traits, env.extendWithout(declSite, names),
123                             analyzer, errors)
124
125  private def noType(hasAt:HasAt) =
126    signal(hasAt, errorMsg("Type is not inferred for: ", hasAt))
127
128  protected def signal(msg:String, hasAt:HasAt) =
129    errors.signal(msg, hasAt)
130
131  protected def signal(hasAt:HasAt, msg:String) =
132    errors.signal(msg, hasAt)
133
134  /**
135   * Determine if subtype <: supertype. If false, then the given error message
136   * is signaled for the given location.
137   */
138  private def isSubtype(subtype:Type, supertype:Type, location:HasAt, error:String): Boolean = {
139    val judgement = isSubtype(subtype, supertype)
140    if (! judgement) signal(error, location)
141    judgement
142  }
143
144  /**
145   * Determine if subtype <: supertype.
146   */
147  private def isSubtype(subtype:Type, supertype:Type): Boolean
148    = analyzer.subtype(subtype, supertype).isTrue
149
150  /**
151   * Return the conditions for subtype <: supertype to hold.
152   */
153  private def checkSubtype(subtype:Type, supertype:Type): ScalaConstraint =
154    analyzer.subtype(subtype, supertype).asInstanceOf[ScalaConstraint]
155
156  private def equivalentTypes(t1: Type, t2: Type): Boolean =
157    analyzer.equivalent(t1, t2).isTrue
158
159  private def normalize(ty: Type): Type =
160    TypeNormalizer.normalize(ty)
161
162  /**
163   * Replaces the given name with the name it aliases
164   * (or leaves it alone if it doesn't alias any thing)
165   */
166  private def handleAlias(name: Id, imports: List[Import]): Id = name match {
167    case SId(_, Some(api), _) =>
168
169      // Get the alias for `name` from this import, if it exists.
170      def getAlias(imp: Import): Option[Id] = imp match {
171        case SImportNames(_, _, aliasApi, aliases) if api.equals(aliasApi) =>
172
173          // Get the name from an aliased name.
174          def getName(aliasedName: AliasedSimpleName): Option[Id] =
175            aliasedName match {
176              case SAliasedSimpleName(_, newName, Some(alias))
177                if alias.equals(name) => Some(newName.asInstanceOf)
178              case _ => None
179            }
180
181          // Get the first name that matched.
182          aliases.flatMap(getName).firstOption
183        case _ => None
184      }
185
186      // Get the first name that matched within any import, or return name.
187      imports.flatMap(getAlias).firstOption.getOrElse(name)
188    case _ => name
189  }
190
191  /**
192   * Get the TypeEnv that corresponds to this API.
193   */
194  private def getEnvFromApi(api: APIName): TypeEnv =
195    TypeEnv.make(traits.compilationUnit(api))
196
197  /**
198   * Lookup the type of the given name in the proper type environment.
199   */
200  private def getTypeFromName(name: Name): Option[Type] = name match {
201    case id@SId(_, Some(api), _) => toOption(getEnvFromApi(api).getType(id))
202    case id@SId(_, None, _) => toOption(env.getType(id))
203    case _ => None
204  }
205
206  def getErrors(): List[StaticError] = errors.errors
207
208  /**
209   * Signal an error if the given type is not a trait.
210   */
211  private def assertTrait(t: BaseType, msg: String, error_loc: Node) = t match {
212    case tt:TraitType => toOption(traits.typeCons(tt.getName)) match {
213      case Some(ti) if ti.isInstanceOf[ProperTraitIndex] =>
214      case _ => signal(error_loc, msg)
215    }
216    case SAnyType(info) =>
217    case _ => signal(error_loc, msg)
218  }
219
220  // TODO: Rewrite this method!
221  private def inheritedMethods(extendedTraits: List[TraitTypeWhere]) =
222    inheritedMethodsHelper(new HierarchyHistory(), extendedTraits)
223
224  // Return all of the methods from super-traits
225  private def inheritedMethodsHelper(history: HierarchyHistory,
226                                     extended_traits: List[TraitTypeWhere])
227                                    : Relation[IdOrOpOrAnonymousName, Method] = {
228    var methods = new IndexedRelation[IdOrOpOrAnonymousName, Method](false)
229    var done = false
230    var h = history
231    for ( trait_ <- extended_traits ; if (! done) ) {
232      val type_ = trait_.getBaseType
233      if ( ! h.hasExplored(type_) ) {
234        h = h.explore(type_)
235        type_ match {
236          case ty@STraitType(_, name, _, params) =>
237            toOption(traits.typeCons(name)) match {
238              case Some(ti) =>
239                if ( ti.isInstanceOf[TraitIndex] ) {
240                  val trait_params = ti.staticParameters
241                  val trait_args = ty.getArgs
242                  // Instantiate methods with static args
243                  val dotted = toSet(ti.asInstanceOf[TraitIndex].dottedMethods).map(t => (t.first, t.second))
244                  for ( pair <- dotted ) {
245                      methods.add(pair._1,
246                                  pair._2.instantiate(trait_params,trait_args).asInstanceOf[Method])
247                  }
248                  val getters = ti.asInstanceOf[TraitIndex].getters
249                  for ( getter <- toSet(getters.keySet) ) {
250                      methods.add(getter,
251                                  getters.get(getter).instantiate(trait_params,trait_args).asInstanceOf[Method])
252                  }
253                  val setters = ti.asInstanceOf[TraitIndex].setters
254                  for ( setter <- toSet(setters.keySet) ) {
255                      methods.add(setter,
256                                  setters.get(setter).instantiate(trait_params,trait_args).asInstanceOf[Method])
257                  }
258                  val paramsToArgs = new StaticTypeReplacer(trait_params, trait_args)
259                  val instantiated_extends_types =
260                    toList(ti.asInstanceOf[TraitIndex].extendsTypes).map( (t:TraitTypeWhere) =>
261                          t.accept(paramsToArgs).asInstanceOf[TraitTypeWhere] )
262                  methods.addAll(inheritedMethodsHelper(h, instantiated_extends_types))
263                } else done = true
264              case _ => done = true
265            }
266          case _ => done = true
267        }
268      }
269    }
270    methods
271  }
272
273  /**
274   * Given a type, which could be a VarType, Intersection or Union, return the TraitTypes
275   * that this type could be used as for the purposes of calling methods and fields.
276   */
277  private def traitTypesCallable(typ: Type): Set[TraitType] = typ match {
278    case t:TraitType => Set(t)
279
280    // Combine all the trait types callable from constituents.
281    case typ:IntersectionType =>
282      conjuncts(typ).filter(NodeUtil.isTraitType).flatMap(traitTypesCallable)
283
284    // Get the trait types callable from the upper bounds of this parameter.
285    case SVarType(_, name, _) => toOption(env.staticParam(name)) match {
286      case Some(s@SStaticParam(_, _, ts, _, _, SKindType(_))) =>
287        Set(ts:_*).filter(NodeUtil.isTraitType).flatMap(traitTypesCallable)
288      case _ => Set.empty[TraitType]
289    }
290
291    case SUnionType(_, ts) =>
292      signal(typ, errorMsg("You should be able to call methods on this type,",
293                           "but this is not yet implemented."))
294      Set.empty[TraitType]
295
296    case _ => Set.empty[TraitType]
297  }
298
299  /**
300   * Not yet implemented.
301   * Waiting for _RewriteFnApp to be implemented.
302   */
303  private def findMethodsInTraitHierarchy(methodName: IdOrOpOrAnonymousName,
304                                          receiverType: Type):
305                                              Set[Method] = {
306
307    val traitTypes = traitTypesCallable(receiverType)
308    val ttAsWheres = traitTypes.map(NodeFactory.makeTraitTypeWhere)
309    val allMethods = inheritedMethods(ttAsWheres.toList)
310    toSet(allMethods.matchFirst(methodName))
311  }
312
313  /**
314   * The Java type checker had a separate postinference pass "closing bindings".
315   * @TODO: Look over this method.
316   */
317  private def generatorClauseGetBindings(clause: GeneratorClause,
318                                         mustBeCondition: Boolean) = clause match {
319    case SGeneratorClause(info, binds, init) =>
320      val newInit = checkExpr(init)
321      val err = errorMsg("Filter expressions in generator clauses must have type Boolean, ",
322                         "but ", init)
323      getType(newInit) match {
324        case None =>
325          signal(init, errorMsg(err, " was not well typed."))
326          (SGeneratorClause(info, Nil, newInit), Nil)
327        case Some(ty) =>
328          isSubtype(ty, Types.BOOLEAN, init, errorMsg(err, " had type ", normalize(ty), "."))
329          binds match {
330            case Nil =>
331              // If bindings are empty, then init must be of type Boolean, a filter, 13.14
332              (SGeneratorClause(info, Nil, newInit), Nil)
333            case hd::tl =>
334              def mkInferenceVarType(id: Id) =
335                NodeFactory.make_InferenceVarType(NodeUtil.getSpan(id))
336              val (lhstype, bindings) = binds.length match {
337                case 1 => // Just one binding
338                  val lhstype = mkInferenceVarType(hd)
339                  (lhstype, List[LValue](NodeFactory.makeLValue(hd, lhstype)))
340                case n =>
341                  // Because generator_type is almost certainly an _InferenceVar,
342                  // we have to declare a new tuple that is the size of the bindings
343                  // and declare one to be a subtype of the other.
344                  val inference_vars = binds.map(mkInferenceVarType)
345                  (Types.makeTuple(toJavaList(inference_vars)),
346                   binds.zip(inference_vars).map((p:(Id,Type)) =>
347                                                 NodeFactory.makeLValue(p._1,p._2)))
348              }
349              // Get the type of the Generator
350              val infer_type = NodeFactory.make_InferenceVarType(NodeUtil.getSpan(init))
351              val generator_type = if (mustBeCondition)
352                                     Types.makeConditionType(infer_type)
353                                   else Types.makeGeneratorType(infer_type)
354              isSubtype(ty, generator_type, init,
355                        errorMsg("Init expression of generator must be a subtype of ",
356                                 (if (mustBeCondition) "Condition" else "Generator"),
357                                 " but is type ", normalize(ty), "."))
358              val err = errorMsg("If more than one variable is bound in a generator, ",
359                                 "generator must have tuple type but ", init,
360                                 " does not or has different number of arguments.")
361              isSubtype(lhstype, generator_type, init, err)
362              isSubtype(generator_type, lhstype, init, err)
363              (SGeneratorClause(info, binds, newInit), bindings)
364          }
365      }
366  }
367
368  /**
369   * @TODO: Look over this method.
370   */
371  private def handleIfClause(c: IfClause) = c match {
372    case SIfClause(info, testClause, body) =>
373      // For generalized 'if' we must introduce new bindings.
374      val (newTestClause, bindings) = generatorClauseGetBindings(testClause, true)
375      // Check body with new bindings
376      val newBody = this.extend(bindings).checkExpr(body).asInstanceOf[Block]
377      getType(newBody) match {
378        case None => noType(body)
379        case _ =>
380      }
381      SIfClause(info, newTestClause, newBody)
382  }
383
384  // For each generator clause, check its body,
385  // then put its variables in scope for the next generator clause.
386  // Finally, return all of the bindings so that they can be put in scope
387  // in some larger expression, like the body of a for loop, for example.
388  // @TODO: Look over this method.
389  def handleGens(generators: List[GeneratorClause]): (List[GeneratorClause], List[LValue]) =
390    generators match {
391      case Nil => (Nil, Nil)
392      case hd::Nil =>
393        val (clause, binds) = generatorClauseGetBindings(hd, false)
394        (List[GeneratorClause](clause), binds)
395      case hd::tl =>
396        val (clause, binds) = generatorClauseGetBindings(hd, false)
397        val (newTl, tlBinds) = this.extend(binds).handleGens(tl)
398        (clause::newTl, binds++tlBinds)
399    }
400
401  /**
402   * Determines if the given overloading is dynamically applicable.
403   */
404  private def isDynamicallyApplicable(overloading: Overloading,
405                              smaArrow: ArrowType,
406                              inferredStaticArgs: List[StaticArg]): Boolean = {
407    // Is this arrow type applicable.
408    def arrowTypeIsApplicable(overloadingType: ArrowType): Boolean = {
409      val typ =
410        // If static args given, then instantiate the overloading first.
411        if (inferredStaticArgs.isEmpty) overloadingType
412        else staticInstantiation(inferredStaticArgs,
413                                 overloadingType).getOrElse(return false).
414                                           asInstanceOf[ArrowType]
415      isSubtype(typ.getDomain, smaArrow.getDomain)
416    }
417
418    // If overloading type is an intersection, check that any of its
419    // constituents is applicable.
420    conjuncts(toOption(overloading.getType).get).
421      map(_.asInstanceOf[ArrowType]).
422      exists(arrowTypeIsApplicable)
423  }
424
425  /**
426   * Calls the other overloading with the conjuncts of the given function type.
427   */
428  private def staticallyMostApplicableArrow(fnType: Type,
429                                            argType: Type,
430                                            expectedType: Option[Type]):
431                                      Option[(ArrowType, List[StaticArg])] = {
432
433    val arrows = conjuncts(fnType).toList.map(_.asInstanceOf[ArrowType])
434    staticallyMostApplicableArrow(arrows, argType, expectedType)
435  }
436
437  /**
438   * Return the statically most applicable arrow type along with the static args
439   * that instantiated that arrow type. This method assumes that all the arrow
440   * types in fnType have already been instantiated if any static args were
441   * supplied.
442   */
443  private def staticallyMostApplicableArrow(allArrows: List[ArrowType],
444                                            argType: Type,
445                                            expectedType: Option[Type]):
446                                        Option[(ArrowType, List[StaticArg])] = {
447
448    // Filter applicable arrows and their instantiated args.
449    val arrowsAndInstantiations =
450      allArrows.flatMap(ty => checkApplicable(ty.asInstanceOf[ArrowType],
451                                              argType,
452                                              expectedType))
453
454    // Define an ordering relation on arrows with their instantiations.
455    def lessThan(overloading1: (ArrowType, List[StaticArg]),
456                 overloading2: (ArrowType, List[StaticArg])): Boolean = {
457
458      val SArrowType(_, domain1, range1, _) = overloading1
459      val SArrowType(_, domain2, range2, _) = overloading2
460
461      if (equivalentTypes(domain1, domain2)) false
462      else isSubtype(domain1, domain2)
463    }
464
465    // Sort the arrows and instantiations to find the statically most
466    // applicable. Return None if none were applicable.
467    arrowsAndInstantiations.sort(lessThan).firstOption
468  }
469
470  /**
471   * Identical to the overloading but with an explicitly given list of static
472   * parameters.
473   */
474  private def staticInstantiation(sargs: List[StaticArg],
475                          sparams: List[StaticParam],
476                          body: Type): Option[Type] = {
477
478    // Check that the args match.
479    if (!staticArgsMatchStaticParams(sargs, sparams)) return None
480
481    // Create mapping from parameter names to static args.
482    val paramMap = Map(sparams.map(_.getName).zip(sargs): _*)
483
484    // Gets the actual value out of a static arg.
485    def sargToVal(sarg: StaticArg): Node = sarg match {
486      case sarg:TypeArg => sarg.getTypeArg
487      case sarg:IntArg => sarg.getIntVal
488      case sarg:BoolArg => sarg.getBoolArg
489      case sarg:OpArg => sarg.getName
490      case sarg:DimArg => sarg.getDimArg
491      case sarg:UnitArg => sarg.getUnitArg
492      case _ => bug("unexpected kind of static arg")
493    }
494
495    // Replaces all the params with args in a node.
496    object staticReplacer extends Walker {
497      override def walk(node: Any): Any = node match {
498        case n:VarType => paramMap.get(n.getName).map(sargToVal).getOrElse(n)
499        // TODO: Check proper name for OpArgs.
500        case n:OpArg => paramMap.get(n.getName.getOriginalName).getOrElse(n)
501        case n:IntRef => paramMap.get(n.getName).map(sargToVal).getOrElse(n)
502        case n:BoolRef => paramMap.get(n.getName).map(sargToVal).getOrElse(n)
503        case n:DimRef => paramMap.get(n.getName).map(sargToVal).getOrElse(n)
504        case n:UnitRef => paramMap.get(n.getName).map(sargToVal).getOrElse(n)
505        case _ => super.walk(node)
506      }
507    }
508
509    // Get the replaced type and clear out its static params, if any.
510    Some(clearStaticParams(staticReplacer(body).asInstanceOf[Type]))
511  }
512
513  /**
514   * Instantiates a generic type with some static arguments. The static
515   * parameters are retrieved from the body type and replaced inside body with
516   * their corresponding static arguments. In the end, any static parameters
517   * in the replaced type will be cleared.
518   *
519   * @param args A list of static arguments to apply to the generic type body.
520   * @param body The generic type whose static parameters are to be replaced.
521   * @return An option of a type identical to body but with every occurrence of
522   *         one of its declared static parameters replaced by corresponding
523   *         static args. If None, then the instantiation failed.
524   */
525  private def staticInstantiation(sargs: List[StaticArg],
526                          body: Type): Option[Type] =
527    staticInstantiation(sargs, getStaticParams(body), body)
528
529  /**
530   * Checks whether an arrow type if applicable to the given args. If so, then
531   * the [possible instantiated] arrow type along with any inferred statics args
532   * are returned.
533   */
534  private def checkApplicable(fnType: ArrowType,
535                              argType: Type,
536                              expectedType: Option[Type]):
537                                Option[(ArrowType, List[StaticArg])] = {
538    val sparams = getStaticParams(fnType)
539
540    // Substitute inference variables for static parameters in fnType.
541
542    // 1. build substitution S = [T_i -> $T_i]
543    // 2. instantiate fnType with S to get an arrow type with inf vars, infArrow
544    val sargs = sparams.map(makeInferenceArg)
545    val infArrow = staticInstantiation(sargs, sparams, fnType).
546      getOrElse(return None).asInstanceOf[ArrowType]
547
548    // 3. argType <:? dom(infArrow) yields a constraint, C1
549    val domainConstraint = checkSubtype(argType, infArrow.getDomain)
550
551    // 4. if expectedType given, C := C1 AND range(infArrow) <:? expectedType
552    val rangeConstraint = expectedType.map(
553      t => checkSubtype(infArrow.getRange, t)).getOrElse(TRUE_FORMULA)
554    val constraint = domainConstraint.scalaAnd(rangeConstraint, isSubtype)
555
556    // Get an inference variable type out of a static arg.
557    def staticArgType(sarg: StaticArg): Option[_InferenceVarType] = sarg match {
558      case sarg:TypeArg => Some(sarg.getTypeArg.asInstanceOf)
559      case _ => None
560    }
561
562    // 5. build bounds map B = [$T_i -> S(UB(T_i))]
563    val infVars = sargs.flatMap(staticArgType)
564    val sparamBounds = sparams.flatMap(staticParamBoundType).
565      map(t => insertStaticParams(t, sparams))
566    val boundsMap = Map(infVars.zip(sparamBounds): _*)
567
568    // 6. solve C to yield a substitution S' = [$T_i -> U_i]
569    val subst = constraint.scalaSolve(boundsMap).getOrElse(return None)
570
571    // 7. instantiate infArrow with [U_i] to get resultArrow
572    val resultArrow = substituteTypesForInferenceVars(subst, infArrow).
573      asInstanceOf[ArrowType]
574
575    // 8. return (resultArrow,StaticArgs([U_i]))
576    val resultArgs = infVars.map((t) =>
577      NodeFactory.makeTypeArg(resultArrow.getInfo.getSpan, subst.apply(t)))
578    Some((resultArrow,resultArgs))
579  }
580
581  /**
582   * Determines if the kinds of the given static args match those of the static
583   * parameters. In the case of type arguments, the type is checked to be a
584   * subtype of the corresponding type parameter's bounds.
585   */
586  private def staticArgsMatchStaticParams(args: List[StaticArg],
587                                          params: List[StaticParam]): Boolean = {
588    if (args.length != params.length) return false
589
590    // Match a single pair.
591    def argMatchesParam(argAndParam: (StaticArg, StaticParam)): Boolean = {
592      val (arg, param) = argAndParam
593      (arg, param.getKind) match {
594        case (STypeArg(_, argType), SKindType(_)) =>
595            toList(param.getExtendsClause).forall((bound:Type) =>
596              isSubtype(argType, bound, arg,
597                        errorMsg(normalize(argType), " not a subtype of ", normalize(bound))))
598        case (SIntArg(_, _), SKindInt(_)) => true
599        case (SBoolArg(_, _), SKindBool(_)) => true
600        case (SDimArg(_, _), SKindDim(_)) => true
601        case (SOpArg(_, _), SKindOp(_)) => true
602        case (SUnitArg(_, _), SKindUnit(_)) => true
603        case (SIntArg(_, _), SKindNat(_)) => true
604        case (_, _) => false
605      }
606    }
607
608    // Match every pair.
609    args.zip(params).forall(argMatchesParam)
610  }
611
612  /**
613   * Given an applicand, the statically most applicable arrow type for it,
614   * and the static args from the application, return the applicand updated
615   * with the dynamically applicable overloadings, arrow type, and static args.
616   */
617  def rewriteApplicand(fn: Expr,
618                       arrow: ArrowType,
619                       sargs: List[StaticArg]): Expr = fn match {
620    case fn: FunctionalRef =>
621
622      // Get the dynamically applicable overloadings.
623      val overloadings =
624        toList(fn.getNewOverloadings).
625        filter(o => isDynamicallyApplicable(o, arrow, sargs))
626
627      // Add in the filtered overloadings, the inferred static args,
628      // and the statically most applicable arrow to the fn.
629      addType(
630        addStaticArgs(
631          addOverloadings(fn, overloadings), sargs), arrow)
632
633    case _ if !sargs.isEmpty =>
634      NI.nyi("No place to put inferred static args in application.")
635
636    // Just add the arrow type if the applicand is not a FunctionalRef.
637    case _ => addType(fn, arrow)
638  }
639
640  // ------------------------------------------------------------------------
641  // END HELPER METHODS -----------------------------------------------------
642  // ------------------------------------------------------------------------
643
644
645  def check(node:Node):Node = node match {
646    case SComponent(info, name, imports, decls, isNative, exports)  =>
647      SComponent(info, name, imports,
648                 decls.map((n:Decl) => check(n).asInstanceOf[Decl]),
649                 isNative, exports)
650
651    case t@STraitDecl(info,
652                      STraitTypeHeader(sparams, mods, name, where,
653                                       throwsC, contract, extendsC, decls),
654                      excludes, comprises, hasEllipses, selfType) => {
655      // Verify that this trait only extends other traits
656      extendsC.foreach( (t:TraitTypeWhere) =>
657                        assertTrait(t.getBaseType,
658                                    "Traits can only extend traits.", t) )
659      val checkerWSparams = this.extend(sparams, where)
660      var method_checker = checkerWSparams
661      var field_checker = checkerWSparams
662      // Add field declarations (getters/setters?) to method_checker
663      method_checker = decls.foldRight(method_checker)
664                                      { (d:Decl, c:STypeChecker) => d match {
665                                        case SVarDecl(_,lhs,_) => c.extend(lhs)
666                                        case _ => c } }
667      toOption(traits.typeCons(name.asInstanceOf[Id])).asInstanceOf[Option[TypeConsIndex]] match {
668        case None => signal(name, errorMsg(name, " is not found.")); t
669        case Some(ti) =>
670          // Extend method checker with methods and functions
671          // that will now be in scope
672          val methods = new UnionRelation(inheritedMethods(extendsC),
673                                          ti.asInstanceOf[TraitIndex].dottedMethods.asInstanceOf[Relation[IdOrOpOrAnonymousName, Method]])
674          method_checker = method_checker.extendWithMethods(methods)
675          method_checker = method_checker.extendWithFunctions(ti.asInstanceOf[TraitIndex].functionalMethods)
676          // Extend method checker with self
677          selfType match {
678            case Some(ty) =>
679              method_checker = method_checker.addSelf(ty)
680              // Check declarations
681              val newDecls = decls.map( (d:Decl) => d match {
682                                        case SFnDecl(_,_,_,_,_) =>
683                                          // methods see extra variables in scope
684                                          method_checker.check(d).asInstanceOf[Decl]
685                                        case SVarDecl(_,lhs,_) =>
686                                          // fields see other fields
687                                          val newD = field_checker.check(d).asInstanceOf[Decl]
688                                          field_checker = field_checker.extend(lhs)
689                                          newD
690                                        case _ => checkerWSparams.check(d).asInstanceOf[Decl] } )
691              STraitDecl(info,
692                         STraitTypeHeader(sparams, mods, name, where,
693                                          throwsC, contract, extendsC, newDecls),
694                         excludes, comprises, hasEllipses, selfType)
695            case _ => signal(t, errorMsg("Self type is not inferred for ", t)); t
696          }
697      }
698    }
699
700    case o@SObjectDecl(info,
701                       STraitTypeHeader(sparams, mods, name, where,
702                                        throwsC, contract, extendsC, decls),
703                       params, selfType) => {
704      // Verify that no extends clauses try to extend an object.
705      extendsC.foreach( (t:TraitTypeWhere) =>
706                        assertTrait(t.getBaseType,
707                                    "Objects can only extend traits.", t.getBaseType) )
708      val checkerWSparams = this.extend(sparams, params, where)
709      var method_checker = checkerWSparams
710      var field_checker = checkerWSparams
711      val newContract = contract match {
712        case Some(e) => Some(method_checker.check(e).asInstanceOf[Contract])
713        case _ => contract
714      }
715      // Extend method checker with fields
716      method_checker = decls.foldRight(method_checker)
717                                      { (d:Decl, c:STypeChecker) => d match {
718                                        case SVarDecl(_,lhs,_) => c.extend(lhs)
719                                        case _ => c } }
720      // Check method declarations.
721      toOption(traits.typeCons(name.asInstanceOf[Id])).asInstanceOf[Option[TypeConsIndex]] match {
722        case None => signal(name, errorMsg(name, " is not found.")); o
723        case Some(oi) =>
724          // Extend type checker with methods and functions
725          // that will now be in scope as regular functions
726          val methods = new UnionRelation(inheritedMethods(extendsC),
727                                          oi.asInstanceOf[TraitIndex].dottedMethods.asInstanceOf[Relation[IdOrOpOrAnonymousName,Method]])
728          method_checker = method_checker.extendWithMethods(methods)
729          method_checker = method_checker.extendWithFunctions(oi.asInstanceOf[TraitIndex].functionalMethods)
730          // Extend method checker with self
731          selfType match {
732            case Some(ty) =>
733              method_checker = method_checker.addSelf(ty)
734              // Check declarations, storing them in the same order
735              val newDecls = decls.map( (d:Decl) => d match {
736                                        case SFnDecl(_,_,_,_,_) =>
737                                          // Methods get some extra vars in their declarations
738                                          method_checker.check(d).asInstanceOf[Decl]
739                                        case SVarDecl(_,lhs,_) =>
740                                          // Fields get to see earlier fields
741                                          val newD = field_checker.check(d).asInstanceOf[Decl]
742                                          field_checker = field_checker.extend(lhs)
743                                          newD
744                                        case _ => checkerWSparams.check(d).asInstanceOf[Decl] } )
745              SObjectDecl(info,
746                          STraitTypeHeader(sparams, mods, name, where,
747                                           throwsC, newContract, extendsC, newDecls),
748                          params, selfType)
749            case _ => signal(o, errorMsg("Self type is not inferred for ", o)); o
750          }
751      }
752    }
753
754    /* Matches if a function declaration does not have a body expression. */
755    case f@SFnDecl(info,
756                   SFnHeader(statics,mods,name,wheres,throws,contract,params,returnType),
757                   unambiguousName, None, implementsUnambiguousName) => {
758      returnType match {
759        case Some(ty) =>
760          if ( NodeUtil.isSetter(f) )
761            isSubtype(ty, Types.VOID, f, "Setter declarations must return void.")
762        case _ =>
763      }
764      f
765    }
766
767    /* Matches if a function declaration has a body expression. */
768    // @TODO: Only change return type of FnHeader if it was an inf var.
769    case f@SFnDecl(info,
770                   SFnHeader(statics,mods,name,wheres,throws,contract,params,returnType),
771                   unambiguousName, Some(body), implementsUnambiguousName) => {
772      val newChecker = this.extend(env.extendWithStaticParams(statics).extendWithParams(params),
773                                   analyzer.extend(statics, wheres))
774      val newContract = contract match {
775        case Some(c) => Some(newChecker.check(c))
776        case None => None
777      }
778      val newBody = newChecker.checkExpr(body, returnType, "Function body",
779                                         "declared return")
780      val newType = getType(newBody) match {
781        case Some(ty) =>
782          if ( NodeUtil.isSetter(f) )
783            isSubtype(ty, Types.VOID, f, "Setter declarations must return void.")
784          Some(ty)
785        case _ => noType(body); returnType
786      }
787      SFnDecl(info,
788              SFnHeader(statics, mods, name, wheres, throws,
789                        newContract.asInstanceOf[Option[Contract]],
790                        params, newType),
791              unambiguousName, Some(newBody), implementsUnambiguousName)
792    }
793
794    case v@SVarDecl(info, lhs, body) => body match {
795      case Some(init) =>
796        val newInit = checkExpr(init)
797        val ty = lhs match {
798          case l::Nil => // We have a single variable binding, not a tuple binding
799            toOption(l.getIdType).asInstanceOf[Option[Type]] match {
800              case Some(typ) => typ
801              case _ => // Eventually, this case will involve type inference
802                signal(v, errorMsg("All inferrred types should at least be inference ",
803                                   "variables by typechecking: ", v))
804                NodeFactory.makeVoidType(NodeUtil.getSpan(l))
805            }
806          case _ =>
807            def handleBinding(binding: LValue) =
808              toOption(binding.getIdType).asInstanceOf[Option[Type]] match {
809                case Some(typ) => typ
810                case _ =>
811                  signal(binding, errorMsg("Missing type for ", binding, "."))
812                  NodeFactory.makeVoidType(NodeUtil.getSpan(binding))
813              }
814            NodeFactory.makeTupleType(NodeUtil.getSpan(v),
815                                      toJavaList(lhs.map(handleBinding)))
816        }
817        getType(newInit) match {
818          case Some(typ) =>
819            isSubtype(typ, ty, v,
820                         errorMsg("Attempt to define variable ", v,
821                                  " with an expression of type ", normalize(typ)))
822          case _ =>
823            signal(v, errorMsg("The right-hand side of ", v, " could not be typed."))
824        }
825        SVarDecl(info, lhs, Some(newInit))
826      case _ => v
827    }
828
829    case id@SId(info,api,name) => {
830      api match {
831        case Some(_) => {
832          val newName = handleAlias(id, toList(current.ast.getImports))
833          getTypeFromName( newName ) match {
834            case None =>
835              // Operators are never qualified in source code,
836              // so if 'name' is qualified and not found,
837              // it must be an Id, not an Op.
838              signal(id, errorMsg("Attempt to reference unbound variable: ", id))
839            case _ => id
840          }
841        }
842        case _ => {
843          getTypeFromName( id ) match {
844            case Some(ty) => ty match {
845              case SLabelType(_) => // then, newName must be an Id
846                signal(id, errorMsg("Cannot use label name ", id, " as an identifier."))
847              case _ =>
848            }
849            case _ => signal(id, errorMsg("Variable '", id, "' not found."))
850          }
851        }
852      }
853      id
854    }
855
856    case SOverloading(info, name, sargs, _) => {
857          val checkedName = check(name).asInstanceOf[IdOrOp]
858
859          // Get the arrow type for this name and check that the supplied static
860        // args match its declared static params. If so, the overloading is
861        // returned with the arrow type filled in.
862        getTypeFromName(checkedName) match {
863          case Some(checkedType) =>
864            if (!sargs.isEmpty)
865              staticInstantiation(sargs, checkedType).
866                map((t:Type) => SOverloading(info, checkedName, sargs, Some(t))).
867                getOrElse(node)
868            else SOverloading(info, checkedName, sargs, Some(checkedType))
869          case None => node
870        }
871      }
872
873    case op@SOp(info,api,name,fixity,enclosing) => {
874      val tyEnv = api match {
875        case Some(api) => getEnvFromApi(api)
876        case _ => env
877      }
878      scalaify(tyEnv.binding(op)).asInstanceOf[Option[TypeEnv.BindingLookup]] match {
879        case None =>
880          if ( enclosing ) signal(op, errorMsg("Enclosing operator not found: ", op))
881          else signal(op, errorMsg("Operator not found: ", OprUtil.decorateOperator(op)))
882        case _ =>
883      }
884      op
885    }
886
887    case _ => throw new Error(errorMsg("not yet implemented: ", node.getClass))
888  }
889
890  def checkExpr(expr: Expr, expected: Option[Type],
891                first: String, second: String): Expr = {
892    val newExpr = checkExpr(expr)
893    getType(newExpr) match {
894      case Some(typ) => expected match {
895        case Some(t) =>
896          isSubtype(typ, t, expr,
897                    errorMsg(first, " has type ", normalize(typ), ", but ", second,
898                             " type is ", normalize(t), "."))
899          addType(newExpr, typ)
900        case _ => addType(newExpr, typ)
901      }
902      case _ => noType(expr); expr
903    }
904  }
905
906  def checkExpr(expr: Expr, expected: Option[Type], message: String): Expr = {
907    val newExpr = checkExpr(expr)
908    getType(newExpr) match {
909      case Some(typ) => expected match {
910        case Some(t) =>
911          isSubtype(typ, t, expr,
912                    errorMsg(message, " has type ", normalize(typ), ", but it must have ",
913                             normalize(t), " type."))
914          addType(newExpr, typ)
915        case _ => addType(newExpr, typ)
916      }
917      case _ => noType(expr); expr
918    }
919  }
920
921  def checkExpr(expr: Expr): Expr = expr match {
922    case o@SObjectExpr(SExprInfo(span,parenthesized,_),
923                     STraitTypeHeader(sparams, mods, name, where,
924                                      throwsC, contract, extendsC, decls),
925                     selfType) => {
926      // Verify that no extends clauses try to extend an object.
927      extendsC.foreach( (t:TraitTypeWhere) =>
928                        assertTrait(t.getBaseType,
929                                    "Objects can only extend traits.", t.getBaseType) )
930      var method_checker = this
931      var field_checker = this
932      val newContract = contract match {
933        case Some(e) => Some(method_checker.check(e).asInstanceOf[Contract])
934        case _ => contract
935      }
936      // Extend the type checker with all of the field decls
937      method_checker = decls.foldRight(method_checker)
938                                      { (d:Decl, c:STypeChecker) => d match {
939                                        case SVarDecl(_,lhs,_) => c.extend(lhs)
940                                        case _ => c } }
941      // Extend type checker with methods and functions
942      // that will now be in scope as regular functions
943      val oi = IndexBuilder.buildObjectExprIndex(o)
944      val methods = new UnionRelation(inheritedMethods(extendsC),
945                                      oi.asInstanceOf[ObjectTraitIndex].dottedMethods.asInstanceOf[Relation[IdOrOpOrAnonymousName, Method]])
946      method_checker = method_checker.extendWithMethods(methods)
947      method_checker = method_checker.extendWithFunctions(oi.asInstanceOf[ObjectTraitIndex].functionalMethods)
948      // Extend method checker with self
949      selfType match {
950        case Some(ty) =>
951          method_checker = method_checker.addSelf(ty)
952          // Typecheck each declaration
953          val newDecls = decls.map( (d:Decl) => d match {
954                                    case SFnDecl(_,_,_,_,_) =>
955                                      // Methods get a few more things in scope than everything else
956                                      method_checker.check(d).asInstanceOf[Decl]
957                                    case SVarDecl(_,lhs,_) =>
958                                      // fields get to see earlier fields
959                                      val newD = field_checker.check(d).asInstanceOf[Decl]
960                                      field_checker = field_checker.extend(lhs)
961                                      newD
962                                    case _ => check(d).asInstanceOf[Decl] } )
963          SObjectExpr(SExprInfo(span,parenthesized,Some(normalize(ty))),
964                      STraitTypeHeader(sparams, mods, name, where,
965                                       throwsC, newContract, extendsC, newDecls),
966                      selfType)
967        case _ => signal(o, errorMsg("Self type is not inferred for ", o)); o
968      }
969    }
970
971    /* Matches if block is an atomic block. */
972    case SBlock(SExprInfo(span,parenthesized,resultType),
973                loc, true, withinDo, exprs) =>
974      forAtomic(SBlock(SExprInfo(span,parenthesized,resultType),
975                       loc, false, withinDo, exprs),
976                "an 'atomic'do block")
977
978    /* Matches if block is not an atomic block. */
979    case SBlock(SExprInfo(span,parenthesized,resultType),
980                loc, false, withinDo, exprs) => {
981      val newLoc = loc match {
982        case Some(l) =>
983          Some(checkExpr(l, Some(Types.REGION), "Location of the block"))
984        case None => loc
985      }
986      exprs.reverse match {
987        case Nil =>
988          SBlock(SExprInfo(span,parenthesized,Some(Types.VOID)),
989                 newLoc, false, withinDo, exprs)
990        case last::rest =>
991        val allButLast = rest.map((e: Expr) => checkExpr(e, Some(Types.VOID),
992                                                         "Non-last expression in a block"))
993          val lastExpr = checkExpr(last)
994          val newExprs = (lastExpr::allButLast).reverse
995          SBlock(SExprInfo(span,parenthesized,getType(lastExpr)),
996                 newLoc, false, withinDo, newExprs)
997      }
998    }
999
1000    case s@SSpawn(SExprInfo(span,paren,optType), body) => {
1001      val newExpr = this.extendWithout(s, labelExitTypes.keySet).checkExpr(body)
1002      getType(newExpr) match {
1003        case Some(typ) =>
1004          SSpawn(SExprInfo(span,paren,Some(Types.makeThreadType(typ))), newExpr)
1005        case _ => noType(body); expr
1006      }
1007    }
1008
1009    case SAtomicExpr(SExprInfo(span,paren,optType), body) => {
1010      val newExpr = forAtomic(body, "an 'atomic' expression")
1011      SAtomicExpr(SExprInfo(span,paren,getType(newExpr)), newExpr)
1012    }
1013
1014    case STryAtomicExpr(SExprInfo(span,paren,optType), body) => {
1015      val newExpr = forAtomic(body, "an 'tryatomic' expression")
1016      STryAtomicExpr(SExprInfo(span,paren,getType(newExpr)), newExpr)
1017    }
1018
1019    // For a tight juxt, create a MathPrimary
1020    case SJuxt(info, multi, infix, front::rest, false, true) => {
1021      def toMathItem(exp: Expr): MathItem = {
1022        val span = NodeUtil.getSpan(exp)
1023        if ( exp.isInstanceOf[TupleExpr] ||
1024             exp.isInstanceOf[VoidLiteralExpr] ||
1025             NodeUtil.isParenthesized(exp) )
1026          ExprFactory.makeParenthesisDelimitedMI(span, exp)
1027        else ExprFactory.makeNonParenthesisDelimitedMI(span, exp)
1028      }
1029      checkExpr(SMathPrimary(info, multi, infix, front, rest.map(toMathItem)))
1030    }
1031
1032    // If this juxt is actually a fn app, then rewrite to a fn app.
1033    case SJuxt(info, multi, infix, front::rest, true, true) => rest.length match {
1034      case 1 => checkExpr(S_RewriteFnApp(info, front, rest.head))
1035      case n => // Make sure it is just two exprs.
1036        signal(expr, errorMsg("TightJuxt denoted as function application but has ",
1037                              n + "(!= 2) expressions."))
1038        expr
1039    }
1040
1041    /* Loose Juxts are handled using the algorithm in 16.8 of Fortress Spec 1.0
1042     */
1043    case SJuxt(SExprInfo(span,paren,optType),
1044               multi, infix, exprs, isApp, false) => {
1045      // Check subexpressions
1046      val checkedExprs = exprs.map(checkExpr)
1047      if ( haveTypes(checkedExprs) ) {
1048        // Break the list of expressions into chunks.
1049        // First the loose juxtaposition is broken into nonempty chunks;
1050        // wherever there is a non-function element followed
1051        // by a function element, the latter begins a new chunk.
1052        // Thus a chunk consists of some number (possibly zero) of
1053        // functions followed by some number (possibly zero) of non-functions.
1054        def chunker(exprs: List[Expr], results: List[(List[Expr],List[Expr])]): List[(List[Expr],List[Expr])] = exprs match {
1055          case Nil => results.reverse
1056          case first::rest =>
1057            if ( isArrows(first) ) {
1058              val (arrows,temp) = (first::rest).span(isArrows)
1059              val (nonArrows,remainingChunks) = temp.span((e:Expr) => ! isArrows(e))
1060              chunker(remainingChunks, (arrows,nonArrows)::results)
1061            } else {
1062              val (nonArrows,remainingChunks) = (first::rest).span((e:Expr) => ! isArrows(e))
1063              chunker(remainingChunks, (List(),nonArrows)::results)
1064            }
1065        }
1066        val chunks = chunker(checkedExprs, List())
1067        // Left associate nonarrows as a single OpExpr
1068        def associateNonArrows(nonArrows: List[Expr]): Option[Expr] =
1069          nonArrows match {
1070            case Nil => None
1071            case head::tail =>
1072              Some(tail.foldLeft(head){ (e1: Expr, e2: Expr) =>
1073                                        ExprFactory.makeOpExpr(infix,e1,e2) })
1074          }
1075        // Right associate everything in a chunk as a _RewriteFnApp
1076        def associateArrows(fs: List[Expr], oe: Option[Expr]) = oe match {
1077          case None => fs match {
1078            case Nil =>
1079              errors.signal("Empty chunk", expr)
1080              expr
1081            case _ =>
1082              fs.take(fs.size-1).foldRight(fs.last){ (f: Expr, e: Expr) =>
1083                                                     ExprFactory.make_RewriteFnApp(f,e) }
1084          }
1085          case Some(e) =>
1086            fs.foldRight(e){ (f: Expr, e: Expr) => ExprFactory.make_RewriteFnApp(f,e) }
1087        }
1088        // Associate a chunk
1089        def associateChunk(chunk: (List[Expr],List[Expr])): Expr = {
1090          val (arrows, nonArrows) = chunk
1091          associateArrows(arrows, associateNonArrows(nonArrows))
1092        }
1093        val associatedChunks = chunks.map(associateChunk)
1094        // (1) If any element that remains has type String,
1095        //     then it is a static error
1096        //     if there is any pair of adjacent elements within the juxtaposition
1097        //     such that neither element is of type String.
1098        val types = if ( haveTypes(associatedChunks) )
1099                      associatedChunks.map((e: Expr) => getType(e).get)
1100                    else List()
1101        def isStringType(t: Type) = analyzer.subtype(t, Types.STRING).isTrue
1102        if ( types.exists(isStringType) ) {
1103          def stringCheck(e: Type, f: Type) =
1104            if ( ! (isStringType(e) || isStringType(f)) ) {
1105              signal(expr, errorMsg("Neither element is of type String in ",
1106                                    "a juxtaposition of String elements."))
1107              e
1108            } else e
1109          types.take(types.size-1).foldRight(types.last)(stringCheck)
1110        }
1111        // (2) Treat the sequence that remains as a multifix application
1112        //     of the juxtaposition operator.
1113        //     The rules for multifix operators then apply.
1114        val multiOpExpr = checkExpr(ExprFactory.makeOpExpr(span, paren, toJavaOption(optType),
1115                                                           multi, toJavaList(associatedChunks)))
1116        if ( getType(multiOpExpr).isDefined ) multiOpExpr
1117        else {
1118          // If not, left associate as InfixJuxts
1119          associatedChunks match {
1120            case Nil =>
1121              errors.signal("Empty juxt", expr)
1122              expr
1123            case head::tail =>
1124              checkExpr(tail.foldLeft(head){ (e1: Expr, e2: Expr) =>
1125                                             ExprFactory.makeOpExpr(infix,e1,e2) })
1126          }
1127        }
1128      } else { noType(expr); expr }
1129    }
1130
1131    // Math primary, which is the more general case,
1132    // is going to be called for both tight Juxt and MathPrimary
1133
1134    // Base case of recursion: If there is no 'rest', return the Expr
1135    case SMathPrimary(info, multi, infix, front, Nil) => checkExpr(front)
1136
1137    case mp@SMathPrimary(info@SExprInfo(span,paren,optType),
1138                         multi, infix, front, rest@second::remained) => {
1139      /** Check for ^ followed by ^ or ^ followed by [], both static errors. */
1140      def exponentiationStaticCheck(items: List[MathItem]) = {
1141        var exponent: Option[MathItem] = None
1142        def checkMathItem(item: MathItem) = item match {
1143          case SExponentiationMI(_,_,_) => exponent match {
1144            case None => exponent = Some(item)
1145            case Some(e) => signal(item, "Two consecutive ^s.")
1146          }
1147          case SSubscriptingMI(_,_,_,_) => exponent match {
1148            case Some(e) =>
1149              signal(item, "Exponentiation followed by subscripting is illegal.")
1150            case None =>
1151          }
1152          case _ => exponent = None
1153        }
1154        // Check for two exponentiations or an exponentiation and a subscript in a row
1155        items.foreach(checkMathItem)
1156      }
1157      exponentiationStaticCheck(rest) // See if simple static errors exist
1158
1159      def isExprMI(expr: MathItem): Boolean = expr match {
1160        case SParenthesisDelimitedMI(_, _) => true
1161        case SNonParenthesisDelimitedMI(_, _) => true
1162        case _ => false
1163      }
1164      def isParenedExprItem(item: MathItem) = item match {
1165        case SParenthesisDelimitedMI(_,_) => true
1166        case _ => false
1167      }
1168      def isFunctionItem(item: MathItem) = item match {
1169        case SParenthesisDelimitedMI(_,e) => isArrows(checkExpr(e))
1170        case SNonParenthesisDelimitedMI(_,e) => isArrows(checkExpr(e))
1171        case _ =>
1172      }
1173      def expectParenedExprItem(item: MathItem) =
1174        if ( ! isParenedExprItem(item) )
1175          signal(item, "Argument to function must be parenthesized.")
1176      def expectExprMI(item: MathItem) =
1177        if ( ! isExprMI(item) )
1178          signal(item, "Item at this location must be an expression, not an operator.")
1179      // items is not an empty list.
1180      def associateMathItems(first: Expr,
1181                             items: List[MathItem]): (Expr, List[MathItem]) = {
1182        /* For each expression element (i.e., not a subscripting, exponentiation
1183         * or postfix operator), determine whether it is a function.
1184         * If some function element is immediately followed by an expression
1185         * element then, find the first such function element, and call the
1186         * next element the argument.
1187         */
1188        // find the left-most function
1189        val (prefix, others) = items.span((e:MathItem) =>
1190                                          !isFunctionItem(e).asInstanceOf[Boolean])
1191        others match {
1192          case fn::arg::suffix => arg match {
1193            // It is a static error if either the argument is not parenthesized,
1194            case SNonParenthesisDelimitedMI(_,e) =>
1195              signal(e, "Tightly juxtaposed expression should be parenthesized.")
1196              (first, Nil)
1197            case SParenthesisDelimitedMI(i,e) => {
1198              // or the argument is immediately followed by a non-expression element.
1199              suffix match {
1200                case third::more =>
1201                  if ( ! isExprMI(third) )
1202                    signal(third, "An expression is expected.")
1203                case _ =>
1204              }
1205              // Otherwise, replace the function and argument with a single element
1206              // that is the application of the function to the argument.  This new
1207              // element is an expression.  Reassociate the resulting sequence
1208              // (which is one element shorter)
1209              val fnApp =
1210                new NonParenthesisDelimitedMI(i,
1211                                              ExprFactory.make_RewriteFnApp(fn.asInstanceOf[ExprMI].getExpr,
1212                                                                            arg.asInstanceOf[ExprMI].getExpr))
1213              associateMathItems( first, prefix++(fnApp::suffix) )
1214            }
1215            case _ => reassociateMathItems( first, items )
1216          }
1217          case _ => reassociateMathItems( first, items )
1218        }
1219      }
1220      // items is not an empty list.
1221      def reassociateMathItems(first: Expr, items: List[MathItem]) = {
1222        val (left, right) = items.span( isExprMI )
1223        val head = left match {
1224          case Nil => first
1225          case _ =>
1226            if ( isExprMI(left.last) )
1227              left.last.asInstanceOf[ExprMI].getExpr
1228            else {
1229              signal(left.last, "An expression is expected.")
1230              first
1231            }
1232        }
1233        right match {
1234        /* If there is any non-expression element (it cannot be the first element)
1235         * then replace the first such element and the element
1236         * immediately preceeding it (which must be an expression) with
1237         * a single element that does the appropriate operator application.
1238         * This new element is an expression.  Reassociate the resulting
1239         * sequence (which is one element shorter.)
1240         */
1241          case item::suffix => {
1242            val newExpr = item match {
1243              case SExponentiationMI(_,op,expr) =>
1244                ExprFactory.makeOpExpr(op, head, toJavaOption(expr))
1245              case SSubscriptingMI(_,op,exprs,sargs) =>
1246                ExprFactory.makeSubscriptExpr(span, head,
1247                                              toJavaList(exprs), some(op),
1248                                              toJavaList(sargs))
1249              case _ =>
1250                signal(item, "Non-expression element is expected.")
1251                head
1252            }
1253            left match {
1254              case Nil => associateMathItems(newExpr, suffix)
1255              case _ =>
1256                val exp = new NonParenthesisDelimitedMI(newExpr.getInfo, newExpr)
1257                associateMathItems(first, left.dropRight(1)++(exp::suffix))
1258            }
1259          }
1260          case _ => (first, items)
1261        }
1262      }
1263
1264      // HANDLE THE FRONT ITEM
1265      val newFront = checkExpr(front)
1266      getType( newFront ) match {
1267        case None => noType(front); front
1268        case Some(t) =>
1269          // If front is a fn followed by an expr, we reassociate
1270          if ( isArrows(t) && isExprMI(second) ) {
1271            // It is a static error if either the argument is not parenthesized,
1272            expectParenedExprItem(second)
1273            // static error if the argument is immediately followed by
1274            // a non-expression element.
1275            remained match {
1276              case hd::tl => expectExprMI(hd)
1277              case Nil =>
1278            }
1279            // Otherwise, make a new MathPrimary that is one element shorter,
1280            // and recur.
1281            val fn = ExprFactory.make_RewriteFnApp(front,
1282                                                   second.asInstanceOf[ExprMI].getExpr)
1283            checkExpr(SMathPrimary(info, multi, infix, fn, remained))
1284          // THE FRONT ITEM WAS NOT A FN FOLLOWED BY AN EXPR, REASSOCIATE REST
1285          } else {
1286            val (head, tail) = associateMathItems( newFront, rest )
1287            // Otherwise, left-associate the sequence, which has only expression
1288            // elements, only the last of which may be a function.
1289            val newTail = tail.map( (e:MathItem) =>
1290                                    if ( ! isExprMI(e) ) {
1291                                      signal(e, "An expression is expected.")
1292                                      ExprFactory.makeVoidLiteralExpr(span)
1293                                    } else e.asInstanceOf[ExprMI].getExpr )
1294            // Treat the sequence that remains as a multifix application of
1295            // the juxtaposition operator.
1296            // The rules for multifix operators then apply.
1297            val multi_op_expr = checkExpr( ExprFactory.makeOpExpr(span, multi,
1298                                                                  toJavaList(head::newTail)) )
1299            getType(multi_op_expr) match {
1300              case Some(_) => multi_op_expr
1301              case None =>
1302                newTail.foldLeft(head){ (r:Expr, e:Expr) =>
1303                                        ExprFactory.makeOpExpr(NodeUtil.spanTwo(r, e),
1304                                                               infix, r, e) }
1305            }
1306          }
1307      }
1308    }
1309
1310    case SSubscriptExpr(SExprInfo(span, paren, _), obj, subs, op, sargs) => {
1311      val checkedObj = checkExpr(obj)
1312      val checkedSubs = subs.map(checkExpr)
1313      val objType = getType(checkedObj).getOrElse(return expr)
1314
1315      // Convert sub types into a single type or tuple of types.
1316      if (!haveTypes(checkedSubs)) return expr
1317      val subsType = checkedSubs.map(s => getType(s).get) match {
1318        case t :: Nil => t
1319        case t =>
1320          NodeFactory.makeTupleType(NodeUtil.getSpan(expr), toJavaList(t))
1321      }
1322
1323      // Get the methods and arrows from the op.
1324      val methods = findMethodsInTraitHierarchy(op.get, objType)
1325      val arrows =
1326        if (sargs.isEmpty) methods.map(getArrowFromMethod)
1327        else methods.
1328               flatMap(m => staticInstantiation(sargs, getArrowFromMethod(m))).
1329               map(_.asInstanceOf[ArrowType])
1330
1331      staticallyMostApplicableArrow(arrows.toList, subsType, None) match {
1332        case Some((arrow, sargs)) =>
1333          SSubscriptExpr(SExprInfo(span, paren, Some(arrow.getRange)),
1334                         checkedObj,
1335                         checkedSubs,
1336                         op,
1337                         sargs)
1338        case one =>
1339          // TODO: Better error message.
1340          signal(expr, "Receiver type %s does not have applicable overloading of %s for argument type %s.".
1341                         format(objType, op.get, subsType))
1342          expr
1343      }
1344    }
1345
1346    case SStringLiteralExpr(SExprInfo(span,parenthesized,_), text) =>
1347      SStringLiteralExpr(SExprInfo(span,parenthesized,Some(Types.STRING)), text)
1348
1349    case SCharLiteralExpr(SExprInfo(span,parenthesized,_), text, charVal) =>
1350      SCharLiteralExpr(SExprInfo(span,parenthesized,Some(Types.CHAR)),
1351                       text, charVal)
1352
1353    case SIntLiteralExpr(SExprInfo(span,parenthesized,_), text, intVal) =>
1354      SIntLiteralExpr(SExprInfo(span,parenthesized,Some(Types.INT_LITERAL)),
1355                      text, intVal)
1356
1357    case SFloatLiteralExpr(SExprInfo(span,parenthesized,_), text, i, n, b, p) =>
1358      SFloatLiteralExpr(SExprInfo(span,parenthesized,Some(Types.FLOAT_LITERAL)),
1359                        text, i, n, b, p)
1360
1361    case SVoidLiteralExpr(SExprInfo(span,parenthesized,_), text) =>
1362      SVoidLiteralExpr(SExprInfo(span,parenthesized,Some(Types.VOID)), text)
1363
1364    // Type checking of varargs and keyword arguments are not yet implemented.
1365    case STupleExpr(SExprInfo(span,parenthesized,_), es, vs, ks, inApp) => {
1366      if ( vs.isDefined || ks.size > 0 ) { // ArgExpr
1367        signal(expr, errorMsg("Type checking of varargs and keyword arguments are ",
1368                              "not yet implemented."))
1369        expr
1370      } else {
1371        val newEs = es.map(checkExpr)
1372        val types = newEs.map((e:Expr) =>
1373                              if (getType(e).isDefined) getType(e).get
1374                              else { noType(e); Types.VOID })
1375        val newType = NodeFactory.makeTupleType(span, toJavaList(types).asInstanceOf[JavaList[Type]])
1376        STupleExpr(SExprInfo(span,parenthesized,Some(newType)), newEs, vs, ks, inApp)
1377      }
1378    }
1379
1380    case fn@SFunctionalRef(_, _, _, name, _, _, overloadings, _) => {
1381      // Note that ExprDisambiguator inserts the static args from a
1382      // FunctionalRef into each of its Overloadings.
1383
1384      // Check all the overloadings and filter out any that have the wrong
1385      // number or kind of static parameters.
1386      val checkedOverloadings = overloadings.
1387        map(check(_).asInstanceOf[Overloading]).filter(_.getType.isSome)
1388
1389      if (checkedOverloadings.isEmpty)
1390        signal(expr, errorMsg("Wrong number or kind of static arguments for function: ",
1391                              name))
1392
1393      // Make the intersection type of all the overloadings.
1394      val overloadingTypes = checkedOverloadings.map(_.getType.unwrap)
1395      val intersectionType =
1396        NodeFactory.makeIntersectionType(NodeUtil.getSpan(fn),
1397                                         toJavaList(overloadingTypes))
1398      addType(addOverloadings(fn, checkedOverloadings), intersectionType)
1399    }
1400
1401    case S_RewriteFnApp(SExprInfo(span, paren, optType), fn, arg) => {
1402      val checkedFn = checkExpr(fn)
1403      val checkedArg = checkExpr(arg)
1404
1405      // Check fn and arg and get their types.
1406      (getType(checkedFn), getType(checkedArg)) match {
1407        case (Some(fnType), Some(_)) if !isArrows(fnType) =>
1408          signal(expr, errorMsg("Applicand has a type that is not an arrow: ",
1409                                normalize(fnType)))
1410          expr
1411        case (Some(fnType), Some(argType)) =>
1412
1413          staticallyMostApplicableArrow(fnType, argType, None) match {
1414            case Some((smostApp, sargs)) =>
1415
1416              // Rewrite the applicand to include the arrow and static args
1417              // and update the application.
1418              val newFn = rewriteApplicand(checkedFn, smostApp, sargs)
1419              S_RewriteFnApp(SExprInfo(span, paren, Some(smostApp.getRange)), newFn, checkedArg)
1420
1421            case None =>
1422              // TODO: Better error message.
1423              signal(expr, "Could not find statically most applicable function.")
1424              expr
1425        }
1426
1427        case _ => expr
1428      }
1429    }
1430
1431    // First try to type check this expression as a multifix operator expression.
1432    // If that fails, type check it as some number of applications of the infix
1433    // operator, left associatively.
1434    case SAmbiguousMultifixOpExpr(info@SExprInfo(span, paren, _),
1435                                  infixOp, multifixOp, args) => {
1436      val checkedArgs = args.map(checkExpr)
1437      if (!haveTypes(checkedArgs)) return expr
1438
1439      def checkAsInfix() = checkExpr(checkedArgs.reduceLeft(
1440        (e1, e2) => SOpExpr(info, infixOp, List(e1, e2))))
1441
1442      // Attempt to check the multifix.
1443      val checkedMultifixOp =
1444        new TryChecker(current, traits, env, analyzer).
1445          tryCheckExpr(multifixOp).
1446          getOrElse(return checkAsInfix())
1447
1448      val opType = getType(checkedMultifixOp).getOrElse(return expr)
1449      val argType =
1450        NodeFactory.makeTupleType(info.getSpan,
1451                                  toJavaList(checkedArgs.map(t => getType(t).get)))
1452
1453      staticallyMostApplicableArrow(opType, argType, None) match {
1454
1455        // If a most applicable arrow, rewrite the applicand and return the
1456        // resulting operator expression.
1457        case Some((smostApp, sargs)) =>
1458          val newOp:FunctionalRef =
1459            rewriteApplicand(checkedMultifixOp, smostApp, sargs).asInstanceOf
1460          SOpExpr(SExprInfo(span, paren, Some(smostApp.getRange)),
1461                  newOp, checkedArgs)
1462
1463        // Check as infix operator expressions.
1464        case None => checkAsInfix()
1465      }
1466    }
1467
1468    case SOpExpr(info, fn, args) => {
1469      val checkedOp = checkExpr(fn)
1470      val checkedArgs = args.map(checkExpr)
1471      val opType = getType(checkedOp).getOrElse(return expr)
1472      if (!haveTypes(checkedArgs)) return expr
1473      val argType =
1474        NodeFactory.makeTupleType(info.getSpan,
1475                                  toJavaList(checkedArgs.map(t => getType(t).get)))
1476      staticallyMostApplicableArrow(opType, argType, None) match {
1477        case Some((smostApp, sargs)) =>
1478          val newOp: OpRef = rewriteApplicand(checkedOp,smostApp,sargs).asInstanceOf
1479          addType(SOpExpr(info, newOp, checkedArgs),smostApp.getRange)
1480
1481        case None =>
1482          // TODO: Better error message.
1483          signal(expr, "Could not find statically most applicable function.")
1484          expr
1485      }
1486
1487    }
1488
1489    case SChainExpr(SExprInfo(span,parenthesized,_), first, links) => {
1490      val newFirst = checkExpr(first)
1491      var prev = newFirst
1492      def checkLink(link:Link) = {
1493        val op = checkExpr(link.getOp).asInstanceOf[FunctionalRef]
1494        val next = checkExpr(link.getExpr)
1495        // Check a temporary binary op, to see if the result is <: Boolean
1496        val tempOpExpr = ExprFactory.makeOpExpr(NodeUtil.spanTwo(prev,next),
1497                                                op, prev, next)
1498        getType(tempOpExpr) match {
1499          case Some(ty) =>
1500            isSubtype(ty, Types.BOOLEAN, tempOpExpr,
1501                      errorMsg("The chained expression ", tempOpExpr,
1502                               " should have type Boolean, but had type ", normalize(ty), "."))
1503          case _ => noType(tempOpExpr)
1504        }
1505        prev = next
1506        SLink(link.getInfo, op, next)
1507      }
1508      SChainExpr(SExprInfo(span,parenthesized,Some(Types.BOOLEAN)), newFirst,
1509                 links.map(checkLink))
1510    }
1511
1512    case SDo(SExprInfo(span,parenthesized,_), fronts) => {
1513      val fs = fronts.map(checkExpr).asInstanceOf[List[Block]]
1514      if ( haveTypes(fs) ) {
1515          // Get union of all clauses' types
1516          val frontTypes =
1517            fs.take(fs.size-1).foldRight(getType(fs.last).get)
1518              { (e:Expr, t:Type) => analyzer.join(getType(e).get, t) }
1519          SDo(SExprInfo(span,parenthesized,Some(normalize(frontTypes))), fs)
1520      } else { noType(expr); expr }
1521    }
1522
1523    case SIf(SExprInfo(span,parenthesized,_), clauses, elseC) => {
1524      val newClauses = clauses.map( handleIfClause )
1525      val types = newClauses.map( (c: IfClause) => getType(c.getBody) match {
1526                                    case Some(ty) => ty
1527                                    case None => noType(c.getBody); Types.VOID
1528                                  } )
1529      val (newElse, newType) = elseC match {
1530        case None => {
1531          // Check that each if/elif clause has void type
1532          types.foreach( (ty: Type) =>
1533                         isSubtype(ty, Types.VOID, expr,
1534                                   errorMsg("An 'if' clause without corresponding 'else' has type ",
1535                                            normalize(ty), " instead of type ().")) )
1536          (None, Types.VOID)
1537        }
1538        case Some(b) => {
1539          val newBlock = checkExpr(b).asInstanceOf[Block]
1540          getType(newBlock) match {
1541            case None => { noType(b) ; (None, Types.VOID) }
1542            case Some(ty) =>
1543              // Get union of all clauses' types
1544              (Some(newBlock), analyzer.join(toJavaList(ty::types)))
1545          }
1546        }
1547      }
1548      SIf(SExprInfo(span,parenthesized,Some(normalize(newType))), newClauses, newElse)
1549    }
1550
1551    case SWhile(SExprInfo(span,parenthesized,_), testExpr, body) => {
1552      val (newTestExpr, bindings) = generatorClauseGetBindings(testExpr, true)
1553      val newBody = this.extend(bindings).checkExpr(body).asInstanceOf[Do]
1554      getType(newBody) match {
1555        case None => noType(body)
1556        case Some(ty) =>
1557          isSubtype(ty, Types.VOID, body,
1558                    errorMsg("Body of while loop must have type (), but had type ",
1559                             normalize(ty), "."))
1560      }
1561      SWhile(SExprInfo(span,parenthesized,Some(Types.VOID)), newTestExpr, newBody)
1562    }
1563
1564    case SFor(SExprInfo(span,parenthesized,_), gens, body) => {
1565      val (newGens, bindings) = handleGens(gens)
1566      val newBody = this.extend(bindings).checkExpr(body).asInstanceOf[Block]
1567      getType(newBody) match {
1568        case None => noType(body)
1569        case Some(ty) =>
1570          isSubtype(ty, Types.VOID, body,
1571                    errorMsg("Body type of a for loop must have type () but has type ",
1572                             normalize(ty), "."))
1573      }
1574      SFor(SExprInfo(span,parenthesized,Some(Types.VOID)), newGens, newBody)
1575    }
1576
1577    case v@SVarRef(SExprInfo(span,paren,_), id, sargs, depth) =>
1578      getTypeFromName(id) match {
1579        case Some(ty) =>
1580          if ( NodeUtil.isSingletonObject(v) )
1581            ty match {
1582              case typ@STraitType(STypeInfo(sp,pr,_,_), name, args, params) =>
1583                if ( NodeUtil.isGenericSingletonType(typ) &&
1584                     staticArgsMatchStaticParams(sargs, params)) {
1585                  // make a trait type that is GenericType instantiated
1586                  val newType = NodeFactory.makeTraitType(sp, pr, name,
1587                                                          toJavaList(sargs))
1588                  SVarRef(SExprInfo(span,paren,Some(newType)), id, sargs, depth)
1589                } else {
1590                  signal(v, "Unexpected type for a singleton object reference.")
1591                  v
1592                }
1593              case _ =>
1594                signal(v, "Unexpected type for a singleton object reference.")
1595                v
1596            }
1597          else SVarRef(SExprInfo(span,paren,Some(normalize(ty))), id, sargs, depth)
1598        case None => signal(id, errorMsg("Type of the variable '", id, "' not found.")); v
1599      }
1600
1601    case _ => throw new Error(errorMsg("Not yet implemented: ", expr.getClass))
1602    // "\n" + expr.toStringVerbose())
1603  }
1604
1605  /**
1606   * A type checker that doesn't report its errors. Use the tryCheck() and
1607   * tryCheckExpr() methods instead of check() and checkExpr() to determine if
1608   * the check failed or not. As soon as any static error is generated, these
1609   * methods will return None. If they succeed, they return the node wrapped
1610   * in Some.
1611   */
1612  private class TryChecker(current: CompilationUnitIndex,
1613                           traits: TraitTable,
1614                           env: TypeEnv,
1615                           analyzer: TypeAnalyzer)
1616      extends STypeChecker(current, traits, env, analyzer, new ErrorLog) {
1617
1618    /**
1619     * Adds to error log and throws the exception it made.
1620     */
1621    override protected def signal(msg:String, hasAt:HasAt) = {
1622      errors.signal(msg, hasAt)
1623      throw errors.errors.last
1624    }
1625
1626    /**
1627     * Adds to error log and throws the exception it made.
1628     */
1629    override protected def signal(hasAt:HasAt, msg:String) = signal(msg, hasAt)
1630
1631    /**
1632     * Check the given node; return it if successful, None otherwise.
1633     */
1634    def tryCheck(node: Node): Option[Node] = {
1635      try {
1636        Some(super.check(node))
1637      }
1638      catch {
1639        case e:StaticError => None
1640        case e => throw e
1641      }
1642    }
1643
1644    /**
1645     * Check the given expression; return it if successful, None otherwise.
1646     */
1647    def tryCheckExpr(expr: Expr): Option[Expr] = {
1648      try {
1649        Some(super.checkExpr(expr))
1650      }
1651      catch {
1652        case e:StaticError => None
1653        case e => throw e
1654      }
1655    }
1656  }
1657
1658  /**
1659   * A type checker that signals an error if a spawn expr occurs inside it.
1660   */
1661  private class AtomicChecker(current: CompilationUnitIndex, traits: TraitTable,
1662                      env: TypeEnv, analyzer: TypeAnalyzer, errors: ErrorLog,
1663                      enclosingExpr: String)
1664      extends STypeChecker(current,traits,env,analyzer,errors) {
1665    val message = errorMsg("A 'spawn' expression must not occur inside ",
1666                           enclosingExpr, ".")
1667    override def checkExpr(e: Expr): Expr = e match {
1668      case SSpawn(_, _) => signal(e, message); e
1669      case _ => super.checkExpr(e)
1670    }
1671  }
1672
1673  private def forAtomic(expr: Expr, enclosingExpr: String) =
1674    new AtomicChecker(current,traits,env,analyzer,errors,enclosingExpr).checkExpr(expr)
1675
1676}
Note: See TracBrowser for help on using the browser.