protected UnboundTypeReference createCopy(ITypeReferenceOwner owner) { UnboundTypeReference result = new UnboundTypeReference(owner, expression, getTypeParameter(), getHandle()); return result; }
@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; }
protected int doIsConformant(LightweightTypeReference left, UnboundTypeReference right, int flags) { if (left.getType() == right.getType() || left.isType(Object.class)) { return flags | SUCCESS; } if ((flags & ALLOW_UNBOXING) == 0 && left.isPrimitive()) { return flags; } boolean doesNotHaveSignificantHints = false; if (((flags & RAW_TYPE) == 0) && (right.canResolveTo(left) || (flags & AS_TYPE_ARGUMENT) != 0 && (doesNotHaveSignificantHints = !right.hasSignificantHints()))) { if ((flags & UNBOUND_COMPUTATION_ADDS_HINTS) != 0 && doesNotHaveSignificantHints) { right.acceptHint(left, BoundTypeArgumentSource.INFERRED_LATER, left, VarianceInfo.INVARIANT, VarianceInfo.INVARIANT); } return flags | SUCCESS; } right.tryResolve(false); LightweightTypeReference resolvedTo = right.getResolvedTo(); if (resolvedTo != null) { return doIsConformant(left, resolvedTo, flags); } return flags; }
public boolean hasSignificantHints() { if (internalIsResolved()) return true; List<LightweightBoundTypeArgument> hints = getAllHints(); if (!hints.isEmpty() && hasSignificantHints(hints)) return true; return false; }
/** * 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 void mergeTypeParametersIntoParent(ResolvedTypes parent) { for(UnboundTypeReference unbound: basicGetTypeParameters().values()) { LightweightTypeReference resolvedTo = unbound.getResolvedTo(); if (resolvedTo == null) { List<JvmTypeParameter> typeParameters = basicGetDeclardTypeParameters(); if (typeParameters != null && typeParameters.contains(unbound.getTypeParameter())) { unbound.tryResolve(); if (!unbound.internalIsResolved()) { if (unbound.getExpression() instanceof XConstructorCall) { unbound.resolve(); // resolve against constraints } else { unbound.acceptHint(unbound.getOwner().newParameterizedTypeReference(unbound.getTypeParameter()), BoundTypeArgumentSource.RESOLVED, unbound, VarianceInfo.INVARIANT, VarianceInfo.INVARIANT); LightweightTypeReference reference = unbound.copyInto(parent.getReferenceOwner()); if (reference instanceof UnboundTypeReference) { parent.acceptUnboundTypeReference(unbound.getHandle(), (UnboundTypeReference) reference);
boolean othersSeen = false; 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); if (getOwner().getDeclaredTypeParameters().contains(reference.getTypeParameter())) { reference.acceptHint(declaration, BoundTypeArgumentSource.RESOLVED, this, VarianceInfo.INVARIANT, VarianceInfo.INVARIANT); return; reference.acceptHint(declaration, BoundTypeArgumentSource.RESOLVED, this, VarianceInfo.INVARIANT, VarianceInfo.INVARIANT); } else if (!constraintSeen && !reference.internalIsResolved() && declaration.isResolved() && !getOwner().isResolved(reference.getHandle()) && reference.canResolveTo(declaration)) { reference.acceptHint(declaration, BoundTypeArgumentSource.RESOLVED, this, VarianceInfo.INVARIANT, VarianceInfo.INVARIANT); } else if (othersSeen && declarationMatches) { reference.acceptHint(declaration, BoundTypeArgumentSource.INFERRED, this, VarianceInfo.INVARIANT, VarianceInfo.INVARIANT); } else { reference.tryResolve(); if (reference.internalIsResolved()) { outerVisit(reference, declaration); } else {
/** * 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; }
@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); }
@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); } }
LightweightTypeReference actualType = getActualType(identifiable); if (actualType != null) { if (actualType.getKind() == LightweightTypeReference.KIND_UNBOUND_TYPE_REFERENCE && !((UnboundTypeReference) actualType).internalIsResolved()) { UnboundTypeReference casted = (UnboundTypeReference) actualType; List<LightweightBoundTypeArgument> hints = getHints(casted.getHandle()); boolean canAddHint = true; for(int i = 0; i < hints.size() && canAddHint; i++) { casted.acceptHint(reference, BoundTypeArgumentSource.EXPECTATION, identifiable, VarianceInfo.OUT, VarianceInfo.OUT);
/** * 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; }
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); }
@Override protected void acceptHint(UnboundTypeReference reference, LightweightTypeReference param) { if (!shouldProcess(reference.getTypeParameter())) { reference.tryResolve(); if (reference.internalIsResolved()) { outerVisit(reference, param); } else { super.acceptHint(reference, param); } } else { reference.acceptHint(boundByInference(param)); } }
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); }
LightweightTypeReference returnType = expectedClosureType.getReturnType(); if (returnType.getKind() == LightweightTypeReference.KIND_UNBOUND_TYPE_REFERENCE) { skippedHandle = ((UnboundTypeReference) returnType).getHandle(); if (operationParameterType.getKind() == LightweightTypeReference.KIND_UNBOUND_TYPE_REFERENCE) { UnboundTypeReference casted = (UnboundTypeReference)operationParameterType; boolean isSkippedHandle = casted.getHandle().equals(skippedHandle); if (!isSkippedHandle && !casted.internalIsResolved() && casted.hasSignificantHints()) { casted.acceptHint(VarianceInfo.IN); ((UnboundTypeReference) returnType).acceptHint(VarianceInfo.OUT);
@Override public void doVisitUnboundTypeReference(UnboundTypeReference reference, WildcardTypeReference declaration) { if (declaration.getLowerBound() == null) { if (!reference.internalIsResolved()) { List<LightweightTypeReference> upperBounds = declaration.getUpperBounds(); for(LightweightTypeReference upperBound: upperBounds) { if (!upperBound.isResolved() || !reference.canResolveTo(upperBound)) { super.doVisitUnboundTypeReference(reference, declaration); return; } } reference.tryResolve(); if (reference.internalIsResolved()) { outerVisit(reference, declaration); } else { addHint(reference, declaration); } return; } } super.doVisitUnboundTypeReference(reference, declaration); } }
@Override protected void doVisitWildcardTypeReference(WildcardTypeReference reference, UnboundTypeReference declaration) { if (shouldProcess(declaration.getTypeParameter())) { declaration.acceptHint(boundByInference(reference)); } else { super.doVisitWildcardTypeReference(reference, declaration); } } };
protected int addHintAndAnnounceSuccess(UnboundTypeReference left, LightweightTypeReference hint, int flags) { if (hint instanceof WildcardTypeReference) { List<LightweightTypeReference> bounds = ((WildcardTypeReference) hint).getUpperBounds(); for(LightweightTypeReference upperBound: bounds) left.acceptHint(upperBound, BoundTypeArgumentSource.INFERRED, this, VarianceInfo.OUT, VarianceInfo.OUT); } else { left.acceptHint(hint, BoundTypeArgumentSource.INFERRED, this, VarianceInfo.OUT, VarianceInfo.OUT); } return flags | SUCCESS; }
throw new IllegalArgumentException("Hint may not be primitive void, <any> or <unknown>"); if (hint instanceof UnboundTypeReference) { if (((UnboundTypeReference) hint).getHandle() == getHandle()) { return; // invalid input, e.g. List<T extends T> acceptHint(new LightweightBoundTypeArgument(hint.getWrapperTypeIfPrimitive(), source, origin, expectedVariance, actualVariance));