@Override public ProducedType getReference() { ProducedType pt = new ProducedType(); if (isMember()) { pt.setQualifyingType(((ClassOrInterface) getContainer()).getType()); } pt.setDeclaration(this); pt.setTypeArguments( getTypeArgumentMap(this, pt.getQualifyingType(), Collections.<ProducedType>emptyList())); return pt; }
private ProducedType substitutedType( Declaration dec, ProducedType pt, Map<TypeParameter, ProducedType> substitutions) { ProducedType type = new ProducedType(); type.setDeclaration(dec); ProducedType qt = pt.getQualifyingType(); if (qt != null) { type.setQualifyingType(substitute(qt, substitutions)); } type.setTypeArguments(substitutedTypeArguments(pt, substitutions)); return type; }
@Test public void testPackageQualified() { ProducedType type = new TypeParser(MockLoader.instance, mockUnit).decodeType("unknown.b", null); Assert.assertNotNull(type); TypeDeclaration declaration = type.getDeclaration(); Assert.assertNotNull(declaration); Assert.assertTrue(declaration instanceof Class); Assert.assertEquals("unknown.b", declaration.getName()); Assert.assertNull(type.getQualifyingType()); }
@Test public void testQualifiedAndParameterised() { ProducedType type = new TypeParser(MockLoader.instance, mockUnit).decodeType("t2<a,b>.t2<c,d>", null); Assert.assertNotNull(type); TypeDeclaration declaration = type.getDeclaration(); Assert.assertNotNull(declaration); Assert.assertTrue(declaration instanceof Class); Assert.assertEquals("t2.t2", declaration.getName()); Assert.assertEquals(2, type.getTypeArgumentList().size()); // c ProducedType c = type.getTypeArgumentList().get(0); Assert.assertEquals("c", c.getDeclaration().getName()); Assert.assertTrue(c.getDeclaration() instanceof Class); // d ProducedType d = type.getTypeArgumentList().get(1); Assert.assertEquals("d", d.getDeclaration().getName()); Assert.assertTrue(d.getDeclaration() instanceof Class); ProducedType qualifyingType = type.getQualifyingType(); Assert.assertNotNull(qualifyingType); TypeDeclaration qualifyingDeclaration = qualifyingType.getDeclaration(); Assert.assertNotNull(qualifyingDeclaration); Assert.assertTrue(qualifyingDeclaration instanceof Class); Assert.assertEquals("t2", qualifyingDeclaration.getName()); Assert.assertEquals(2, qualifyingType.getTypeArgumentList().size()); // a ProducedType a = qualifyingType.getTypeArgumentList().get(0); Assert.assertEquals("a", a.getDeclaration().getName()); Assert.assertTrue(a.getDeclaration() instanceof Class); // b ProducedType b = qualifyingType.getTypeArgumentList().get(1); Assert.assertEquals("b", b.getDeclaration().getName()); Assert.assertTrue(b.getDeclaration() instanceof Class); }
private ProducedType getCommonSupertype( final List<ProducedType> caseTypes, TypeDeclaration dec, final TypeDeclaration selfTypeToIgnore) { // now try to construct a common produced // type that is a common supertype by taking // the type args and unioning them List<ProducedType> args = new ArrayList<ProducedType>(); for (TypeParameter tp : dec.getTypeParameters()) { List<ProducedType> list2 = new ArrayList<ProducedType>(); ProducedType result; if (tp.isContravariant()) { for (ProducedType pt : caseTypes) { ProducedType st = pt.getSupertype(dec, selfTypeToIgnore); if (st == null) { return null; } addToIntersection(list2, st.getTypeArguments().get(tp)); } IntersectionType it = new IntersectionType(getDeclaration().getUnit()); it.setSatisfiedTypes(list2); result = it.canonicalize().getType(); } else { for (ProducedType pt : caseTypes) { ProducedType st = pt.getSupertype(dec, selfTypeToIgnore); if (st == null) { return null; } addToUnion(list2, st.getTypeArguments().get(tp)); } UnionType ut = new UnionType(getDeclaration().getUnit()); ut.setCaseTypes(list2); result = ut.getType(); } args.add(result); } // check that the unioned type args // satisfy the type constraints for (int i = 0; i < args.size(); i++) { TypeParameter tp = dec.getTypeParameters().get(i); for (ProducedType ub : tp.getSatisfiedTypes()) { if (!args.get(i).isSubtypeOf(ub)) { return null; } } } // recurse to the qualifying type ProducedType outerType; if (dec.isMember()) { TypeDeclaration outer = (TypeDeclaration) dec.getContainer(); List<ProducedType> list = new ArrayList<ProducedType>(); for (ProducedType pt : caseTypes) { ProducedType st = pt.getQualifyingType().getSupertype(outer, null); list.add(st); } outerType = getCommonSupertype(list, outer, null); } else { outerType = null; } // make the resulting type ProducedType candidateResult = dec.getProducedType(outerType, args); // check the the resulting type is *really* // a subtype (take variance into account) for (ProducedType pt : caseTypes) { if (!pt.isSubtypeOf(candidateResult)) { return null; } } return candidateResult; }
/** Is this type exactly the same type as the given type? */ public boolean isExactly(ProducedType type) { if (getDeclaration() instanceof BottomType) { return type.getDeclaration() instanceof BottomType; } else if (getDeclaration() instanceof UnionType) { List<ProducedType> cases = getCaseTypes(); if (type.getDeclaration() instanceof UnionType) { List<ProducedType> otherCases = type.getCaseTypes(); if (cases.size() != otherCases.size()) { return false; } else { for (ProducedType c : cases) { boolean found = false; for (ProducedType oc : otherCases) { if (c.isExactly(oc)) { found = true; break; } } if (!found) { return false; } } return true; } } else if (cases.size() == 1) { ProducedType st = cases.get(0); return st.isExactly(type); } else { return false; } } else if (getDeclaration() instanceof IntersectionType) { List<ProducedType> types = getSatisfiedTypes(); if (type.getDeclaration() instanceof IntersectionType) { List<ProducedType> otherTypes = type.getSatisfiedTypes(); if (types.size() != otherTypes.size()) { return false; } else { for (ProducedType c : types) { boolean found = false; for (ProducedType oc : otherTypes) { if (c.isExactly(oc)) { found = true; break; } } if (!found) { return false; } } return true; } } else if (types.size() == 1) { ProducedType st = types.get(0); return st.isExactly(type); } else { return false; } } else if (type.getDeclaration() instanceof UnionType) { List<ProducedType> otherCases = type.getCaseTypes(); if (otherCases.size() == 1) { ProducedType st = otherCases.get(0); return this.isExactly(st); } else { return false; } } else if (type.getDeclaration() instanceof IntersectionType) { List<ProducedType> otherTypes = type.getSatisfiedTypes(); if (otherTypes.size() == 1) { ProducedType st = otherTypes.get(0); return this.isExactly(st); } else { return false; } } else { if (!type.getDeclaration().equals(getDeclaration())) { return false; } else { ProducedType qt = getQualifyingType(); ProducedType tqt = type.getQualifyingType(); if (qt == null) { if (tqt != null) { return false; } } else { if (tqt == null) { return false; } else { TypeDeclaration totd = (TypeDeclaration) type.getDeclaration().getContainer(); ProducedType tqts = tqt.getSupertype(totd); TypeDeclaration otd = (TypeDeclaration) getDeclaration().getContainer(); ProducedType qts = qt.getSupertype(otd); if (!qts.isExactly(tqts)) { return false; } } } for (TypeParameter p : getDeclaration().getTypeParameters()) { ProducedType arg = getTypeArguments().get(p); ProducedType otherArg = type.getTypeArguments().get(p); if (arg == null || otherArg == null) { return false; /*throw new RuntimeException( "Missing type argument for: " + p.getName() + " of " + getDeclaration().getName());*/ } else if (!arg.isExactly(otherArg)) { return false; } } return true; } } }
/** Is this type a subtype of the given type? Ignore a certain self type constraint. */ public boolean isSubtypeOf(ProducedType type, TypeDeclaration selfTypeToIgnore) { if (getDeclaration() instanceof BottomType) { return true; } else if (type.getDeclaration() instanceof BottomType) { return false; } else if (getDeclaration() instanceof UnionType) { for (ProducedType ct : getInternalCaseTypes()) { if (ct == null || !ct.isSubtypeOf(type, selfTypeToIgnore)) { return false; } } return true; } else if (type.getDeclaration() instanceof UnionType) { for (ProducedType ct : type.getInternalCaseTypes()) { if (ct != null && isSubtypeOf(ct, selfTypeToIgnore)) { return true; } } return false; } else if (type.getDeclaration() instanceof IntersectionType) { for (ProducedType ct : type.getInternalSatisfiedTypes()) { if (ct != null && !isSubtypeOf(ct, selfTypeToIgnore)) { return false; } } return true; } else if (getDeclaration() instanceof IntersectionType) { for (ProducedType ct : getInternalSatisfiedTypes()) { if (ct == null || ct.isSubtypeOf(type, selfTypeToIgnore)) { return true; } } return false; } else { ProducedType st = getSupertype(type.getDeclaration(), selfTypeToIgnore); if (st == null) { return false; } else { ProducedType stqt = st.getQualifyingType(); ProducedType tqt = type.getQualifyingType(); if (stqt == null) { if (tqt != null) { // probably extraneous! return false; } } else { if (tqt == null) { // probably extraneous! return false; } else { // note that the qualifying type of the // given type may be an invariant subtype // of the type that declares the member // type, as long as it doesn't refine the // member type TypeDeclaration totd = (TypeDeclaration) type.getDeclaration().getContainer(); ProducedType tqts = tqt.getSupertype(totd); if (!stqt.isSubtypeOf(tqts)) { return false; } } } for (TypeParameter p : type.getDeclaration().getTypeParameters()) { ProducedType arg = st.getTypeArguments().get(p); ProducedType otherArg = type.getTypeArguments().get(p); if (arg == null || otherArg == null) { /*throw new RuntimeException("Missing type argument for type parameter: " + p.getName() + " of " + type.getDeclaration().getName());*/ return false; } else if (p.isCovariant()) { if (!arg.isSubtypeOf(otherArg)) { return false; } } else if (p.isContravariant()) { if (!otherArg.isSubtypeOf(arg)) { return false; } } else { if (!arg.isExactly(otherArg)) { return false; } } } return true; } } }