1307 private Map<InferenceBound, List<Type>> bounds; |
1307 private Map<InferenceBound, List<Type>> bounds; |
1308 |
1308 |
1309 /** inference variable's inferred type (set from Infer.java) */ |
1309 /** inference variable's inferred type (set from Infer.java) */ |
1310 public Type inst = null; |
1310 public Type inst = null; |
1311 |
1311 |
|
1312 /** number of declared (upper) bounds */ |
|
1313 public int declaredCount; |
|
1314 |
1312 /** inference variable's change listener */ |
1315 /** inference variable's change listener */ |
1313 public UndetVarListener listener = null; |
1316 public UndetVarListener listener = null; |
1314 |
1317 |
1315 @Override |
1318 @Override |
1316 public <R,S> R accept(Type.Visitor<R,S> v, S s) { |
1319 public <R,S> R accept(Type.Visitor<R,S> v, S s) { |
1317 return v.visitUndetVar(this, s); |
1320 return v.visitUndetVar(this, s); |
1318 } |
1321 } |
1319 |
1322 |
1320 public UndetVar(TypeVar origin, Types types) { |
1323 public UndetVar(TypeVar origin, Types types) { |
1321 this(origin, types, true); |
|
1322 } |
|
1323 |
|
1324 public UndetVar(TypeVar origin, Types types, boolean includeBounds) { |
|
1325 super(UNDETVAR, origin); |
1324 super(UNDETVAR, origin); |
1326 bounds = new EnumMap<InferenceBound, List<Type>>(InferenceBound.class); |
1325 bounds = new EnumMap<InferenceBound, List<Type>>(InferenceBound.class); |
1327 bounds.put(InferenceBound.UPPER, includeBounds ? types.getBounds(origin) : List.<Type>nil()); |
1326 List<Type> declaredBounds = types.getBounds(origin); |
|
1327 declaredCount = declaredBounds.length(); |
|
1328 bounds.put(InferenceBound.UPPER, declaredBounds); |
1328 bounds.put(InferenceBound.LOWER, List.<Type>nil()); |
1329 bounds.put(InferenceBound.LOWER, List.<Type>nil()); |
1329 bounds.put(InferenceBound.EQ, List.<Type>nil()); |
1330 bounds.put(InferenceBound.EQ, List.<Type>nil()); |
1330 } |
1331 } |
1331 |
1332 |
1332 public String toString() { |
1333 public String toString() { |
1338 if (inst != null) return inst.baseType(); |
1339 if (inst != null) return inst.baseType(); |
1339 else return this; |
1340 else return this; |
1340 } |
1341 } |
1341 |
1342 |
1342 /** get all bounds of a given kind */ |
1343 /** get all bounds of a given kind */ |
1343 public List<Type> getBounds(InferenceBound ib) { |
1344 public List<Type> getBounds(InferenceBound... ibs) { |
1344 return bounds.get(ib); |
1345 ListBuffer<Type> buf = ListBuffer.lb(); |
|
1346 for (InferenceBound ib : ibs) { |
|
1347 buf.appendList(bounds.get(ib)); |
|
1348 } |
|
1349 return buf.toList(); |
|
1350 } |
|
1351 |
|
1352 /** get the list of declared (upper) bounds */ |
|
1353 public List<Type> getDeclaredBounds() { |
|
1354 ListBuffer<Type> buf = ListBuffer.lb(); |
|
1355 int count = 0; |
|
1356 for (Type b : getBounds(InferenceBound.UPPER)) { |
|
1357 if (count++ == declaredCount) break; |
|
1358 buf.append(b); |
|
1359 } |
|
1360 return buf.toList(); |
1345 } |
1361 } |
1346 |
1362 |
1347 /** add a bound of a given kind - this might trigger listener notification */ |
1363 /** add a bound of a given kind - this might trigger listener notification */ |
1348 public void addBound(InferenceBound ib, Type bound, Types types) { |
1364 public void addBound(InferenceBound ib, Type bound, Types types) { |
|
1365 Type bound2 = toTypeVarMap.apply(bound); |
1349 List<Type> prevBounds = bounds.get(ib); |
1366 List<Type> prevBounds = bounds.get(ib); |
1350 for (Type b : prevBounds) { |
1367 for (Type b : prevBounds) { |
1351 if (types.isSameType(b, bound)) { |
1368 //check for redundancy - use strict version of isSameType on tvars |
1352 return; |
1369 //(as the standard version will lead to false positives w.r.t. clones ivars) |
|
1370 if (types.isSameType(b, bound2, true)) return; |
|
1371 } |
|
1372 bounds.put(ib, prevBounds.prepend(bound2)); |
|
1373 notifyChange(EnumSet.of(ib)); |
|
1374 } |
|
1375 //where |
|
1376 Type.Mapping toTypeVarMap = new Mapping("toTypeVarMap") { |
|
1377 @Override |
|
1378 public Type apply(Type t) { |
|
1379 if (t.hasTag(UNDETVAR)) { |
|
1380 UndetVar uv = (UndetVar)t; |
|
1381 return uv.qtype; |
|
1382 } else { |
|
1383 return t.map(this); |
|
1384 } |
1353 } |
1385 } |
1354 } |
1386 }; |
1355 bounds.put(ib, prevBounds.prepend(bound)); |
|
1356 notifyChange(EnumSet.of(ib)); |
|
1357 } |
|
1358 |
1387 |
1359 /** replace types in all bounds - this might trigger listener notification */ |
1388 /** replace types in all bounds - this might trigger listener notification */ |
1360 public void substBounds(List<Type> from, List<Type> to, Types types) { |
1389 public void substBounds(List<Type> from, List<Type> to, Types types) { |
1361 EnumSet<InferenceBound> changed = EnumSet.noneOf(InferenceBound.class); |
1390 List<Type> instVars = from.diff(to); |
1362 Map<InferenceBound, List<Type>> bounds2 = new EnumMap<InferenceBound, List<Type>>(InferenceBound.class); |
1391 //if set of instantiated ivars is empty, there's nothing to do! |
1363 for (Map.Entry<InferenceBound, List<Type>> _entry : bounds.entrySet()) { |
1392 if (instVars.isEmpty()) return; |
1364 InferenceBound ib = _entry.getKey(); |
1393 final EnumSet<InferenceBound> boundsChanged = EnumSet.noneOf(InferenceBound.class); |
1365 List<Type> prevBounds = _entry.getValue(); |
1394 UndetVarListener prevListener = listener; |
1366 List<Type> newBounds = types.subst(prevBounds, from, to); |
1395 try { |
1367 bounds2.put(ib, newBounds); |
1396 //setup new listener for keeping track of changed bounds |
1368 if (prevBounds != newBounds) { |
1397 listener = new UndetVarListener() { |
1369 changed.add(ib); |
1398 public void varChanged(UndetVar uv, Set<InferenceBound> ibs) { |
|
1399 boundsChanged.addAll(ibs); |
|
1400 } |
|
1401 }; |
|
1402 for (Map.Entry<InferenceBound, List<Type>> _entry : bounds.entrySet()) { |
|
1403 InferenceBound ib = _entry.getKey(); |
|
1404 List<Type> prevBounds = _entry.getValue(); |
|
1405 ListBuffer<Type> newBounds = ListBuffer.lb(); |
|
1406 ListBuffer<Type> deps = ListBuffer.lb(); |
|
1407 //step 1 - re-add bounds that are not dependent on ivars |
|
1408 for (Type t : prevBounds) { |
|
1409 if (!t.containsAny(instVars)) { |
|
1410 newBounds.append(t); |
|
1411 } else { |
|
1412 deps.append(t); |
|
1413 } |
|
1414 } |
|
1415 //step 2 - replace bounds |
|
1416 bounds.put(ib, newBounds.toList()); |
|
1417 //step 3 - for each dependency, add new replaced bound |
|
1418 for (Type dep : deps) { |
|
1419 addBound(ib, types.subst(dep, from, to), types); |
|
1420 } |
1370 } |
1421 } |
1371 } |
1422 } finally { |
1372 if (!changed.isEmpty()) { |
1423 listener = prevListener; |
1373 bounds = bounds2; |
1424 if (!boundsChanged.isEmpty()) { |
1374 notifyChange(changed); |
1425 notifyChange(boundsChanged); |
|
1426 } |
1375 } |
1427 } |
1376 } |
1428 } |
1377 |
1429 |
1378 private void notifyChange(EnumSet<InferenceBound> ibs) { |
1430 private void notifyChange(EnumSet<InferenceBound> ibs) { |
1379 if (listener != null) { |
1431 if (listener != null) { |