1f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassettipackage com.github.javaparser.symbolsolver.resolution.typeinference.constraintformulas;
2f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti
3e8007447885c3ee0a462444cbc7fa83e80297f4aFederico Tomassettiimport com.github.javaparser.resolution.types.ResolvedType;
4f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassettiimport com.github.javaparser.symbolsolver.model.resolution.TypeSolver;
5f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassettiimport com.github.javaparser.symbolsolver.model.typesystem.ReferenceTypeImpl;
6f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassettiimport com.github.javaparser.symbolsolver.resolution.typeinference.BoundSet;
7f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassettiimport com.github.javaparser.symbolsolver.resolution.typeinference.ConstraintFormula;
8f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassettiimport com.github.javaparser.symbolsolver.resolution.typesolvers.ReflectionTypeSolver;
9f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti
10f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassettiimport static com.github.javaparser.symbolsolver.resolution.typeinference.TypeHelper.isCompatibleInALooseInvocationContext;
11f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassettiimport static com.github.javaparser.symbolsolver.resolution.typeinference.TypeHelper.isProperType;
12f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti
13f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti/**
14f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti * A type S is compatible in a loose invocation context with type T
15f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti *
16f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti * @author Federico Tomassetti
17f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti */
18f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassettipublic class TypeCompatibleWithType extends ConstraintFormula {
19e8007447885c3ee0a462444cbc7fa83e80297f4aFederico Tomassetti    private ResolvedType s;
20e8007447885c3ee0a462444cbc7fa83e80297f4aFederico Tomassetti    private ResolvedType t;
21f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti    private TypeSolver typeSolver;
22f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti
23e8007447885c3ee0a462444cbc7fa83e80297f4aFederico Tomassetti    public TypeCompatibleWithType(TypeSolver typeSolver, ResolvedType s, ResolvedType t) {
24f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti        this.typeSolver = typeSolver;
25f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti        this.s = s;
26f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti        this.t = t;
27f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti    }
28f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti
29f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti    @Override
30f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti    public ReductionResult reduce(BoundSet currentBoundSet) {
31f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti        // A constraint formula of the form ‹S → T› is reduced as follows:
32f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti        //
33f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti        // 1. If S and T are proper types, the constraint reduces to true if S is compatible in a loose invocation context with T (§5.3), and false otherwise.
34f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti
35f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti        if (isProperType(s) && isProperType(t)) {
36f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti            if (isCompatibleInALooseInvocationContext(s, t)) {
37f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti                return ReductionResult.trueResult();
38f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti            } else {
39f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti                return ReductionResult.falseResult();
40f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti            }
41f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti        }
42f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti
43f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti        // 2. Otherwise, if S is a primitive type, let S' be the result of applying boxing conversion (§5.1.7) to S. Then the constraint reduces to ‹S' → T›.
44f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti
45f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti        if (s.isPrimitive()) {
46f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti            ReflectionTypeSolver typeSolver = new ReflectionTypeSolver();
47e8007447885c3ee0a462444cbc7fa83e80297f4aFederico Tomassetti            ResolvedType sFirst = new ReferenceTypeImpl(typeSolver.solveType(s.asPrimitive().getBoxTypeQName()), typeSolver);
48f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti            return ReductionResult.oneConstraint(new TypeCompatibleWithType(typeSolver, sFirst, t));
49f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti        }
50f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti
51f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti        // 3. Otherwise, if T is a primitive type, let T' be the result of applying boxing conversion (§5.1.7) to T. Then the constraint reduces to ‹S = T'›.
52f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti
53f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti        if (t.isPrimitive()) {
54f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti            ReflectionTypeSolver typeSolver = new ReflectionTypeSolver();
55e8007447885c3ee0a462444cbc7fa83e80297f4aFederico Tomassetti            ResolvedType tFirst = new ReferenceTypeImpl(typeSolver.solveType(t.asPrimitive().getBoxTypeQName()), typeSolver);
56f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti            return ReductionResult.oneConstraint(new TypeSameAsType(s, tFirst));
57f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti        }
58f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti
59f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti        // The fourth and fifth cases are implicit uses of unchecked conversion (§5.1.9). These, along with any use of
60f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti        // unchecked conversion in the first case, may result in compile-time unchecked warnings, and may influence a
61f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti        // method's invocation type (§15.12.2.6).
62f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti
63f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti        // 4. Otherwise, if T is a parameterized type of the form G<T1, ..., Tn>, and there exists no type of the
64f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti        //    form G<...> that is a supertype of S, but the raw type G is a supertype of S, then the constraint reduces
65f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti        //    to true.
66f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti
67f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti        if (t.isReferenceType() && !t.asReferenceType().getTypeDeclaration().getTypeParameters().isEmpty()) {
68f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti            // FIXME I really cannot understand what the specification means...
69f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti
70f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti            // there exists a type of the form G<...> that is a supertype of S?
71f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti            boolean condition1 = t.isAssignableBy(s);
72f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti
73f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti            // the raw type G is a supertype of S
74e8007447885c3ee0a462444cbc7fa83e80297f4aFederico Tomassetti            ResolvedType G = t.asReferenceType().toRawType();
75f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti            boolean condition2 = G.isAssignableBy(s);
76f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti
77f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti            if (!condition1 && condition2) {
78f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti                return ReductionResult.trueResult();
79f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti            }
80f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti
81f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti            //throw new UnsupportedOperationException();
82f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti        }
83f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti
84f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti        // 5. Otherwise, if T is an array type of the form G<T1, ..., Tn>[]k, and there exists no type of the form
85f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti        //    G<...>[]k that is a supertype of S, but the raw type G[]k is a supertype of S, then the constraint
86f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti        //    reduces to true. (The notation []k indicates an array type of k dimensions.)
87f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti
88f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti        if (t.isArray()) {
89f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti            throw new UnsupportedOperationException();
90f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti        }
91f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti
92f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti        // 6. Otherwise, the constraint reduces to ‹S <: T›
93f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti
94f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti        return ReductionResult.empty().withConstraint(new TypeSubtypeOfType(typeSolver, s, t));
95f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti    }
96f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti
97f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti    @Override
98f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti    public boolean equals(Object o) {
99f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti        if (this == o) return true;
100f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti        if (o == null || getClass() != o.getClass()) return false;
101f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti
102f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti        TypeCompatibleWithType that = (TypeCompatibleWithType) o;
103f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti
104f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti        if (!s.equals(that.s)) return false;
105f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti        return t.equals(that.t);
106f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti    }
107f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti
108f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti    @Override
109f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti    public int hashCode() {
110f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti        int result = s.hashCode();
111f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti        result = 31 * result + t.hashCode();
112f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti        return result;
113f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti    }
114f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti
115f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti    @Override
116f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti    public String toString() {
117f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti        return "TypeCompatibleWithType{" +
118f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti                "s=" + s +
119f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti                ", t=" + t +
120f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti                '}';
121f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti    }
122f30c3694b1c6dd5b3db5dfbbc1dddcbffbf6cb95Federico Tomassetti}
123