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

Revision 3835, 73.2 KB (checked in by sukyoungryu, 6 months ago)

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