| 1 |
/******************************************************************************* |
|---|
| 2 |
Copyright 2008 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.interpreter.evaluator.values; |
|---|
| 19 |
|
|---|
| 20 |
import static com.sun.fortress.exceptions.InterpreterBug.bug; |
|---|
| 21 |
import static com.sun.fortress.exceptions.ProgramError.errorMsg; |
|---|
| 22 |
|
|---|
| 23 |
import java.util.ArrayList; |
|---|
| 24 |
import java.util.List; |
|---|
| 25 |
import edu.rice.cs.plt.tuple.Option; |
|---|
| 26 |
|
|---|
| 27 |
import com.sun.fortress.exceptions.FortressException; |
|---|
| 28 |
import com.sun.fortress.interpreter.evaluator.Environment; |
|---|
| 29 |
import com.sun.fortress.interpreter.evaluator.EvalType; |
|---|
| 30 |
import com.sun.fortress.interpreter.evaluator.types.FType; |
|---|
| 31 |
import com.sun.fortress.interpreter.evaluator.types.FTypeTuple; |
|---|
| 32 |
import com.sun.fortress.interpreter.evaluator.types.SymbolicBool; |
|---|
| 33 |
import com.sun.fortress.interpreter.evaluator.types.SymbolicInstantiatedType; |
|---|
| 34 |
import com.sun.fortress.interpreter.evaluator.types.SymbolicNat; |
|---|
| 35 |
import com.sun.fortress.interpreter.evaluator.types.SymbolicOprType; |
|---|
| 36 |
import com.sun.fortress.nodes.BaseType; |
|---|
| 37 |
import com.sun.fortress.nodes.BoolParam; |
|---|
| 38 |
import com.sun.fortress.nodes.IntParam; |
|---|
| 39 |
import com.sun.fortress.nodes.NatParam; |
|---|
| 40 |
import com.sun.fortress.nodes.OpParam; |
|---|
| 41 |
import com.sun.fortress.nodes.StaticParam; |
|---|
| 42 |
import com.sun.fortress.nodes.TypeAlias; |
|---|
| 43 |
import com.sun.fortress.nodes.TypeParam; |
|---|
| 44 |
import com.sun.fortress.nodes.WhereClause; |
|---|
| 45 |
import com.sun.fortress.nodes.WhereConstraint; |
|---|
| 46 |
import com.sun.fortress.nodes.WhereExtends; |
|---|
| 47 |
import com.sun.fortress.nodes_util.Applicable; |
|---|
| 48 |
import com.sun.fortress.nodes_util.NodeUtil; |
|---|
| 49 |
import com.sun.fortress.useful.HasAt; |
|---|
| 50 |
import com.sun.fortress.useful.Hasher; |
|---|
| 51 |
import com.sun.fortress.useful.MagicNumbers; |
|---|
| 52 |
import com.sun.fortress.useful.NI; |
|---|
| 53 |
import com.sun.fortress.useful.Useful; |
|---|
| 54 |
|
|---|
| 55 |
public abstract class SingleFcn extends Fcn implements HasAt { |
|---|
| 56 |
|
|---|
| 57 |
public SingleFcn(Environment within) { |
|---|
| 58 |
super(within); |
|---|
| 59 |
} |
|---|
| 60 |
|
|---|
| 61 |
abstract public String at(); |
|---|
| 62 |
abstract public List<FType> getDomain(); |
|---|
| 63 |
abstract public FType getRange(); |
|---|
| 64 |
public boolean isOverride() { return false; } |
|---|
| 65 |
|
|---|
| 66 |
/** |
|---|
| 67 |
* For now, prefer to unwrap tuples because that avoid creating |
|---|
| 68 |
* new memo entries for tuple types. |
|---|
| 69 |
* @return |
|---|
| 70 |
*/ |
|---|
| 71 |
public List<FType> getNormalizedDomain() { |
|---|
| 72 |
List<FType> d = getDomain(); |
|---|
| 73 |
if (d.size() == 1) { |
|---|
| 74 |
FType t = d.get(0); |
|---|
| 75 |
if (t instanceof FTypeTuple) { |
|---|
| 76 |
d = ((FTypeTuple) t).getTypes(); |
|---|
| 77 |
} |
|---|
| 78 |
} |
|---|
| 79 |
return d; |
|---|
| 80 |
|
|---|
| 81 |
} |
|---|
| 82 |
|
|---|
| 83 |
/** |
|---|
| 84 |
* This is just like getNormalizedDomain, except that the method version |
|---|
| 85 |
* of functional methods appends a "nat" Type indicating the position of |
|---|
| 86 |
* the self parameter. |
|---|
| 87 |
* @return |
|---|
| 88 |
*/ |
|---|
| 89 |
public List<FType> getNormalizedDomainForTables() { |
|---|
| 90 |
return getNormalizedDomain(); |
|---|
| 91 |
} |
|---|
| 92 |
|
|---|
| 93 |
public List<FValue> fixupArgCount(List<FValue> args) { |
|---|
| 94 |
System.out.println("Naive fixupArgCount "+this+ |
|---|
| 95 |
"("+this.getClass()+")"+ |
|---|
| 96 |
" of "+Useful.listInParens(args)); |
|---|
| 97 |
int dsz = getDomain().size(); |
|---|
| 98 |
if (args.size() == dsz) return args; |
|---|
| 99 |
return null; |
|---|
| 100 |
} |
|---|
| 101 |
|
|---|
| 102 |
// NOTE: I believe it is ok for functions to use object identity for |
|---|
| 103 |
// equals and hashCode(). |
|---|
| 104 |
|
|---|
| 105 |
static class SignatureEquivalence extends Hasher<SingleFcn> { |
|---|
| 106 |
@Override |
|---|
| 107 |
public long hash(SingleFcn x) { |
|---|
| 108 |
long a = (long) x.asMethodName().hashCode() * MagicNumbers.s; |
|---|
| 109 |
long b = (long) x.getNormalizedDomainForTables().hashCode() * MagicNumbers.l; |
|---|
| 110 |
// System.err.println("Hash of " + x + " yields " + a + " and " + b); |
|---|
| 111 |
|
|---|
| 112 |
return a + b; |
|---|
| 113 |
} |
|---|
| 114 |
|
|---|
| 115 |
@Override |
|---|
| 116 |
public boolean equiv(SingleFcn x, SingleFcn y) { |
|---|
| 117 |
List<FType> dx = x.getNormalizedDomainForTables(); |
|---|
| 118 |
List<FType> dy = y.getNormalizedDomainForTables(); |
|---|
| 119 |
if (dx.size() != dy.size()) |
|---|
| 120 |
return false; |
|---|
| 121 |
if (! x.asMethodName().equals(y.asMethodName())) |
|---|
| 122 |
return false; |
|---|
| 123 |
for (int i = 0; i < dx.size(); i++) { |
|---|
| 124 |
if (! dx.get(i).equals(dy.get(i))) |
|---|
| 125 |
return false; |
|---|
| 126 |
} |
|---|
| 127 |
return true; |
|---|
| 128 |
} |
|---|
| 129 |
|
|---|
| 130 |
} |
|---|
| 131 |
|
|---|
| 132 |
|
|---|
| 133 |
/** |
|---|
| 134 |
* Given a (generic) applicable, an environment for type |
|---|
| 135 |
* evaluation. and a location to which problems can be |
|---|
| 136 |
* attached, create the ordered list of symbolic instantiation |
|---|
| 137 |
* arguments consistent with the type parameters and where |
|---|
| 138 |
* clauses. The symbolic types so created will be tied to |
|---|
| 139 |
* a newly generated environment so that they do not contaminate |
|---|
| 140 |
* any "real" environments. |
|---|
| 141 |
* |
|---|
| 142 |
* The instantiated generics can be used to allow checks on |
|---|
| 143 |
* overloading. |
|---|
| 144 |
* |
|---|
| 145 |
* @throws Error |
|---|
| 146 |
*/ |
|---|
| 147 |
static public List<FType> createSymbolicInstantiation(Environment bte, Applicable ap, HasAt location) throws Error { |
|---|
| 148 |
List<StaticParam> tpl = ap.getStaticParams(); |
|---|
| 149 |
Option<WhereClause> wcl = ap.getWhere(); |
|---|
| 150 |
|
|---|
| 151 |
// The (possibly multiple and interrelated) symbolic |
|---|
| 152 |
// types must be created in an environment, but we don't |
|---|
| 153 |
// want to contaminate a "real" environment with these names. |
|---|
| 154 |
// We also don't want "crosstalk" between type parameters |
|---|
| 155 |
// to different overloaded things. |
|---|
| 156 |
Environment ge = bte.extendAt(location); |
|---|
| 157 |
|
|---|
| 158 |
// Note that we must arrange for the symbolic things |
|---|
| 159 |
// to meet the constraints required by the object. |
|---|
| 160 |
List<FType> instantiationTypes; |
|---|
| 161 |
try { |
|---|
| 162 |
instantiationTypes = createSymbolicInstantiation(tpl, wcl, ge); |
|---|
| 163 |
} catch (FortressException e) { |
|---|
| 164 |
e.setContext(location,ge); |
|---|
| 165 |
throw e; |
|---|
| 166 |
} |
|---|
| 167 |
return instantiationTypes; |
|---|
| 168 |
} |
|---|
| 169 |
|
|---|
| 170 |
static public List<FType> createSymbolicInstantiation(Environment bte, |
|---|
| 171 |
List<StaticParam> tpl, |
|---|
| 172 |
Option<WhereClause> wcl, |
|---|
| 173 |
HasAt location) throws Error { |
|---|
| 174 |
return createSymbolicInstantiation(tpl, wcl, bte.extendAt(location)); |
|---|
| 175 |
} |
|---|
| 176 |
/** |
|---|
| 177 |
* @param tpl |
|---|
| 178 |
* @param wcl |
|---|
| 179 |
* @param ge The generic environment that is being populated by this instantiation. |
|---|
| 180 |
* @throws Error |
|---|
| 181 |
*/ |
|---|
| 182 |
static private List<FType> createSymbolicInstantiation(List<StaticParam> tpl, Option<WhereClause> wcl, Environment ge) throws Error { |
|---|
| 183 |
ArrayList<FType> a = new ArrayList<FType>(); |
|---|
| 184 |
for (StaticParam tp: tpl) { |
|---|
| 185 |
String name = NodeUtil.getName(tp); |
|---|
| 186 |
FType t; |
|---|
| 187 |
if (tp instanceof TypeParam) { |
|---|
| 188 |
t = new SymbolicInstantiatedType(name, ge, tp); |
|---|
| 189 |
} else if (tp instanceof NatParam || tp instanceof IntParam) { |
|---|
| 190 |
t = new SymbolicNat(name); |
|---|
| 191 |
} else if (tp instanceof BoolParam) { |
|---|
| 192 |
t = new SymbolicBool(name); |
|---|
| 193 |
} else if (tp instanceof OpParam) { |
|---|
| 194 |
OpParam op = (OpParam) tp; |
|---|
| 195 |
t = new SymbolicOprType(name, ge, op); |
|---|
| 196 |
} else { |
|---|
| 197 |
return bug(tp, errorMsg("Unimplemented symbolic StaticParam ", tp)); |
|---|
| 198 |
} |
|---|
| 199 |
ge.putType(name, t); |
|---|
| 200 |
a.add(t); |
|---|
| 201 |
} |
|---|
| 202 |
|
|---|
| 203 |
// Expect that where clauses will add names and constraints. |
|---|
| 204 |
if ( wcl.isSome() ) { |
|---|
| 205 |
for (WhereConstraint wc : wcl.unwrap().getConstraints()) { |
|---|
| 206 |
if (wc instanceof TypeAlias) { |
|---|
| 207 |
TypeAlias ta = (TypeAlias) wc; |
|---|
| 208 |
NI.nyi("Where clauses - type alias"); |
|---|
| 209 |
} else if (wc instanceof WhereExtends) { |
|---|
| 210 |
WhereExtends we = (WhereExtends) wc; |
|---|
| 211 |
String we_name = we.getName().getText(); |
|---|
| 212 |
// List<Type> we_supers = we.getSupers(); |
|---|
| 213 |
if (ge.getTypeNull(we_name) == null) { |
|---|
| 214 |
// Add name |
|---|
| 215 |
SymbolicInstantiatedType st = new SymbolicInstantiatedType(we_name, ge, we); |
|---|
| 216 |
ge.putType(we_name, st); |
|---|
| 217 |
} |
|---|
| 218 |
} |
|---|
| 219 |
} |
|---|
| 220 |
} |
|---|
| 221 |
|
|---|
| 222 |
EvalType eval_type = new EvalType(ge); |
|---|
| 223 |
|
|---|
| 224 |
// Process constraints |
|---|
| 225 |
for (StaticParam tp: tpl) { |
|---|
| 226 |
String name = NodeUtil.getName(tp); |
|---|
| 227 |
if (tp instanceof TypeParam) { |
|---|
| 228 |
TypeParam stp = (TypeParam) tp; |
|---|
| 229 |
String stp_name = NodeUtil.getName(stp); |
|---|
| 230 |
SymbolicInstantiatedType st = (SymbolicInstantiatedType) ge.getType(stp_name); |
|---|
| 231 |
List<BaseType> oext = stp.getExtendsClause(); |
|---|
| 232 |
// pass null, no excludes here. |
|---|
| 233 |
// Note no need to replace environment, these |
|---|
| 234 |
// are precreated in a fresh environment. |
|---|
| 235 |
st.setExtendsAndExcludes(eval_type.getFTypeListFromList(oext), null); |
|---|
| 236 |
} else if (tp instanceof NatParam || tp instanceof IntParam || |
|---|
| 237 |
tp instanceof OpParam || tp instanceof BoolParam) { |
|---|
| 238 |
// No constraint handling right now |
|---|
| 239 |
} else { |
|---|
| 240 |
return bug(tp, errorMsg("Unexpected StaticParam ", tp)); |
|---|
| 241 |
} |
|---|
| 242 |
} |
|---|
| 243 |
|
|---|
| 244 |
// Expect that where clauses will add names and constraints. |
|---|
| 245 |
if ( wcl.isSome() ) { |
|---|
| 246 |
for (WhereConstraint wc : wcl.unwrap().getConstraints()) { |
|---|
| 247 |
if (wc instanceof TypeAlias) { |
|---|
| 248 |
NI.nyi("Where clauses - type alias"); |
|---|
| 249 |
TypeAlias ta = (TypeAlias) wc; |
|---|
| 250 |
} else if (wc instanceof WhereExtends) { |
|---|
| 251 |
WhereExtends we = (WhereExtends) wc; |
|---|
| 252 |
String we_name = we.getName().getText(); |
|---|
| 253 |
List<BaseType> we_supers = we.getSupers(); |
|---|
| 254 |
SymbolicInstantiatedType st = (SymbolicInstantiatedType) ge.getType(we_name); |
|---|
| 255 |
st.addExtends(eval_type.getFTypeListFromList(we_supers)); |
|---|
| 256 |
} |
|---|
| 257 |
} |
|---|
| 258 |
} |
|---|
| 259 |
|
|---|
| 260 |
return a; |
|---|
| 261 |
} |
|---|
| 262 |
|
|---|
| 263 |
public static Hasher<SingleFcn> signatureEquivalence = new SignatureEquivalence(); |
|---|
| 264 |
|
|---|
| 265 |
static class NameEquivalence extends Hasher<SingleFcn> { |
|---|
| 266 |
@Override |
|---|
| 267 |
public long hash(SingleFcn x) { |
|---|
| 268 |
long a = (long) x.getFnName().hashCode() * MagicNumbers.N; |
|---|
| 269 |
return a; |
|---|
| 270 |
} |
|---|
| 271 |
|
|---|
| 272 |
@Override |
|---|
| 273 |
public boolean equiv(SingleFcn x, SingleFcn y) { |
|---|
| 274 |
return x.getFnName().equals(y.getFnName()); |
|---|
| 275 |
} |
|---|
| 276 |
|
|---|
| 277 |
} |
|---|
| 278 |
|
|---|
| 279 |
public static Hasher<SingleFcn> nameEquivalence = new NameEquivalence(); |
|---|
| 280 |
|
|---|
| 281 |
|
|---|
| 282 |
} |
|---|