| 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.useful |
|---|
| 19 | |
|---|
| 20 | import _root_.java.util.ArrayList |
|---|
| 21 | import com.sun.fortress.compiler.GlobalEnvironment |
|---|
| 22 | import com.sun.fortress.compiler.Types |
|---|
| 23 | import com.sun.fortress.compiler.index._ |
|---|
| 24 | import com.sun.fortress.compiler.typechecker.StaticTypeReplacer |
|---|
| 25 | import com.sun.fortress.compiler.typechecker.TypeAnalyzer |
|---|
| 26 | import com.sun.fortress.compiler.typechecker.TypesUtil |
|---|
| 27 | import com.sun.fortress.exceptions.InterpreterBug.bug |
|---|
| 28 | import com.sun.fortress.exceptions.TypeError |
|---|
| 29 | import com.sun.fortress.nodes._ |
|---|
| 30 | import com.sun.fortress.nodes_util.ExprFactory |
|---|
| 31 | import com.sun.fortress.nodes_util.{NodeFactory => NF} |
|---|
| 32 | import com.sun.fortress.nodes_util.{NodeUtil => NU} |
|---|
| 33 | import com.sun.fortress.scala_src.nodes._ |
|---|
| 34 | import com.sun.fortress.scala_src.useful.Lists._ |
|---|
| 35 | import com.sun.fortress.scala_src.useful.Options._ |
|---|
| 36 | import com.sun.fortress.useful.HasAt |
|---|
| 37 | import com.sun.fortress.useful.NI |
|---|
| 38 | |
|---|
| 39 | object STypesUtil { |
|---|
| 40 | |
|---|
| 41 | /** |
|---|
| 42 | * A function type that takes two types and returns a boolean. |
|---|
| 43 | */ |
|---|
| 44 | type Subtype = (Type, Type) => Boolean |
|---|
| 45 | |
|---|
| 46 | /** |
|---|
| 47 | * Return the arrow type of the given FnDecl node. |
|---|
| 48 | */ |
|---|
| 49 | def makeArrowFromFnDecl(f: FnDecl): ArrowType = { |
|---|
| 50 | val returnType = f.getHeader.getReturnType.unwrap |
|---|
| 51 | val params = toList(f.getHeader.getParams).map(NU.getParamType) |
|---|
| 52 | val argType = makeArgumentType(params) |
|---|
| 53 | val sparams = f.getHeader.getStaticParams |
|---|
| 54 | val where = f.getHeader.getWhereClause |
|---|
| 55 | val throws = f.getHeader.getThrowsClause |
|---|
| 56 | NF.makeArrowType(NU.getSpan(f), |
|---|
| 57 | false, |
|---|
| 58 | argType, |
|---|
| 59 | returnType, |
|---|
| 60 | NF.makeEffect(throws), |
|---|
| 61 | sparams, |
|---|
| 62 | where) |
|---|
| 63 | } |
|---|
| 64 | |
|---|
| 65 | /** |
|---|
| 66 | * Return the arrow type of the given Method. |
|---|
| 67 | * @TODO Make sure that the getReturnType method in these indices works |
|---|
| 68 | * as it should. |
|---|
| 69 | */ |
|---|
| 70 | def makeArrowFromFunctional(f: Functional): ArrowType = f match { |
|---|
| 71 | case m:Method => |
|---|
| 72 | val returnType = m.getReturnType.unwrap |
|---|
| 73 | val params = toList(m.parameters).map(NU.getParamType) |
|---|
| 74 | val argType = makeArgumentType(params) |
|---|
| 75 | m match { |
|---|
| 76 | case m:DeclaredMethod => makeArrowFromFnDecl(m.ast) |
|---|
| 77 | case g:FieldGetterMethod => |
|---|
| 78 | NF.makeArrowType(NU.getSpan(g.ast), |
|---|
| 79 | argType, |
|---|
| 80 | returnType) |
|---|
| 81 | case s:FieldSetterMethod => |
|---|
| 82 | NF.makeArrowType(NU.getSpan(s.ast), |
|---|
| 83 | argType, |
|---|
| 84 | returnType) |
|---|
| 85 | } |
|---|
| 86 | case f:Function => f match { |
|---|
| 87 | case f:DeclaredFunction => makeArrowFromFnDecl(f.ast) |
|---|
| 88 | case f:FunctionalMethod => makeArrowFromFnDecl(f.ast) |
|---|
| 89 | case f:Constructor => |
|---|
| 90 | val argType = |
|---|
| 91 | makeArgumentType(toList(f.parameters).map(NU.getParamType)) |
|---|
| 92 | val returnType = f.getReturnType.unwrap |
|---|
| 93 | val sparams = f.staticParameters |
|---|
| 94 | val where = f.where |
|---|
| 95 | val throws = f.thrownTypes |
|---|
| 96 | NF.makeArrowType(NF.typeSpan, |
|---|
| 97 | false, |
|---|
| 98 | argType, |
|---|
| 99 | returnType, |
|---|
| 100 | NF.makeEffect(throws), |
|---|
| 101 | sparams, |
|---|
| 102 | where) |
|---|
| 103 | } |
|---|
| 104 | } |
|---|
| 105 | |
|---|
| 106 | /** |
|---|
| 107 | * Make a single argument type from a list of types. |
|---|
| 108 | */ |
|---|
| 109 | def makeArgumentType(ts: List[Type]): Type = ts match { |
|---|
| 110 | case Nil => Types.VOID |
|---|
| 111 | case t :: Nil => t |
|---|
| 112 | case _ => |
|---|
| 113 | val span1 = NU.getSpan(ts.head) |
|---|
| 114 | val span2 = NU.getSpan(ts.last) |
|---|
| 115 | NF.makeTupleType(NU.spanTwo(span1, span2), toJavaList(ts)) |
|---|
| 116 | } |
|---|
| 117 | |
|---|
| 118 | /** |
|---|
| 119 | * Make a domain type from a list of parameters, including varargs and |
|---|
| 120 | * keyword types. Ported from `TypeEnv.domainFromParams`. |
|---|
| 121 | */ |
|---|
| 122 | def makeDomainType(ps: List[Param]): Type = { |
|---|
| 123 | val paramTypes = new ArrayList[Type](ps.length) |
|---|
| 124 | val keywordTypes = new ArrayList[KeywordType](ps.length) |
|---|
| 125 | var varargsType: Option[Type] = None |
|---|
| 126 | val span = ps match { |
|---|
| 127 | case Nil => NF.typeSpan |
|---|
| 128 | case _ => NU.spanTwo(NU.getSpan(ps.first), NU.getSpan(ps.last)) |
|---|
| 129 | } |
|---|
| 130 | |
|---|
| 131 | // Extract out the appropriate parameter types. |
|---|
| 132 | ps.foreach(p => p match { |
|---|
| 133 | case SParam(_, _, _, _, _, Some(vaType)) => // Vararg |
|---|
| 134 | varargsType = Some(vaType) |
|---|
| 135 | case SParam(_, name, _, Some(idType), Some(expr), _) => // Keyword |
|---|
| 136 | keywordTypes.add(NF.makeKeywordType(name, idType)) |
|---|
| 137 | case SParam(_, _, _, Some(idType), _, _) => // Normal |
|---|
| 138 | paramTypes.add(idType) |
|---|
| 139 | case _ => bug("Parameter missing type") |
|---|
| 140 | }) |
|---|
| 141 | NF.makeDomain(span, paramTypes, toJavaOption(varargsType), keywordTypes) |
|---|
| 142 | } |
|---|
| 143 | |
|---|
| 144 | /** |
|---|
| 145 | * Convert a static parameter to the corresponding static arg. Ported from |
|---|
| 146 | * `TypeEnv.staticParamsToArgs`. |
|---|
| 147 | */ |
|---|
| 148 | def staticParamToArg(p: StaticParam): StaticArg = { |
|---|
| 149 | val span = NU.getSpan(p) |
|---|
| 150 | (p.getName, p.getKind) match { |
|---|
| 151 | case (id:Id, _:KindBool) => NF.makeBoolArg(span, NF.makeBoolRef(span, id)) |
|---|
| 152 | case (id:Id, _:KindDim) => NF.makeDimArg(span, NF.makeDimRef(span, id)) |
|---|
| 153 | case (id:Id, _:KindInt) => NF.makeIntArg(span, NF.makeIntRef(span, id)) |
|---|
| 154 | case (id:Id, _:KindNat) => NF.makeIntArg(span, NF.makeIntRef(span, id)) |
|---|
| 155 | case (id:Id, _:KindType) => NF.makeTypeArg(span, NF.makeVarType(span, id)) |
|---|
| 156 | case (id:Id, _:KindUnit) => |
|---|
| 157 | NF.makeUnitArg(span, NF.makeUnitRef(span, false, id)) |
|---|
| 158 | case (op:Op, _:KindOp) => NF.makeOpArg(span, ExprFactory.makeOpRef(op)) |
|---|
| 159 | case _ => bug("Unexpected static parameter kind") |
|---|
| 160 | } |
|---|
| 161 | } |
|---|
| 162 | |
|---|
| 163 | /** |
|---|
| 164 | * Get all the static parameters out of the given type. |
|---|
| 165 | */ |
|---|
| 166 | def getStaticParams(typ: Type): List[StaticParam] = |
|---|
| 167 | toList(typ.getInfo.getStaticParams) |
|---|
| 168 | |
|---|
| 169 | /** |
|---|
| 170 | * Return an identical type that has no static params. |
|---|
| 171 | * TODO: How to handle where clauses in TypeInfos? |
|---|
| 172 | */ |
|---|
| 173 | def clearStaticParams(typ: Type): Type = { |
|---|
| 174 | |
|---|
| 175 | // A walker that clears static params out of TypeInfos. |
|---|
| 176 | object paramWalker extends Walker { |
|---|
| 177 | override def walk(node: Any): Any = node match { |
|---|
| 178 | case STypeInfo(_, _, Nil, _) => node |
|---|
| 179 | case STypeInfo(a, b, _, _) => STypeInfo(a, b, Nil, None) |
|---|
| 180 | case _ => super.walk(node) |
|---|
| 181 | } |
|---|
| 182 | } |
|---|
| 183 | paramWalker(typ).asInstanceOf[Type] |
|---|
| 184 | } |
|---|
| 185 | |
|---|
| 186 | /** |
|---|
| 187 | * Insert static parameters into a type. If the type already has static |
|---|
| 188 | * parameters, a bug is thrown. |
|---|
| 189 | */ |
|---|
| 190 | def insertStaticParams(typ: Type, sparams: List[StaticParam]): Type = { |
|---|
| 191 | |
|---|
| 192 | // A walker that clears static params out of TypeInfos. |
|---|
| 193 | object paramWalker extends Walker { |
|---|
| 194 | override def walk(node: Any): Any = node match { |
|---|
| 195 | case STypeInfo(a, b, Nil, c) => STypeInfo(a, b, sparams, c) |
|---|
| 196 | case STypeInfo(_, _, _, _) => |
|---|
| 197 | bug("cannot overwrite static parameters") |
|---|
| 198 | case _ => super.walk(node) |
|---|
| 199 | } |
|---|
| 200 | } |
|---|
| 201 | paramWalker(typ).asInstanceOf |
|---|
| 202 | } |
|---|
| 203 | |
|---|
| 204 | /** |
|---|
| 205 | * Determine if the type previously inferred by the type checker from the |
|---|
| 206 | * given expression is an arrow or intersection of arrow types. |
|---|
| 207 | */ |
|---|
| 208 | def isArrows(expr: Expr): Boolean = isArrows(SExprUtil.getType(expr).get) |
|---|
| 209 | |
|---|
| 210 | /** |
|---|
| 211 | * Determine if the given type is an arrow or intersection of arrow types. |
|---|
| 212 | */ |
|---|
| 213 | def isArrows(ty: Type): Boolean = |
|---|
| 214 | TypesUtil.isArrows(ty).asInstanceOf[Boolean] |
|---|
| 215 | |
|---|
| 216 | /** |
|---|
| 217 | * Performs the given substitution on the body type. |
|---|
| 218 | */ |
|---|
| 219 | def substituteTypesForInferenceVars(substitution: Map[_InferenceVarType, Type], |
|---|
| 220 | body: Type): Type = { |
|---|
| 221 | |
|---|
| 222 | object substitutionWalker extends Walker { |
|---|
| 223 | override def walk(node: Any): Any = node match { |
|---|
| 224 | case ty:_InferenceVarType => substitution.get(ty).getOrElse(super.walk(ty)) |
|---|
| 225 | case _ => super.walk(node) |
|---|
| 226 | } |
|---|
| 227 | } |
|---|
| 228 | |
|---|
| 229 | // Perform the substitution on the body type. |
|---|
| 230 | substitutionWalker(body).asInstanceOf[Type] |
|---|
| 231 | } |
|---|
| 232 | |
|---|
| 233 | /** |
|---|
| 234 | * Returns the type of the static parameter's bound if it is a type parameter. |
|---|
| 235 | */ |
|---|
| 236 | def staticParamBoundType(sparam: StaticParam): Option[Type] = |
|---|
| 237 | sparam.getKind match { |
|---|
| 238 | case SKindType(_) => Some(NF.makeIntersectionType(sparam.getExtendsClause)) |
|---|
| 239 | case _ => None |
|---|
| 240 | } |
|---|
| 241 | |
|---|
| 242 | /** |
|---|
| 243 | * Given a static parameters, returns a static arg containing a fresh |
|---|
| 244 | * inference variable. |
|---|
| 245 | */ |
|---|
| 246 | def makeInferenceArg(sparam: StaticParam): StaticArg = sparam.getKind match { |
|---|
| 247 | case SKindType(_) => { |
|---|
| 248 | // Create a new inference var type. |
|---|
| 249 | val t = NF.make_InferenceVarType(NU.getSpan(sparam)) |
|---|
| 250 | NF.makeTypeArg(NF.makeSpan(t), t) |
|---|
| 251 | } |
|---|
| 252 | case SKindInt(_) => NI.nyi() |
|---|
| 253 | case SKindBool(_) => NI.nyi() |
|---|
| 254 | case SKindDim(_) => NI.nyi() |
|---|
| 255 | case SKindOp(_) => NI.nyi() |
|---|
| 256 | case SKindUnit(_) => NI.nyi() |
|---|
| 257 | case SKindNat(_) => NI.nyi() |
|---|
| 258 | case _ => bug("unexpected kind of static parameter") |
|---|
| 259 | } |
|---|
| 260 | |
|---|
| 261 | /** |
|---|
| 262 | * Returns a list of conjuncts of the given type. If given an intersection |
|---|
| 263 | * type, this is the set of the constituents. If ANY, this is empty. If some |
|---|
| 264 | * other type, this is the singleton set of that type. |
|---|
| 265 | */ |
|---|
| 266 | def conjuncts(ty: Type): Set[Type] = ty match { |
|---|
| 267 | case _:AnyType => Set.empty[Type] |
|---|
| 268 | case SIntersectionType(_, elts) => Set(elts:_*).flatMap(conjuncts) |
|---|
| 269 | case _ => Set(ty) |
|---|
| 270 | } |
|---|
| 271 | |
|---|
| 272 | /** |
|---|
| 273 | * Returns TypeConsIndex of "typ". |
|---|
| 274 | */ |
|---|
| 275 | def getTypes(typ:Id, globalEnv: GlobalEnvironment, |
|---|
| 276 | compilation_unit: CompilationUnitIndex): TypeConsIndex = typ match { |
|---|
| 277 | case SId(info,Some(name),text) => |
|---|
| 278 | globalEnv.api(name).typeConses.get(SId(info,None,text)) |
|---|
| 279 | case _ => compilation_unit.typeConses.get(typ) |
|---|
| 280 | } |
|---|
| 281 | } |
|---|