| 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 | |
|---|
| 18 | package com.sun.fortress.scala_src.typechecker |
|---|
| 19 | |
|---|
| 20 | import _root_.java.util.{List => JavaList} |
|---|
| 21 | import _root_.java.util.{Map => JavaMap} |
|---|
| 22 | import _root_.java.util.{HashMap => JavaHashMap} |
|---|
| 23 | import _root_.java.util.{Set => JavaSet} |
|---|
| 24 | import edu.rice.cs.plt.tuple.{Option => JavaOption} |
|---|
| 25 | import edu.rice.cs.plt.collect.EmptyRelation |
|---|
| 26 | import edu.rice.cs.plt.collect.IndexedRelation |
|---|
| 27 | import edu.rice.cs.plt.collect.Relation |
|---|
| 28 | import edu.rice.cs.plt.collect.UnionRelation |
|---|
| 29 | import com.sun.fortress.compiler.IndexBuilder |
|---|
| 30 | import com.sun.fortress.compiler.disambiguator.ExprDisambiguator.HierarchyHistory |
|---|
| 31 | import com.sun.fortress.compiler.index.CompilationUnitIndex |
|---|
| 32 | import com.sun.fortress.compiler.index.{FunctionalMethod => JavaFunctionalMethod} |
|---|
| 33 | import com.sun.fortress.compiler.index.Method |
|---|
| 34 | import com.sun.fortress.compiler.index.ObjectTraitIndex |
|---|
| 35 | import com.sun.fortress.compiler.index.ProperTraitIndex |
|---|
| 36 | import com.sun.fortress.compiler.index.TraitIndex |
|---|
| 37 | import com.sun.fortress.compiler.index.TypeConsIndex |
|---|
| 38 | import com.sun.fortress.compiler.typechecker.TypeNormalizer |
|---|
| 39 | import com.sun.fortress.compiler.typechecker.StaticTypeReplacer |
|---|
| 40 | import com.sun.fortress.compiler.typechecker.TypeAnalyzer |
|---|
| 41 | import com.sun.fortress.compiler.typechecker.TypeEnv |
|---|
| 42 | import com.sun.fortress.compiler.Types |
|---|
| 43 | import com.sun.fortress.exceptions.InterpreterBug.bug |
|---|
| 44 | import com.sun.fortress.exceptions.StaticError |
|---|
| 45 | import com.sun.fortress.exceptions.StaticError.errorMsg |
|---|
| 46 | import com.sun.fortress.exceptions.ProgramError |
|---|
| 47 | import com.sun.fortress.exceptions.ProgramError.error |
|---|
| 48 | import com.sun.fortress.nodes._ |
|---|
| 49 | import com.sun.fortress.nodes_util.NodeFactory |
|---|
| 50 | import com.sun.fortress.nodes_util.ExprFactory |
|---|
| 51 | import com.sun.fortress.nodes_util.NodeUtil |
|---|
| 52 | import com.sun.fortress.nodes_util.OprUtil |
|---|
| 53 | import com.sun.fortress.scala_src.typechecker.ScalaConstraintUtil._ |
|---|
| 54 | import com.sun.fortress.scala_src.nodes._ |
|---|
| 55 | import com.sun.fortress.scala_src.useful.ASTGenHelper._ |
|---|
| 56 | import com.sun.fortress.scala_src.useful.ErrorLog |
|---|
| 57 | import com.sun.fortress.scala_src.useful.Lists._ |
|---|
| 58 | import com.sun.fortress.scala_src.useful.Options._ |
|---|
| 59 | import com.sun.fortress.scala_src.useful.Sets._ |
|---|
| 60 | import com.sun.fortress.scala_src.useful.SExprUtil._ |
|---|
| 61 | import com.sun.fortress.scala_src.useful.STypesUtil._ |
|---|
| 62 | import com.sun.fortress.useful.HasAt |
|---|
| 63 | import 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 | */ |
|---|
| 71 | object 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 | |
|---|
| 80 | class 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 | } |
|---|