All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.extendj.ast.Constraints Maven / Gradle / Ivy

The newest version!
package org.extendj.ast;

import java.util.ArrayList;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.IOException;
import java.util.Set;
import beaver.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.LinkedHashSet;
import java.util.*;
import org.jastadd.util.PrettyPrintable;
import org.jastadd.util.PrettyPrinter;
import java.util.zip.*;
import java.io.*;
import org.jastadd.util.*;
import java.io.BufferedInputStream;
import java.io.DataInputStream;
/**
 * @ast class
 * @aspect GenericMethodsInference
 * @declaredat /home/jesper/git/extendj/java5/frontend/GenericMethodsInference.jrag:102
 */
 class Constraints extends java.lang.Object {
  
    /**
     * Set of type bounds for inferred type variables.
     */
    static class ConstraintSet {
      /** Lower type bounds. */
      public Collection lower = new HashSet(4);

      /** Upper type bounds. */
      public Collection upper = new HashSet(4);

      /** Equal type bounds. */
      public Collection equal = new HashSet(4);

      /**
       * Computed type argument.
       *
       * 

Set to {@code null} before inference starts and if no type matches * the bounds. */ public TypeDecl typeArgument; } private Collection typeVariables; protected Map constraintsMap; public boolean rawAccess = false; public Constraints() { typeVariables = new ArrayList(4); constraintsMap = new HashMap(); } public void addTypeVariable(TypeVariable T) { if (!typeVariables.contains(T)) { typeVariables.add(T); constraintsMap.put(T, new ConstraintSet()); } } public boolean unresolvedTypeArguments() { for (TypeVariable T : typeVariables) { ConstraintSet set = constraintsMap.get(T); if (set.typeArgument == null) { return true; } } return false; } public String toString() { StringBuilder str = new StringBuilder(); for (TypeVariable T : typeVariables) { ConstraintSet set = constraintsMap.get(T); for (TypeDecl U : set.lower) { if (str.length() > 0) { str.append("\n"); } str.append(T.fullName() + " :> " + U.fullName()); } for (TypeDecl U : set.upper) { if (str.length() > 0) { str.append("\n"); } str.append(T.fullName() + " <: " + U.fullName()); } for (TypeDecl U : set.equal) { if (str.length() > 0) { str.append("\n"); } str.append(T.fullName() + " = " + U.fullName()); } } return str.toString(); } public void resolveBounds() { for (TypeVariable T : typeVariables) { ConstraintSet set = constraintsMap.get(T); if (set.typeArgument == null) { set.typeArgument = T.firstBound().type(); } } } public void resolveEqualityConstraints() { for (TypeVariable T : typeVariables) { ConstraintSet set = constraintsMap.get(T); for (TypeDecl U : set.equal) { if (!typeVariables.contains(U)) { // Replace equality constraints for other type variables. replaceEqualityConstraints(T, U); set.equal.clear(); // Make U is the only equality constraint for T. set.equal.add(U); set.typeArgument = U; break; // Continue on next type variable. } else if (T == U) { // Discard constraint. } else { replaceAllConstraints(T, U); // Rewrite all constraints involving T to use U instead. break; // Continue on next type variable. } } if (set.typeArgument == null && set.equal.size() == 1 && set.equal.contains(T)) { set.typeArgument = T; } } } public void replaceEqualityConstraints(TypeDecl before, TypeDecl after) { for (TypeVariable T : typeVariables) { ConstraintSet set = constraintsMap.get(T); replaceConstraints(set.equal, before, after); } } public void replaceAllConstraints(TypeDecl before, TypeDecl after) { for (TypeVariable T : typeVariables) { ConstraintSet set = constraintsMap.get(T); replaceConstraints(set.lower, before, after); replaceConstraints(set.upper, before, after); replaceConstraints(set.equal, before, after); } } private void replaceConstraints(Collection constraints, TypeDecl before, TypeDecl after) { Collection newConstraints = new ArrayList(); for (Iterator iter = constraints.iterator(); iter.hasNext(); ) { TypeDecl U = iter.next(); if (U == before) { // TODO: fix parameterized type iter.remove(); newConstraints.add(after); } } constraints.addAll(newConstraints); } public void resolveSubtypeConstraints() { for (TypeVariable T : typeVariables) { ConstraintSet set = constraintsMap.get(T); if (set.typeArgument == null && !set.upper.isEmpty()) { if (set.upper.size() == 1) { set.typeArgument = set.upper.iterator().next(); } else { ArrayList bounds = new ArrayList(); for (TypeDecl type : set.upper) { bounds.add(type); } set.typeArgument = GLBTypeFactory.glb(bounds); } } } } public void resolveSupertypeConstraints() { for (TypeVariable T : typeVariables) { ConstraintSet set = constraintsMap.get(T); if (set.typeArgument == null && !set.lower.isEmpty()) { if (set.lower.size() == 1) { set.typeArgument = set.lower.iterator().next(); } else { set.typeArgument = T.lookupLUBType(set.lower).lub(); } } } } /** * Computes the direct supertypes of a type. */ protected static Collection directSupertypes(TypeDecl t) { // TODO(joqvist): this should be an attribute of TypeDecl instead. if (t instanceof ClassDecl) { ClassDecl type = (ClassDecl) t; Collection set = new HashSet(); if (type.hasSuperclass()) { set.add(type.superclass()); } for (int i = 0; i < type.getNumImplements(); i++) { set.add(type.getImplements(i).type()); } return set; } else if (t instanceof InterfaceDecl) { InterfaceDecl type = (InterfaceDecl) t; Collection set = new HashSet(); for (int i = 0; i < type.getNumSuperInterface(); i++) { set.add(type.getSuperInterface(i).type()); } return set; } else if (t instanceof TypeVariable) { TypeVariable type = (TypeVariable) t; Collection set = new HashSet(); for (int i = 0; i < type.getNumTypeBound(); i++) { set.add(type.getTypeBound(i).type()); } return set; } else { throw new Error(String.format( "Operation not supported for %s, %s", t.fullName(), t.getClass().getName())); } } /** * Computes the parameterized supertypes of some type. */ protected static Collection parameterizedSupertypes(TypeDecl type) { // TODO(joqvist): this should be an attribute of TypeDecl instead. Collection result = new HashSet(); addParameterizedSupertypes(type, new HashSet(), result); return result; } protected static void addParameterizedSupertypes(TypeDecl type, Collection processed, Collection result) { // TODO(joqvist): this should be an attribute of TypeDecl instead. if (!processed.contains(type)) { processed.add(type); if (type.isParameterizedType()) { result.add((ParTypeDecl) type); } for (TypeDecl typeDecl : directSupertypes(type)) { addParameterizedSupertypes(typeDecl, processed, result); } } } /** * Gives the inferred type arguments. */ public Collection typeArguments() { Collection list = new ArrayList(typeVariables.size()); for (TypeVariable T : typeVariables) { ConstraintSet set = constraintsMap.get(T); list.add(set.typeArgument); } return list; } /** * Adds A as a lower bound for type variable T. */ public void addSupertypeConstraint(TypeDecl T, TypeDecl A) { ConstraintSet set = constraintsMap.get(T); set.lower.add(A); } /** * Adds A as an upper bound for type variable T. */ public void addSubtypeConstraint(TypeDecl T, TypeDecl A) { ConstraintSet set = constraintsMap.get(T); set.upper.add(A); } /** * T = A : T and A are the same type. * *

This assigns type A to the type variable T. * *

It could happen that T and A refer to the same object, if the generic * method call is recursive. It is important to still add the * constraint T = T even though it may seen redundant: one type variable * represents the type variable in the generic method call, and one type * variable represents a type in the context of the method call. Removing * a constraint T = T removes information from the type inference and * breaks existing tests. See the regression test generics/method_23p. */ public void addEqualConstraint(TypeDecl T, TypeDecl A) { ConstraintSet set = constraintsMap.get(T); set.equal.add(A); } /** * A << F : A is convertible to F by method invocation conversion. * *

Note: convertibleTo and convertibleFrom are not symmetrical. * They differ in which side of the relation contains the type variables to * be inferred. * * @param A actual argument type. * @param F formal argument type (target type), containing type variables to be inferred. */ public void convertibleTo(TypeDecl A, TypeDecl F) { if (!F.involvesTypeParameters()) { // F does not involve a type parameter Tj. No constraint is implied on Tj. return; } if (A.isNull()) { // A is the type of null. No constraint is implied on Tj. return; } if (A.isUnboxedPrimitive()) { // A is a primitive type. A is converted to a reference type U // via boxing conversion and this algorithm is applied recursively to // the constraint U << F. TypeDecl U = A.boxed(); convertibleTo(U, F); } else if (F instanceof TypeVariable) { // F = Tj implies the constraint Tj :> A. if (typeVariables.contains(F)) { addSupertypeConstraint(F, A); } } else if (F.isArrayDecl()) { // If F = U[], where the type U involves Tj, then if A is an array type // V[] or a type variable with an upper bound that is an array type // V[], where V is a reference type, this algorithm is applied // recursively to the constraint V << U. TypeDecl U = F.componentType(); if (!U.involvesTypeParameters()) { return; } if (A.isArrayDecl()) { TypeDecl V = A.componentType(); if (V.isReferenceType()) { convertibleTo(V, U); } } else if (A.isTypeVariable()) { TypeVariable t = (TypeVariable) A; for (int i = 0; i < t.getNumTypeBound(); i++) { TypeDecl typeBound = t.getTypeBound(i).type(); if (typeBound.isArrayDecl() && typeBound.componentType().isReferenceType()) { TypeDecl V = typeBound.componentType(); convertibleTo(V, U); } } } } else if (F instanceof ParTypeDecl && !F.isRawType()) { ParTypeDecl PF = (ParTypeDecl) F; for (ParTypeDecl PA : parameterizedSupertypes(A)) { if (PF.genericDecl() == PA.genericDecl()) { if (A.isRawType()) { rawAccess = true; } else { java.util.List pfArgs = PF.getParameterization().args; java.util.List paArgs = PA.getParameterization().args; for (int i = 0; i < pfArgs.size(); i++) { TypeDecl T = pfArgs.get(i); if (T.involvesTypeParameters()) { if (!T.isWildcard()) { TypeDecl U = T; TypeDecl V = paArgs.get(i); constraintEqual(V, U); } else if (T instanceof WildcardExtendsType) { TypeDecl U = ((WildcardExtendsType) T).extendsType(); TypeDecl S = paArgs.get(i); if (!S.isWildcard()) { TypeDecl V = S; convertibleTo(V, U); } else if (S instanceof WildcardExtendsType) { TypeDecl V = ((WildcardExtendsType) S).extendsType(); convertibleTo(V, U); } } else if (T instanceof WildcardSuperType) { TypeDecl U = ((WildcardSuperType) T).superType(); TypeDecl S = paArgs.get(i); if (!S.isWildcard()) { TypeDecl V = S; convertibleFrom(V, U); } else if (S instanceof WildcardSuperType) { TypeDecl V = ((WildcardSuperType) S).superType(); convertibleFrom(V, U); } } } } } break; } } } } /** * A >> F : F is convertible to A by method invocation conversion. * *

Note: convertibleTo and convertibleFrom are not symmetrical. * They differ in which side of the relation contains the type variables to * be inferred. * * @param A actual argument type. * @param F formal argument type (target type), containing type variables to be inferred. */ public void convertibleFrom(TypeDecl A, TypeDecl F) { if (!F.involvesTypeParameters()) { // F does not involve a type parameter Tj. No constraint is implied on Tj. return; } else if (A.isNull()) { // A is the type of null. No constraint is implied on Tj. return; } else if (F instanceof TypeVariable) { if (typeVariables.contains(F)) { addSubtypeConstraint(F, A); } } else if (F.isArrayDecl()) { TypeDecl U = F.componentType(); if (A.isArrayDecl()) { TypeDecl V = A.componentType(); convertibleFrom(V, U); } else if (A.isTypeVariable()) { TypeVariable t = (TypeVariable) A; for (int i = 0; i < t.getNumTypeBound(); i++) { TypeDecl typeBound = t.getTypeBound(i).type(); if (typeBound.isArrayDecl() && typeBound.componentType().isReferenceType()) { TypeDecl V = typeBound.componentType(); convertibleFrom(V, U); } } } } else if (F instanceof ParTypeDecl && !F.isRawType() && A instanceof ParTypeDecl && !A.isRawType()) { ParTypeDecl PF = (ParTypeDecl) F; ParTypeDecl PA = (ParTypeDecl) A; java.util.List pfArgs = PF.getParameterization().args; java.util.List paArgs = PA.getParameterization().args; TypeDecl G = PF.genericDecl(); TypeDecl H = PA.genericDecl(); if (G.subtype(H)) { for (int i = 0; i < pfArgs.size(); i++) { TypeDecl T = pfArgs.get(i); if (T.involvesTypeParameters()) { // F has the form G<...,U,...> where U is a type expression that involves Tj. if (!T.isWildcard()) { TypeDecl U = T; if (H != G) { for (ParTypeDecl V : parameterizedSupertypes(F)) { if (V.genericDecl() == H) { if (!V.isRawType()) { // TODO(joqvist): must substitute type parameter i of G for T in H to get V! // See JLS7 \u00a715.12.2.7: https://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.12.2.7 if (F.subtype((TypeDecl) V)) { convertibleFrom(A, (TypeDecl) V); } } break; } } } else if (pfArgs.size() == paArgs.size()) { TypeDecl X = paArgs.get(i); if (!X.isWildcard()) { TypeDecl W = X; constraintEqual(W, U); } else if (X instanceof WildcardExtendsType) { TypeDecl W = ((WildcardExtendsType) X).extendsType(); convertibleFrom(W, U); } else if (X instanceof WildcardSuperType) { TypeDecl W = ((WildcardSuperType) X).superType(); convertibleTo(W, U); } } } else if (T instanceof WildcardExtendsType) { // F has the form G<..., ? extends U, ...> where U is a type expression // that involves Tj. TypeDecl U = ((WildcardExtendsType) T).extendsType(); if (H != G) { for (ParTypeDecl V : parameterizedSupertypes(F)) { if (V.genericDecl() == H) { if (!V.isRawType()) { // Replace type argument Un with ? extends Un in V. ArrayList list = new ArrayList(); for (TypeDecl vArg : V.getParameterization().args) { list.add(vArg.asWildcardExtends()); } TypeDecl typeV = ((GenericTypeDecl) H).lookupParTypeDecl(list); convertibleFrom(A, typeV); } break; } } } else if (pfArgs.size() == paArgs.size()) { TypeDecl X = paArgs.get(i); if (X instanceof WildcardExtendsType) { TypeDecl W = ((WildcardExtendsType) X).extendsType(); convertibleFrom(W, U); } } } else if (T instanceof WildcardSuperType) { // F has the form G<..., ? super U, ...> where U is a type expression // that involves Tj. TypeDecl U = ((WildcardSuperType) T).superType(); if (H != G) { for (ParTypeDecl V : parameterizedSupertypes(F)) { if (V.genericDecl() == H) { if (!V.isRawType()) { // Replace type argument Un with ? super Un in V. ArrayList list = new ArrayList(); for (TypeDecl vArg : V.getParameterization().args) { list.add(vArg.asWildcardExtends()); } TypeDecl typeV = ((GenericTypeDecl) H).lookupParTypeDecl(list); convertibleFrom(A, typeV); } break; } } } else if (pfArgs.size() == paArgs.size()) { TypeDecl X = paArgs.get(i); if (X instanceof WildcardSuperType) { TypeDecl W = ((WildcardSuperType) X).superType(); convertibleTo(W, U); } } } } } } } else if (F.isRawType()) { rawAccess = true; } } /** * T = A : T and A are the same type. */ public void constraintEqual(TypeDecl A, TypeDecl F) { if (!F.involvesTypeParameters()) { // F does not involve a type parameter Tj. No constraint is implied on Tj. return; } else if (A.isNull()) { // A is the type of null. No constraint is implied on Tj. return; } else if (F instanceof TypeVariable) { if (typeVariables.contains(F)) { addEqualConstraint(F, A); } } else if (F.isArrayDecl()) { TypeDecl U = F.componentType(); if (A.isArrayDecl()) { TypeDecl V = A.componentType(); constraintEqual(V, U); } else if (A.isTypeVariable()) { TypeVariable t = (TypeVariable) A; for (int i = 0; i < t.getNumTypeBound(); i++) { TypeDecl typeBound = t.getTypeBound(i).type(); if (typeBound.isArrayDecl() && typeBound.componentType().isReferenceType()) { TypeDecl V = typeBound.componentType(); constraintEqual(V, U); } } } } else if (F instanceof ParTypeDecl && !F.isRawType() && A instanceof ParTypeDecl) { ParTypeDecl PF = (ParTypeDecl) F; ParTypeDecl PA = (ParTypeDecl) A; java.util.List pfArgs = PF.getParameterization().args; java.util.List paArgs = PA.getParameterization().args; if (PF.genericDecl() == PA.genericDecl()) { if (A.isRawType()) { rawAccess = true; } else { for (int i = 0; i < pfArgs.size(); i++) { TypeDecl T = pfArgs.get(i); if (T.involvesTypeParameters()) { if (!T.isWildcard()) { TypeDecl U = T; TypeDecl V = paArgs.get(i); constraintEqual(V, U); } else if (T instanceof WildcardExtendsType) { TypeDecl U = ((WildcardExtendsType) T).extendsType(); TypeDecl S = paArgs.get(i); if (S instanceof WildcardExtendsType) { TypeDecl V = ((WildcardExtendsType) S).extendsType(); constraintEqual(V, U); } } else if (T instanceof WildcardSuperType) { TypeDecl U = ((WildcardSuperType) T).superType(); TypeDecl S = paArgs.get(i); if (S instanceof WildcardSuperType) { TypeDecl V = ((WildcardSuperType) S).superType(); constraintEqual(V, U); } } } } } } } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy