private void printTypeParameters(List<TypeParameter> args, Object arg) { if (args != null) { for (Iterator<TypeParameter> i = args.iterator(); i.hasNext(); ) { TypeParameter t = i.next(); t.accept(this, arg); if (i.hasNext()) {} } } }
public void visit(TypeParameter n, Object arg) { if (n.getTypeBound() != null) { for (Iterator<ClassOrInterfaceType> i = n.getTypeBound().iterator(); i.hasNext(); ) { ClassOrInterfaceType c = i.next(); c.accept(this, arg); if (i.hasNext()) {} } } }
/** * Determine if this is a decidable supertype, i.e. if it obeys the restriction that types with * contravariant type parameters may only appear in covariant positions. * * @return a list of type parameters which appear in illegal positions */ public List<TypeDeclaration> checkDecidability() { List<TypeDeclaration> errors = new ArrayList<TypeDeclaration>(); for (TypeParameter tp : getDeclaration().getTypeParameters()) { ProducedType pt = getTypeArguments().get(tp); if (pt != null) { pt.checkDecidability(tp.isCovariant(), tp.isContravariant(), errors); } } return errors; }
private static List<TypeParameterRequirement> createTypeParameters( Iterable<TypeParameter> typeParameters, List<ImplementationDependency> dependencies) { Set<String> orderableRequired = new HashSet<>(); Set<String> comparableRequired = new HashSet<>(); for (ImplementationDependency dependency : dependencies) { if (dependency instanceof OperatorImplementationDependency) { OperatorType operator = ((OperatorImplementationDependency) dependency).getOperator(); if (operator == CAST) { continue; } Set<String> argumentTypes = ((OperatorImplementationDependency) dependency) .getSignature() .getArgumentTypes() .stream() .map(TypeSignature::getBase) .collect(toImmutableSet()); checkArgument( argumentTypes.size() == 1, "Operator dependency must only have arguments of a single type"); String argumentType = Iterables.getOnlyElement(argumentTypes); if (COMPARABLE_TYPE_OPERATORS.contains(operator)) { comparableRequired.add(argumentType); } if (ORDERABLE_TYPE_OPERATORS.contains(operator)) { orderableRequired.add(argumentType); } } } ImmutableList.Builder<TypeParameterRequirement> typeParameterRequirements = ImmutableList.builder(); for (TypeParameter typeParameter : typeParameters) { String name = typeParameter.value(); if (orderableRequired.contains(name)) { typeParameterRequirements.add(orderableTypeParameter(name)); } else if (comparableRequired.contains(name)) { typeParameterRequirements.add(comparableTypeParameter(name)); } else { typeParameterRequirements.add(typeParameter(name)); } } return typeParameterRequirements.build(); }
@Override public List<? extends Declaration> locallyDeclaredDeclarations() throws LookupException { if (_localDeclarationCache == null) { synchronized (this) { if (_localDeclarationCache == null) { List<Declaration> result = Lists.create(); BlockFixer stub = new BlockFixer(); stub.setUniParent(this); for (TypeParameter parameter : parameters()) { TypeParameter clone = clone(parameter); clone.setOrigin(parameter); result.add(clone); stub.add(clone); } _localDeclarationCache = ImmutableList.copyOf(result); } } } return _localDeclarationCache; }
private void checkDecidability( boolean covariant, boolean contravariant, List<TypeDeclaration> errors) { if (getDeclaration() instanceof TypeParameter) { // nothing to do } else if (getDeclaration() instanceof UnionType) { for (ProducedType ct : getCaseTypes()) { ct.checkDecidability(covariant, contravariant, errors); } } else if (getDeclaration() instanceof IntersectionType) { for (ProducedType ct : getSatisfiedTypes()) { ct.checkDecidability(covariant, contravariant, errors); } } else { for (TypeParameter tp : getDeclaration().getTypeParameters()) { if (!covariant && tp.isContravariant()) { // a type with contravariant parameters appears at // a contravariant location in satisfies / extends errors.add(getDeclaration()); } ProducedType pt = getTypeArguments().get(tp); if (pt != null) { if (tp.isCovariant()) { pt.checkDecidability(covariant, contravariant, errors); } else if (tp.isContravariant()) { if (covariant | contravariant) { pt.checkDecidability(!covariant, !contravariant, errors); } else { // else if we are in a nonvariant position, it stays nonvariant pt.checkDecidability(covariant, contravariant, errors); } } else { pt.checkDecidability(false, false, errors); } } } } }
private void checkVariance( boolean covariant, boolean contravariant, Declaration declaration, List<TypeParameter> errors) { // TODO: fix this to allow reporting multiple errors! if (getDeclaration() instanceof TypeParameter) { TypeParameter tp = (TypeParameter) getDeclaration(); boolean ok = tp.getDeclaration().equals(declaration) || ((covariant || !tp.isCovariant()) && (contravariant || !tp.isContravariant())); if (!ok) { // a covariant type parameter appears in a contravariant location, or // a contravariant type parameter appears in a covariant location. errors.add(tp); } } else if (getDeclaration() instanceof UnionType) { for (ProducedType ct : getCaseTypes()) { ct.checkVariance(covariant, contravariant, declaration, errors); } } else if (getDeclaration() instanceof IntersectionType) { for (ProducedType ct : getSatisfiedTypes()) { ct.checkVariance(covariant, contravariant, declaration, errors); } } else { for (TypeParameter tp : getDeclaration().getTypeParameters()) { ProducedType pt = getTypeArguments().get(tp); if (pt != null) { if (tp.isCovariant()) { pt.checkVariance(covariant, contravariant, declaration, errors); } else if (tp.isContravariant()) { if (covariant | contravariant) { pt.checkVariance(!covariant, !contravariant, declaration, errors); } else { // else if we are in a nonvariant position, it stays nonvariant pt.checkVariance(covariant, contravariant, declaration, errors); } } else { pt.checkVariance(false, false, declaration, errors); } } } } }
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 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; } } }
@Override public Void visitTypeParameter(TypeParameter node) { visit(node.getName()); visit(" extends ", node.getBound()); return null; }