| 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.ArrayList |
|---|
| 21 | import _root_.java.util.{List => JavaList} |
|---|
| 22 | import _root_.java.util.{Set => JavaSet} |
|---|
| 23 | import edu.rice.cs.plt.tuple.{Option => JavaOption} |
|---|
| 24 | import scala.collection.Map |
|---|
| 25 | import scala.collection.Set |
|---|
| 26 | import scala.collection.mutable.HashMap |
|---|
| 27 | import scala.collection.mutable.HashSet |
|---|
| 28 | import com.sun.fortress.compiler.GlobalEnvironment |
|---|
| 29 | import com.sun.fortress.compiler.index.CompilationUnitIndex |
|---|
| 30 | import com.sun.fortress.compiler.index.ObjectTraitIndex |
|---|
| 31 | import com.sun.fortress.compiler.index.ProperTraitIndex |
|---|
| 32 | import com.sun.fortress.compiler.index.TraitIndex |
|---|
| 33 | import com.sun.fortress.compiler.index.{Function => JavaFunction} |
|---|
| 34 | import com.sun.fortress.compiler.index.{Functional => JavaFunctional} |
|---|
| 35 | import com.sun.fortress.compiler.index.{Method => JavaMethod} |
|---|
| 36 | import com.sun.fortress.compiler.disambiguator.ExprDisambiguator.HierarchyHistory |
|---|
| 37 | import com.sun.fortress.compiler.typechecker.TypeAnalyzer |
|---|
| 38 | import com.sun.fortress.exceptions.InterpreterBug |
|---|
| 39 | import com.sun.fortress.exceptions.StaticError |
|---|
| 40 | import com.sun.fortress.exceptions.TypeError |
|---|
| 41 | import com.sun.fortress.nodes._ |
|---|
| 42 | import com.sun.fortress.nodes_util.NodeFactory |
|---|
| 43 | import com.sun.fortress.nodes_util.NodeUtil |
|---|
| 44 | import com.sun.fortress.nodes_util.Span |
|---|
| 45 | import com.sun.fortress.parser_util.IdentifierUtil |
|---|
| 46 | import com.sun.fortress.repository.FortressRepository |
|---|
| 47 | import com.sun.fortress.scala_src.useful._ |
|---|
| 48 | import com.sun.fortress.scala_src.useful.Lists._ |
|---|
| 49 | import com.sun.fortress.scala_src.useful.Options._ |
|---|
| 50 | import com.sun.fortress.scala_src.useful.STypesUtil |
|---|
| 51 | import com.sun.fortress.scala_src.useful.Sets._ |
|---|
| 52 | import com.sun.fortress.scala_src.nodes._ |
|---|
| 53 | |
|---|
| 54 | /* Check the set of overloadings in this compilation unit. |
|---|
| 55 | * |
|---|
| 56 | * The following functionals are not checked yet: |
|---|
| 57 | * functional methods |
|---|
| 58 | * dotted methods |
|---|
| 59 | * object constructors |
|---|
| 60 | * |
|---|
| 61 | * The following features are not (fully) checked yet: |
|---|
| 62 | * static parameters |
|---|
| 63 | * exclusion relationships |
|---|
| 64 | * varargs parameters |
|---|
| 65 | * keyword parameters |
|---|
| 66 | */ |
|---|
| 67 | class OverloadingChecker(compilation_unit: CompilationUnitIndex, |
|---|
| 68 | globalEnv: GlobalEnvironment, |
|---|
| 69 | repository: FortressRepository) { |
|---|
| 70 | var typeAnalyzer = TypeAnalyzer.make(new TraitTable(compilation_unit, globalEnv)) |
|---|
| 71 | var errors = List[StaticError]() |
|---|
| 72 | |
|---|
| 73 | /* Called by com.sun.fortress.compiler.StaticChecker.checkComponent |
|---|
| 74 | * and com.sun.fortress.compiler.StaticChecker.checkApi |
|---|
| 75 | */ |
|---|
| 76 | def checkOverloading(): JavaList[StaticError] = { |
|---|
| 77 | val fnsInComp = compilation_unit.functions |
|---|
| 78 | for ( f <- toSet(fnsInComp.firstSet) ; if isDeclaredName(f) ) { |
|---|
| 79 | checkOverloading(f, toSet(fnsInComp.matchFirst(f)).asInstanceOf[Set[JavaFunctional]]) |
|---|
| 80 | } |
|---|
| 81 | val typesInComp = compilation_unit.typeConses |
|---|
| 82 | for ( t <- toSet(typesInComp.keySet) ; |
|---|
| 83 | if NodeUtil.isTraitOrObject(typesInComp.get(t)) ) { |
|---|
| 84 | val traitOrObject = typesInComp.get(t).asInstanceOf[TraitIndex] |
|---|
| 85 | /* All inherited abstract methods in object definitions and |
|---|
| 86 | * object expressions should be defined, |
|---|
| 87 | * with compatible signatures and modifiers. |
|---|
| 88 | */ |
|---|
| 89 | if ( compilation_unit.ast.isInstanceOf[Component] && |
|---|
| 90 | traitOrObject.isInstanceOf[ObjectTraitIndex] ) { |
|---|
| 91 | val ast = traitOrObject.ast |
|---|
| 92 | val toCheck = inheritedAbstractMethods(toList(NodeUtil.getExtendsClause(ast))) |
|---|
| 93 | for ( t <- toCheck.keySet ) { |
|---|
| 94 | for ( ds <- toCheck.get(t) ) { |
|---|
| 95 | for ( d <- ds ) { |
|---|
| 96 | if ( ! implement(d, toList(NodeUtil.getDecls(ast))) ) |
|---|
| 97 | error(NodeUtil.getSpan(d).toString, |
|---|
| 98 | "The inherited abstract method " + d + |
|---|
| 99 | " from the trait " + t + |
|---|
| 100 | "\n in the object " + NodeUtil.getName(ast) + |
|---|
| 101 | " is not defined in the component " + |
|---|
| 102 | compilation_unit.ast.getName + ".") |
|---|
| 103 | } |
|---|
| 104 | } |
|---|
| 105 | } |
|---|
| 106 | } |
|---|
| 107 | |
|---|
| 108 | /* The parameter type of a setter must be the same as the return type |
|---|
| 109 | * of a getter with the same name, if any. |
|---|
| 110 | */ |
|---|
| 111 | for ( f <- toSet(traitOrObject.setters.keySet) ) { |
|---|
| 112 | if ( traitOrObject.getters.keySet.contains(f) ) { |
|---|
| 113 | val getter = traitOrObject.getters.get(f) |
|---|
| 114 | // Setter declarations are guaranteed to have a single parameter. |
|---|
| 115 | val param = traitOrObject.setters.get(f).parameters.get(0) |
|---|
| 116 | val span = getter.getSpan.toString |
|---|
| 117 | if ( param.getIdType.isSome && |
|---|
| 118 | ! typeAnalyzer.equivalent(param.getIdType.unwrap, |
|---|
| 119 | getter.getReturnType.unwrap).isTrue ) |
|---|
| 120 | error(span, |
|---|
| 121 | "The parameter type of a setter must be " + |
|---|
| 122 | "the same as\n the return type of a getter " + |
|---|
| 123 | "with the same name, if any.") |
|---|
| 124 | } |
|---|
| 125 | } |
|---|
| 126 | val methods = traitOrObject.dottedMethods |
|---|
| 127 | val staticParameters = new ArrayList[StaticParam]() |
|---|
| 128 | // Add static parameters of the enclosing trait or object |
|---|
| 129 | staticParameters.addAll( traitOrObject.staticParameters ) |
|---|
| 130 | // Extend the type analyzer with the collected static parameters |
|---|
| 131 | val oldTypeAnalyzer = typeAnalyzer |
|---|
| 132 | for ( f <- toSet(methods.firstSet) ; if isDeclaredName(f) ) { |
|---|
| 133 | typeAnalyzer = typeAnalyzer.extend(staticParameters, none[WhereClause]) |
|---|
| 134 | checkOverloading(f, toSet(methods.matchFirst(f)).asInstanceOf[Set[JavaFunctional]]) |
|---|
| 135 | } |
|---|
| 136 | typeAnalyzer = oldTypeAnalyzer |
|---|
| 137 | } |
|---|
| 138 | toJavaList(errors) |
|---|
| 139 | } |
|---|
| 140 | |
|---|
| 141 | /* Checks the validity of the overloaded function declarations. */ |
|---|
| 142 | private def checkOverloading(name: IdOrOpOrAnonymousName, |
|---|
| 143 | set: Set[JavaFunctional]) = { |
|---|
| 144 | var signatures = List[((JavaList[StaticParam],Type,Type),Span)]() |
|---|
| 145 | for ( f <- set ; if isDeclaredFunctional(f) ) { |
|---|
| 146 | val result = f.getReturnType.unwrap |
|---|
| 147 | val param = paramsToType(f.parameters, f.getSpan) |
|---|
| 148 | val sparams = f.staticParameters |
|---|
| 149 | signatures.find(p => p._1 == (sparams,param,result)) match { |
|---|
| 150 | case Some((_,span)) => |
|---|
| 151 | error(mergeSpan(span, f.getSpan), |
|---|
| 152 | "There are multiple declarations of " + |
|---|
| 153 | name + " with the same type: " + |
|---|
| 154 | param + " -> " + result) |
|---|
| 155 | case _ => |
|---|
| 156 | signatures = ((sparams, param, result), f.getSpan) :: signatures |
|---|
| 157 | } |
|---|
| 158 | } |
|---|
| 159 | var index = 1 |
|---|
| 160 | for ( first <- signatures ) { |
|---|
| 161 | signatures.slice(index, signatures.length) |
|---|
| 162 | .foreach(second => if (! validOverloading(first, second, signatures) ) { |
|---|
| 163 | val firstO = toString(first) |
|---|
| 164 | val secondO = toString(second) |
|---|
| 165 | val mismatch = if (firstO < secondO) |
|---|
| 166 | firstO + "\n and " + secondO |
|---|
| 167 | else |
|---|
| 168 | secondO + "\n and " + firstO |
|---|
| 169 | error(mergeSpan(first, second), |
|---|
| 170 | "Invalid overloading of " + name + |
|---|
| 171 | ":\n " + mismatch) |
|---|
| 172 | }) |
|---|
| 173 | index += 1 |
|---|
| 174 | } |
|---|
| 175 | } |
|---|
| 176 | |
|---|
| 177 | /* Checks the overloading rules: subtype / exclusion / meet */ |
|---|
| 178 | private def validOverloading(first: ((JavaList[StaticParam],Type,Type),Span), |
|---|
| 179 | second: ((JavaList[StaticParam],Type,Type),Span), |
|---|
| 180 | set: List[((JavaList[StaticParam],Type,Type),Span)]) = |
|---|
| 181 | subtype(first, second) || subtype(second, first) || |
|---|
| 182 | exclusion(first, second) || meet(first, second, set) |
|---|
| 183 | |
|---|
| 184 | /* Checks the overloading rule: subtype */ |
|---|
| 185 | private def subtype(f: JavaFunction, g: JavaFunction): Boolean = |
|---|
| 186 | subtype(paramsToType(g.parameters, g.getSpan), |
|---|
| 187 | paramsToType(f.parameters, f.getSpan)) && |
|---|
| 188 | subtype(f.getReturnType.unwrap, g.getReturnType.unwrap) |
|---|
| 189 | |
|---|
| 190 | private def subtype(sub_type: Type, super_type: Type): Boolean = |
|---|
| 191 | typeAnalyzer.subtype(sub_type, super_type).isTrue |
|---|
| 192 | |
|---|
| 193 | private def subtype(sub_type: ((JavaList[StaticParam],Type,Type),Span), |
|---|
| 194 | super_type: ((JavaList[StaticParam],Type,Type),Span)): Boolean = { |
|---|
| 195 | val oldTypeAnalyzer = typeAnalyzer |
|---|
| 196 | // Add static parameters of the method |
|---|
| 197 | val staticParameters = new ArrayList[StaticParam]() |
|---|
| 198 | staticParameters.addAll(sub_type._1._1) |
|---|
| 199 | staticParameters.addAll(super_type._1._1) |
|---|
| 200 | typeAnalyzer = typeAnalyzer.extend(staticParameters, none[WhereClause]) |
|---|
| 201 | val result = subtype(super_type._1._2, sub_type._1._2) && |
|---|
| 202 | subtype(sub_type._1._3, super_type._1._3) |
|---|
| 203 | typeAnalyzer = oldTypeAnalyzer |
|---|
| 204 | result |
|---|
| 205 | } |
|---|
| 206 | |
|---|
| 207 | /* Checks the overloading rule: exclusion |
|---|
| 208 | * Invariant: firstParam is not equal to secondParam |
|---|
| 209 | * The following types are not yet supported: |
|---|
| 210 | * Types tagged with dimensions or units |
|---|
| 211 | * Effects on arrow types |
|---|
| 212 | * Keyword parameters and varargs parameters |
|---|
| 213 | * Intersection types |
|---|
| 214 | * Union types |
|---|
| 215 | * Fixed-point types |
|---|
| 216 | */ |
|---|
| 217 | private def exclusion(first: ((JavaList[StaticParam],Type,Type),Span), |
|---|
| 218 | second: ((JavaList[StaticParam],Type,Type),Span)): Boolean = { |
|---|
| 219 | val oldTypeAnalyzer = typeAnalyzer |
|---|
| 220 | // Add static parameters of the method |
|---|
| 221 | val staticParameters = new ArrayList[StaticParam]() |
|---|
| 222 | staticParameters.addAll(first._1._1) |
|---|
| 223 | staticParameters.addAll(second._1._1) |
|---|
| 224 | typeAnalyzer = typeAnalyzer.extend(staticParameters, none[WhereClause]) |
|---|
| 225 | val result = new ExclusionOracle(typeAnalyzer, |
|---|
| 226 | new ErrorLog()).excludes(first._1._2, |
|---|
| 227 | second._1._2) |
|---|
| 228 | typeAnalyzer = oldTypeAnalyzer |
|---|
| 229 | result |
|---|
| 230 | } |
|---|
| 231 | |
|---|
| 232 | /* Checks the overloading rule: meet */ |
|---|
| 233 | /* Not yet fully implemented... */ |
|---|
| 234 | private def meet(first: ((JavaList[StaticParam],Type,Type),Span), |
|---|
| 235 | second: ((JavaList[StaticParam],Type,Type),Span), |
|---|
| 236 | set: List[((JavaList[StaticParam],Type,Type),Span)]) = { |
|---|
| 237 | val oldTypeAnalyzer = typeAnalyzer |
|---|
| 238 | // Add static parameters of the method |
|---|
| 239 | val staticParameters = new ArrayList[StaticParam]() |
|---|
| 240 | staticParameters.addAll(first._1._1) |
|---|
| 241 | staticParameters.addAll(second._1._1) |
|---|
| 242 | typeAnalyzer = typeAnalyzer.extend(staticParameters, none[WhereClause]) |
|---|
| 243 | var result = false |
|---|
| 244 | val exclusionOracle = new ExclusionOracle(typeAnalyzer, new ErrorLog()) |
|---|
| 245 | val meet = (reduce(typeAnalyzer.meet(first._1._2, second._1._2), exclusionOracle), |
|---|
| 246 | reduce(typeAnalyzer.meet(first._1._3, second._1._3), exclusionOracle)) |
|---|
| 247 | for ( f <- set ; if ! result ) |
|---|
| 248 | if ( subtype(f._1._2, meet._1) && |
|---|
| 249 | subtype(meet._1, f._1._2) && |
|---|
| 250 | subtype(meet._2, f._1._3) && |
|---|
| 251 | subtype(f._1._3, meet._2)) |
|---|
| 252 | result = true |
|---|
| 253 | typeAnalyzer = oldTypeAnalyzer |
|---|
| 254 | result |
|---|
| 255 | } |
|---|
| 256 | |
|---|
| 257 | /* If "t" is an intersection type of "elements", |
|---|
| 258 | * - if there are tuple types and non-tuple types in "elements" |
|---|
| 259 | * return BottomType |
|---|
| 260 | * - if "elements" are all non-tuple types |
|---|
| 261 | * check comprises clauses |
|---|
| 262 | * - if "elements" are all tuple types |
|---|
| 263 | * simplify "t" |
|---|
| 264 | */ |
|---|
| 265 | private def reduce(t: Type, exclusionOracle: ExclusionOracle): Type = t match { |
|---|
| 266 | case SIntersectionType(info, elements) => |
|---|
| 267 | val (tuples, nots) = elements.partition(NodeUtil.isTupleType) |
|---|
| 268 | if ( ! tuples.isEmpty && ! nots.isEmpty ) NodeFactory.makeBottomType(info) |
|---|
| 269 | else if ( tuples.isEmpty ) { |
|---|
| 270 | // If all the "elements" have comprises clauses |
|---|
| 271 | // and they all include type "M", then "M" is the meet. |
|---|
| 272 | existComprisedMeet(elements, exclusionOracle) match { |
|---|
| 273 | case Some(m) => m |
|---|
| 274 | case _ => t |
|---|
| 275 | } |
|---|
| 276 | } else { |
|---|
| 277 | val size = NodeUtil.getTupleTypeSize(tuples.head) |
|---|
| 278 | if ( tuples.forall(ty => NodeUtil.getTupleTypeSize(ty) == size && |
|---|
| 279 | ! NodeUtil.hasVarargs(ty) && |
|---|
| 280 | ! NodeUtil.hasKeywords(ty)) ) { |
|---|
| 281 | var elems = List[Type]() |
|---|
| 282 | var i = 0 |
|---|
| 283 | while ( i < size ) { |
|---|
| 284 | elems = elems ::: List(typeAnalyzer.meet(toJavaList(tuples.map(ty => NodeUtil.getTupleTypeElem(ty, i))))) |
|---|
| 285 | i += 1 |
|---|
| 286 | } |
|---|
| 287 | val mt = NodeFactory.makeTupleType(NodeUtil.getSpan(t), toJavaList(elems)) |
|---|
| 288 | NodeFactory.makeIntersectionType(info, toJavaList(mt :: tuples)) |
|---|
| 289 | } else t |
|---|
| 290 | } |
|---|
| 291 | case _ => t |
|---|
| 292 | } |
|---|
| 293 | |
|---|
| 294 | /* If all the "types" have comprises clauses |
|---|
| 295 | * and they all include types "comprised", |
|---|
| 296 | * then if "comprised" = {"M"} and all the others are exclusive |
|---|
| 297 | * then "M" is the meet |
|---|
| 298 | */ |
|---|
| 299 | private def existComprisedMeet(types: List[Type], |
|---|
| 300 | exclusionOracle: ExclusionOracle): Option[TraitType] = { |
|---|
| 301 | var allComprises = List[(Id, List[TraitType])]() |
|---|
| 302 | var meets: List[TraitType] = null |
|---|
| 303 | for ( t <- types ) { |
|---|
| 304 | if ( t.isInstanceOf[TraitType] ) { |
|---|
| 305 | val name = t.asInstanceOf[TraitType].getName |
|---|
| 306 | STypesUtil.getTypes(name, globalEnv, compilation_unit) match { |
|---|
| 307 | case ti:ProperTraitIndex => |
|---|
| 308 | var comprises = List[TraitType]() |
|---|
| 309 | for ( s <- toSet(ti.comprisesTypes) ) comprises = s::comprises |
|---|
| 310 | allComprises = (name, comprises)::allComprises |
|---|
| 311 | if ( ! comprises.isEmpty ) { |
|---|
| 312 | if ( meets == null ) meets = comprises |
|---|
| 313 | else meets = meets.intersect(comprises) |
|---|
| 314 | } else return None // no comprises clause |
|---|
| 315 | case _ => return None // not a trait |
|---|
| 316 | } |
|---|
| 317 | } else return None |
|---|
| 318 | } |
|---|
| 319 | if ( meets.length == 1 ) { |
|---|
| 320 | val meet = meets.head |
|---|
| 321 | def nonExclusive(pair: (List[TraitType], List[TraitType])): Boolean = { |
|---|
| 322 | for ( first <- pair._1 - meet ) { |
|---|
| 323 | for ( second <- pair._2 - meet ) { |
|---|
| 324 | if ( typeAnalyzer.equivalent(first, second).isFalse && |
|---|
| 325 | ! exclusionOracle.excludes(first, second) ) |
|---|
| 326 | return true |
|---|
| 327 | } |
|---|
| 328 | } |
|---|
| 329 | false |
|---|
| 330 | } |
|---|
| 331 | for ( first <- allComprises ) { |
|---|
| 332 | for ( second <- allComprises ; |
|---|
| 333 | if ! first._1.getText.equals(second._1.getText) ) { |
|---|
| 334 | if ( nonExclusive(first._2, second._2) ) return None |
|---|
| 335 | } |
|---|
| 336 | } |
|---|
| 337 | Some(meet) |
|---|
| 338 | } else None |
|---|
| 339 | } |
|---|
| 340 | |
|---|
| 341 | /* Returns the set of overloaded function declarations |
|---|
| 342 | * covering the given set of the overloaded declarations. |
|---|
| 343 | * Invariant: set.size > 1 |
|---|
| 344 | */ |
|---|
| 345 | def coverOverloading(set: Set[JavaFunction]) = { |
|---|
| 346 | var result = Set[JavaFunction]() |
|---|
| 347 | for ( f <- set ) { if ( ! coveredBy(f, result) ) result = result + f } |
|---|
| 348 | result = result.filter(f => f match { case DeclaredFunction(_) => true |
|---|
| 349 | case _ => false } ) |
|---|
| 350 | result.map(f => f match { case DeclaredFunction(fd) => fd }) |
|---|
| 351 | } |
|---|
| 352 | |
|---|
| 353 | private def coveredBy(f: JavaFunction, set: Set[JavaFunction]): Boolean = { |
|---|
| 354 | var result = false |
|---|
| 355 | for ( g <- set ; if ! result ) { if ( coveredBy(f, g) ) result = true } |
|---|
| 356 | result |
|---|
| 357 | } |
|---|
| 358 | |
|---|
| 359 | /* Whether the signature of f is covered by the signature of g */ |
|---|
| 360 | private def coveredBy(f: JavaFunction, g: JavaFunction): Boolean = { |
|---|
| 361 | val staticParameters = new ArrayList[StaticParam]() |
|---|
| 362 | // Add static parameters of "f" |
|---|
| 363 | staticParameters.addAll(f.staticParameters) |
|---|
| 364 | // If "f" is a functional method, |
|---|
| 365 | // add static parameters of "f"'s enclosing trait or object |
|---|
| 366 | if ( NodeUtil.isFunctionalMethod(f) ) { |
|---|
| 367 | val ind = typeAnalyzer.traitTable.typeCons(NodeUtil.getDeclaringTrait(f)) |
|---|
| 368 | if ( ind.isSome && NodeUtil.isTraitOrObject(ind.unwrap) ) { |
|---|
| 369 | staticParameters.addAll( NodeUtil.getStaticParameters(ind.unwrap) ) |
|---|
| 370 | } |
|---|
| 371 | } |
|---|
| 372 | // If "g" is a functional method, |
|---|
| 373 | // add static parameters of "g"'s enclosing trait or object |
|---|
| 374 | if ( NodeUtil.isFunctionalMethod(g) ) { |
|---|
| 375 | val ind = typeAnalyzer.traitTable.typeCons(NodeUtil.getDeclaringTrait(g)) |
|---|
| 376 | if ( ind.isSome && NodeUtil.isTraitOrObject(ind.unwrap) ) { |
|---|
| 377 | staticParameters.addAll( NodeUtil.getStaticParameters(ind.unwrap) ) |
|---|
| 378 | } |
|---|
| 379 | } |
|---|
| 380 | // Add static parameters of "g" |
|---|
| 381 | for ( s <- toList(g.staticParameters) ) staticParameters.add(s) |
|---|
| 382 | // Extend the type analyzer with the collected static parameters |
|---|
| 383 | val oldTypeAnalyzer = typeAnalyzer |
|---|
| 384 | // Whether "g"'s parameter type is a subtype of "f"'s parameter type |
|---|
| 385 | // and "f"'s return type is a subtype of "g"'s return type |
|---|
| 386 | typeAnalyzer = typeAnalyzer.extend(staticParameters, none[WhereClause]) |
|---|
| 387 | val result = subtype(f, g) |
|---|
| 388 | typeAnalyzer = oldTypeAnalyzer |
|---|
| 389 | result |
|---|
| 390 | } |
|---|
| 391 | |
|---|
| 392 | def isDeclaredName(f: IdOrOpOrAnonymousName) = f match { |
|---|
| 393 | case SId(_,_,str) => IdentifierUtil.validId(str) |
|---|
| 394 | case SOp(_,_,str,_,_) => NodeUtil.validOp(str) |
|---|
| 395 | case _ => false |
|---|
| 396 | } |
|---|
| 397 | |
|---|
| 398 | def isDeclaredFunctional(f: JavaFunctional) = f match { |
|---|
| 399 | case DeclaredFunction(fd) => true |
|---|
| 400 | case DeclaredMethod(_,_) => true |
|---|
| 401 | case _ => false |
|---|
| 402 | } |
|---|
| 403 | |
|---|
| 404 | private def mergeSpan(sub_type: ((JavaList[StaticParam],Type,Type),Span), |
|---|
| 405 | super_type: ((JavaList[StaticParam],Type,Type),Span)): String = |
|---|
| 406 | mergeSpan(sub_type._2, super_type._2) |
|---|
| 407 | |
|---|
| 408 | private def mergeSpan(first: Span, second: Span): String = |
|---|
| 409 | if (first.toString < second.toString) |
|---|
| 410 | first.toString + ":\n" + second.toString |
|---|
| 411 | else |
|---|
| 412 | second.toString + ":\n" + first.toString |
|---|
| 413 | |
|---|
| 414 | private def toString(ty: ((JavaList[StaticParam],Type,Type), Span)): String = |
|---|
| 415 | ty._1._2 + " -> " + ty._1._3 + " @ " + ty._2 |
|---|
| 416 | |
|---|
| 417 | /* Returns the type of the given list of parameters. */ |
|---|
| 418 | private def paramsToType(params: JavaList[Param], span: Span): Type = |
|---|
| 419 | params.size match { |
|---|
| 420 | case 0 => NodeFactory.makeVoidType(span) |
|---|
| 421 | case 1 => paramToType(params.get(0)) |
|---|
| 422 | case _ => |
|---|
| 423 | NodeFactory.makeTupleType(NodeUtil.spanAll(params), |
|---|
| 424 | Lists.toJavaList(Lists.toList(params).map(p => paramToType(p)))) |
|---|
| 425 | } |
|---|
| 426 | |
|---|
| 427 | /* Returns the type of the given parameter. */ |
|---|
| 428 | private def paramToType(param: Param): Type = |
|---|
| 429 | toOption(param.getIdType) match { |
|---|
| 430 | case Some(ty) => ty |
|---|
| 431 | case _ => |
|---|
| 432 | toOption(param.getVarargsType) match { |
|---|
| 433 | case Some(ty) => ty |
|---|
| 434 | case _ => |
|---|
| 435 | val span = NodeUtil.getSpan(param) |
|---|
| 436 | error(span.toString, |
|---|
| 437 | "Type checking couldn't infer the type of " + param) |
|---|
| 438 | NodeFactory.makeVoidType(span) |
|---|
| 439 | } |
|---|
| 440 | } |
|---|
| 441 | |
|---|
| 442 | private def error(loc: String, msg: String) = |
|---|
| 443 | errors = errors ::: List(TypeError.make(msg, loc.toString)) |
|---|
| 444 | |
|---|
| 445 | /* Returns true if any of the concrete method declarations in "decls" |
|---|
| 446 | implements the abstract method declaration "d". |
|---|
| 447 | */ |
|---|
| 448 | private def implement(d: FnDecl, decls: List[Decl]): Boolean = |
|---|
| 449 | decls.exists( (decl: Decl) => decl match { |
|---|
| 450 | case fd@SFnDecl(_,_,_,_,_) => implement(d, fd) |
|---|
| 451 | case _ => false |
|---|
| 452 | } ) |
|---|
| 453 | |
|---|
| 454 | /* Returns true if the concrete method declaration "decl" |
|---|
| 455 | implements the abstract method declaration "d". |
|---|
| 456 | */ |
|---|
| 457 | private def implement(d: FnDecl, decl: FnDecl): Boolean = |
|---|
| 458 | NodeUtil.getName(d).asInstanceOf[IdOrOp].getText.equals(NodeUtil.getName(decl).asInstanceOf[IdOrOp].getText) && |
|---|
| 459 | NodeUtil.getMods(d).containsAll(NodeUtil.getMods(decl)) && |
|---|
| 460 | ( typeAnalyzer.equivalent(NodeUtil.getParamType(d), |
|---|
| 461 | NodeUtil.getParamType(decl)).isTrue || |
|---|
| 462 | implement(toList(NodeUtil.getParams(d)), toList(NodeUtil.getParams(decl))) ) && |
|---|
| 463 | typeAnalyzer.equivalent(NodeUtil.getReturnType(d).unwrap, |
|---|
| 464 | NodeUtil.getReturnType(decl).unwrap).isTrue |
|---|
| 465 | |
|---|
| 466 | /* Returns true if the parameters of the concrete method declaration "params" |
|---|
| 467 | `implements' the parameters of the abstract method declaration "ps". |
|---|
| 468 | */ |
|---|
| 469 | private def implement(ps: List[Param], params: List[Param]): Boolean = |
|---|
| 470 | ! ps.zip(params).exists( (p:(Param,Param)) => |
|---|
| 471 | typeAnalyzer.equivalent(NodeUtil.getParamType(p._1), |
|---|
| 472 | NodeUtil.getParamType(p._2)).isFalse && |
|---|
| 473 | ! p._1.getName.getText.equals("self") ) |
|---|
| 474 | |
|---|
| 475 | private def inheritedAbstractMethods(extended_traits: List[TraitTypeWhere]) = |
|---|
| 476 | inheritedAbstractMethodsHelper(new HierarchyHistory(), extended_traits) |
|---|
| 477 | |
|---|
| 478 | private def inheritedAbstractMethodsHelper(hist: HierarchyHistory, |
|---|
| 479 | extended_traits: List[TraitTypeWhere]): |
|---|
| 480 | Map[IdOrOp, Set[FnDecl]] = { |
|---|
| 481 | var h = hist |
|---|
| 482 | var map = new HashMap[IdOrOp, Set[FnDecl]]() |
|---|
| 483 | for ( trait_ <- extended_traits ; if ! h.hasExplored(trait_.getBaseType) ) { |
|---|
| 484 | trait_.getBaseType match { |
|---|
| 485 | case ty@STraitType(info, name, args, params) => |
|---|
| 486 | h = h.explore(ty) |
|---|
| 487 | val tci = typeAnalyzer.traitTable.typeCons(name) |
|---|
| 488 | if ( tci.isSome && tci.unwrap.isInstanceOf[TraitIndex] ) { |
|---|
| 489 | val ti = tci.unwrap.asInstanceOf[TraitIndex] |
|---|
| 490 | map.put(name, collectAbstractMethods(name, toList(NodeUtil.getDecls(ti.ast)))) |
|---|
| 491 | map ++= inheritedAbstractMethodsHelper(h, toList(ti.extendsTypes)) |
|---|
| 492 | } else error(NodeUtil.getSpan(trait_).toString, |
|---|
| 493 | "Trait types are expected in an extends clause but found " |
|---|
| 494 | + ty.toStringVerbose + "\n" + tci.getClass) |
|---|
| 495 | case SAnyType(_) => |
|---|
| 496 | case ty => error(NodeUtil.getSpan(trait_).toString, |
|---|
| 497 | "Trait types are expected in an extends clause but found " |
|---|
| 498 | + ty.toStringVerbose) |
|---|
| 499 | } |
|---|
| 500 | } |
|---|
| 501 | map |
|---|
| 502 | } |
|---|
| 503 | |
|---|
| 504 | private def collectAbstractMethods(name: IdOrOp, decls: List[Decl]) = { |
|---|
| 505 | val set = new HashSet[FnDecl] |
|---|
| 506 | decls.foreach( (d: Decl) => d match { |
|---|
| 507 | case fd@SFnDecl(_,SFnHeader(_,mods,_,_,_,_,_,_),_,body,_) => |
|---|
| 508 | if ( compilation_unit.typeConses.keySet.contains(name) ) { |
|---|
| 509 | if ( ! body.isDefined ) set += fd |
|---|
| 510 | } else if ( mods.isAbstract ) set += fd |
|---|
| 511 | case _ => }) |
|---|
| 512 | set |
|---|
| 513 | } |
|---|
| 514 | } |
|---|