public boolean hasSignificantHints() { if (internalIsResolved()) return true; List<LightweightBoundTypeArgument> hints = getAllHints(); if (!hints.isEmpty() && hasSignificantHints(hints)) return true; return false; }
protected int doIsConformant(UnboundTypeReference left, UnboundTypeReference right, int flags) { if (left.getHandle().equals(right.getHandle())) { return flags | SUCCESS; } List<LightweightBoundTypeArgument> leftHints = left.getAllHints(); List<LightweightBoundTypeArgument> rightHints = right.getAllHints(); if ((flags & UNBOUND_COMPUTATION_ADDS_HINTS) != 0) { if (leftHints.isEmpty() || rightHints.isEmpty() || !left.hasSignificantHints(leftHints) || !right.hasSignificantHints()) { left.acceptHint(right, BoundTypeArgumentSource.INFERRED, this, VarianceInfo.OUT, VarianceInfo.OUT); return flags | SUCCESS; } } if (leftHints.equals(rightHints)) { return flags | SUCCESS; } return tryResolveAndCheckConformance(left, right, flags); }
/** * Try to resolve this reference iff there are hints available. * May be invoked multiple times since it will simply returns if * the reference is already resolved. The caller can decide whether * type constraints are considered to be significant hints or not. */ public void tryResolve(boolean constraintsAreSignificant) { if (internalIsResolved()) return; List<LightweightBoundTypeArgument> hints = getAllHints(); if (!hints.isEmpty() && hasSignificantHints(hints, constraintsAreSignificant)) { resolveWithHints(hints); } }
protected boolean isUnknownReceiverType(LightweightTypeReference receiverType) { if (receiverType.isUnknown()) { return true; } if (receiverType instanceof UnboundTypeReference) { List<LightweightBoundTypeArgument> hints = ((UnboundTypeReference) receiverType).getAllHints(); for(LightweightBoundTypeArgument hint: hints) { LightweightTypeReference typeReference = hint.getTypeReference(); if (typeReference != null && typeReference.isUnknown()) return true; } } return false; }
/** * Returns true if the existing hints would allow to resolve to the given reference. */ public boolean canResolveTo(LightweightTypeReference reference) { if (internalIsResolved()) return reference.isAssignableFrom(resolvedTo, new TypeConformanceComputationArgument(false, true, true, true, false, false /* TODO do we need to support synonmys here? */)); List<LightweightBoundTypeArgument> hints = getAllHints(); if (!hints.isEmpty() && hasSignificantHints(hints)) { return canResolveTo(reference, hints); } return false; }
/** * Force this reference to be resolved. If not hints are available, * the reference is resolved to the constraints of the type parameters. * @return the resolved representation. Never <code>null</code>. */ public LightweightTypeReference resolve() { if (internalIsResolved()) return resolvedTo; List<LightweightBoundTypeArgument> allHints = getAllHints(); if (!allHints.isEmpty() && resolveWithHints(allHints)) { LightweightTypeReference result = internalGetResolvedTo(); if (result != null) { return result; } } resolveAgainstConstraints(); return resolvedTo; }
public void acceptHint(LightweightBoundTypeArgument hint) { if (internalIsResolved()) { throw new IllegalStateException("Cannot add hints to a resolved reference"); } if (hint.getSource() == BoundTypeArgumentSource.EXPLICIT) { LightweightTypeReference reference = hint.getTypeReference(); if (!(reference instanceof ParameterizedTypeReference) && !reference.isArray() && !reference.isUnknown()) { throw new IllegalArgumentException("cannot set " + hint + " as explicit hint"); } if (!getAllHints().isEmpty()) { throw new IllegalStateException("Cannot set explicit hint if other hints are present: " + getAllHints()); } this.resolvedTo = reference; getOwner().acceptHint(getHandle(), new LightweightBoundTypeArgument(resolvedTo, BoundTypeArgumentSource.RESOLVED, this, hint.getDeclaredVariance(), hint.getActualVariance())); return; } getOwner().acceptHint(this.getHandle(), hint); }
@Override protected List<JvmType> doVisitUnboundTypeReference(UnboundTypeReference reference, ResourceSet resourceSet) { List<LightweightBoundTypeArgument> hints = reference.getAllHints(); if (!hints.isEmpty()) { if (reference.resolveWithHints(hints)) { LightweightTypeReference resolvedTo = reference.getResolvedTo(); if (resolvedTo != null) return resolvedTo.accept(this, resourceSet); } } JvmTypeParameter typeParameter = reference.getTypeParameter(); return getRawTypesFromConstraints(reference.getOwner(), typeParameter, resourceSet); }
private JvmOperation findImplementingOperation(UnboundTypeReference unboundTypeReference) { List<LightweightBoundTypeArgument> hints = unboundTypeReference.getAllHints(); for(LightweightBoundTypeArgument hint: hints) { LightweightTypeReference hintReference = hint.getTypeReference(); if (hintReference != null && (hint.getSource() == BoundTypeArgumentSource.INFERRED || hint.getSource() == BoundTypeArgumentSource.INFERRED_EXPECTATION)) { List<JvmType> rawTypes = hintReference.getRawTypes(); JvmOperation result = findImplementingOperation(rawTypes); if (result != null) { return result; } } } return null; }
@Override protected LightweightTypeReference doVisitUnboundTypeReference(UnboundTypeReference reference, Object param) { if (reference.internalIsResolved()) { return super.doVisitUnboundTypeReference(reference, param); } else { List<LightweightBoundTypeArgument> hints = reference.getAllHints(); for (LightweightBoundTypeArgument hint : hints) { BoundTypeArgumentSource source = hint.getSource(); if (source == BoundTypeArgumentSource.INFERRED || source == BoundTypeArgumentSource.EXPECTATION || source == BoundTypeArgumentSource.INFERRED_CONSTRAINT) { reference.tryResolve(); if (reference.internalIsResolved()) { return reference.accept(this, param); } } } } return reference; }
@Override public LightweightTypeReference doVisitUnboundTypeReference(UnboundTypeReference reference, Set<JvmTypeParameter> visiting) { if (reference.getHandle() == left.getHandle()) { if (right.getKind() == KIND_UNBOUND_TYPE_REFERENCE) { UnboundTypeReference rightUnbound = (UnboundTypeReference) right; List<LightweightBoundTypeArgument> rightHints = rightUnbound.getAllHints(); for(LightweightBoundTypeArgument rightHint: rightHints) { LightweightTypeReference rightHintReference = rightHint.getTypeReference(); if (rightHintReference != null && leftHintReference.getUniqueIdentifier().equals(rightHintReference.getUniqueIdentifier())) { return super.doVisitUnboundTypeReference(reference, visiting); } } } return rightTypeArgument.getTypeReference(); } return super.doVisitUnboundTypeReference(reference, visiting); } };
protected int tryResolveAndCheckConformance( UnboundTypeReference left, final List<LightweightBoundTypeArgument> leftHints, LightweightTypeReference right, int flags) { class Helper { final List<LightweightBoundTypeArgument> hintsToProcess; final List<LightweightBoundTypeArgument> inferredHintsToProcess; int laterCount = 0; boolean inferredAsWildcard = false; Helper(List<LightweightBoundTypeArgument> hints) { hintsToProcess = Lists.newArrayListWithCapacity(hints.size()); inferredHintsToProcess = Lists.newArrayListWithCapacity(hints.size()); for(LightweightBoundTypeArgument hint: hints) { if (hint.getDeclaredVariance() != null) { hintsToProcess.add(hint); if (hint.getSource() == BoundTypeArgumentSource.INFERRED) { if (hint.getTypeReference() instanceof WildcardTypeReference) { inferredAsWildcard = true; } inferredHintsToProcess.add(hint); } else if (hint.getSource() == BoundTypeArgumentSource.INFERRED_LATER) { laterCount++; } } } } private List<LightweightBoundTypeArgument> getHintsToMerge() { return inferredHintsToProcess.isEmpty() || (laterCount > 1 && inferredAsWildcard) ? hintsToProcess : inferredHintsToProcess;
@Override protected void doVisitUnboundTypeReference(UnboundTypeReference reference, UnboundTypeReference declaration) { if (declaration.internalIsResolved() || getOwner().isResolved(declaration.getHandle())) { declaration.tryResolve(); outerVisit(declaration, reference, declaration, getExpectedVariance(), getActualVariance()); } else { if (getParametersToProcess().contains(declaration.getTypeParameter()) && VarianceInfo.OUT == getActualVariance() && VarianceInfo.OUT == getExpectedVariance()) { if (getDefaultSource() == BoundTypeArgumentSource.EXPECTATION) { List<LightweightBoundTypeArgument> hints = reference.getAllHints(); for(int i = 0; i < hints.size(); i++) { if (hints.get(i).getSource() == BoundTypeArgumentSource.INFERRED) { return; } } } } acceptHint(declaration, reference); } }
protected boolean isExpectedType(LightweightTypeReference expectation, Class<?> clazz) { if (expectation != null) { if (expectation.isResolved() && isSubtypeButNotSynonym(expectation, clazz)) { return true; } if (expectation instanceof UnboundTypeReference) { if (expectation.getOwner().newParameterizedTypeReference(((UnboundTypeReference) expectation).getTypeParameter()).isSubtypeOf(clazz)) { return true; } List<LightweightBoundTypeArgument> hints = ((UnboundTypeReference) expectation).getAllHints(); for(LightweightBoundTypeArgument hint: hints) { LightweightTypeReference hintReference = hint.getTypeReference(); if (hintReference != null && isSubtypeButNotSynonym(hintReference, clazz)) { return true; } } } else if (expectation instanceof ParameterizedTypeReference) { return isSubtypeButNotSynonym(expectation, clazz); } } return false; }
@Override protected void addHint(UnboundTypeReference typeParameter, LightweightTypeReference reference) { if (!typeParameter.internalIsResolved() && getExpectedVariance() == VarianceInfo.INVARIANT) { if (getExpectedVariance() == getActualVariance() && reference.getKind() != LightweightTypeReference.KIND_UNBOUND_TYPE_REFERENCE) { doAddHint(typeParameter, reference, BoundTypeArgumentSource.INFERRED_EXPECTATION); } else if (getActualVariance() == VarianceInfo.IN && !typeParameter.hasSignificantHints()) { if (reference.getKind() != LightweightTypeReference.KIND_UNBOUND_TYPE_REFERENCE) { doAddHint(typeParameter, reference, BoundTypeArgumentSource.INFERRED_EXPECTATION); } else { UnboundTypeReference casted = (UnboundTypeReference)reference; List<LightweightBoundTypeArgument> hints = casted.getAllHints(); for(LightweightBoundTypeArgument hint: hints) { // avoid bogus transitive hints, e.g. if a reference was used with another variance // INFERRED_LATER serves as an indicator for these hints if (hint.getSource() == BoundTypeArgumentSource.INFERRED_LATER) { return; } } doAddHint(typeParameter, reference, BoundTypeArgumentSource.INFERRED_EXPECTATION); } } } }
boolean othersSeen = false; boolean declarationMatches = getExpectedVariance() != VarianceInfo.OUT; List<LightweightBoundTypeArgument> hints = reference.getAllHints(); for(int i = 0; i < hints.size(); i++) { LightweightBoundTypeArgument hint = hints.get(i);
boolean declarationMatches = getExpectedVariance() != VarianceInfo.OUT; if (reference.getTypeParameter() != declaration.getType()) { List<LightweightBoundTypeArgument> hints = reference.getAllHints(); for(int i = 0; i < hints.size(); i++) { LightweightBoundTypeArgument hint = hints.get(i);