boolean addConstraintsFromTypeParameters( TypeBinding subCandidate, ParameterizedTypeBinding ca, List<ConstraintFormula> constraints) { TypeBinding[] ai = ca.arguments; // C<A1,A2,...> if (ai == null) return true; // no arguments here means nothing to check TypeBinding cb = subCandidate.findSuperTypeOriginatingFrom(ca); // C<B1,B2,...> if (cb == null) return false; // nothing here means we failed if (TypeBinding.equalsEquals(ca, cb)) // incl C#RAW vs C#RAW return true; if (!(cb instanceof ParameterizedTypeBinding)) { // if C is parameterized with its own type variables, there're no more constraints to be // created here, otherwise let's fail return ca.isParameterizedWithOwnVariables(); } TypeBinding[] bi = ((ParameterizedTypeBinding) cb).arguments; if (cb.isRawType() || bi == null || bi.length == 0) return (this.isSoft && InferenceContext18.SIMULATE_BUG_JDK_8026527) ? true : false; // FALSE would conform to the spec for (int i = 0; i < ai.length; i++) constraints.add( ConstraintTypeFormula.create(bi[i], ai[i], TYPE_ARGUMENT_CONTAINED, this.isSoft)); return true; }
private TypeConstants.BoundCheckStatus internalBoundCheck( Substitution substitution, TypeBinding argumentType, Scope scope, ASTNode location) { if (argumentType == TypeBinding.NULL || TypeBinding.equalsEquals(argumentType, this)) { return BoundCheckStatus.OK; } boolean hasSubstitution = substitution != null; if (!(argumentType instanceof ReferenceBinding || argumentType.isArrayType())) return BoundCheckStatus.MISMATCH; // special case for re-entrant source types (selection, code assist, etc)... // can request additional types during hierarchy walk that are found as source types that also // 'need' to connect their hierarchy if (this.superclass == null) return BoundCheckStatus.OK; if (argumentType.kind() == Binding.WILDCARD_TYPE) { WildcardBinding wildcard = (WildcardBinding) argumentType; switch (wildcard.boundKind) { case Wildcard.EXTENDS: TypeBinding wildcardBound = wildcard.bound; if (TypeBinding.equalsEquals(wildcardBound, this)) return BoundCheckStatus.OK; boolean isArrayBound = wildcardBound.isArrayType(); if (!wildcardBound.isInterface()) { TypeBinding substitutedSuperType = hasSubstitution ? Scope.substitute(substitution, this.superclass) : this.superclass; if (substitutedSuperType.id != TypeIds.T_JavaLangObject) { if (isArrayBound) { if (!wildcardBound.isCompatibleWith(substitutedSuperType, scope)) return BoundCheckStatus.MISMATCH; } else { TypeBinding match = wildcardBound.findSuperTypeOriginatingFrom(substitutedSuperType); if (match != null) { if (substitutedSuperType.isProvablyDistinct(match)) { return BoundCheckStatus.MISMATCH; } } else { match = substitutedSuperType.findSuperTypeOriginatingFrom(wildcardBound); if (match != null) { if (match.isProvablyDistinct(wildcardBound)) { return BoundCheckStatus.MISMATCH; } } else { if (denotesRelevantSuperClass(wildcardBound) && denotesRelevantSuperClass(substitutedSuperType)) { // non-object real superclass should have produced a valid 'match' above return BoundCheckStatus.MISMATCH; } } } } } } boolean mustImplement = isArrayBound || ((ReferenceBinding) wildcardBound).isFinal(); for (int i = 0, length = this.superInterfaces.length; i < length; i++) { TypeBinding substitutedSuperType = hasSubstitution ? Scope.substitute(substitution, this.superInterfaces[i]) : this.superInterfaces[i]; if (isArrayBound) { if (!wildcardBound.isCompatibleWith(substitutedSuperType, scope)) return BoundCheckStatus.MISMATCH; } else { TypeBinding match = wildcardBound.findSuperTypeOriginatingFrom(substitutedSuperType); if (match != null) { if (substitutedSuperType.isProvablyDistinct(match)) { return BoundCheckStatus.MISMATCH; } } else if (mustImplement) { return BoundCheckStatus .MISMATCH; // cannot be extended further to satisfy missing bounds } } } break; case Wildcard.SUPER: // if the wildcard is lower-bounded by a type variable that has no relevant upper bound // there's nothing to check here (bug 282152): if (wildcard.bound.isTypeVariable() && ((TypeVariableBinding) wildcard.bound).superclass.id == TypeIds.T_JavaLangObject) break; return boundCheck(substitution, wildcard.bound, scope, location); case Wildcard.UNBOUND: break; } return BoundCheckStatus.OK; } boolean unchecked = false; boolean checkNullAnnotations = scope.environment().usesNullTypeAnnotations(); boolean haveReportedNullProblem = false; if (this.superclass.id != TypeIds.T_JavaLangObject) { TypeBinding substitutedSuperType = hasSubstitution ? Scope.substitute(substitution, this.superclass) : this.superclass; if (TypeBinding.notEquals(substitutedSuperType, argumentType)) { if (!argumentType.isCompatibleWith(substitutedSuperType, scope)) { return BoundCheckStatus.MISMATCH; } TypeBinding match = argumentType.findSuperTypeOriginatingFrom(substitutedSuperType); if (match != null) { // Enum#RAW is not a substitute for <E extends Enum<E>> (86838) if (match.isRawType() && substitutedSuperType.isBoundParameterizedType()) unchecked = true; } } if (location != null && checkNullAnnotations) { if (NullAnnotationMatching.analyse( this, argumentType, substitutedSuperType, substitution, -1, CheckMode.BOUND_CHECK) .isAnyMismatch()) { scope.problemReporter().nullityMismatchTypeArgument(this, argumentType, location); haveReportedNullProblem = true; } } } for (int i = 0, length = this.superInterfaces.length; i < length; i++) { TypeBinding substitutedSuperType = hasSubstitution ? Scope.substitute(substitution, this.superInterfaces[i]) : this.superInterfaces[i]; if (TypeBinding.notEquals(substitutedSuperType, argumentType)) { if (!argumentType.isCompatibleWith(substitutedSuperType, scope)) { return BoundCheckStatus.MISMATCH; } TypeBinding match = argumentType.findSuperTypeOriginatingFrom(substitutedSuperType); if (match != null) { // Enum#RAW is not a substitute for <E extends Enum<E>> (86838) if (match.isRawType() && substitutedSuperType.isBoundParameterizedType()) unchecked = true; } } if (location != null && checkNullAnnotations) { if (NullAnnotationMatching.analyse( this, argumentType, substitutedSuperType, substitution, -1, CheckMode.BOUND_CHECK) .isAnyMismatch()) { scope.problemReporter().nullityMismatchTypeArgument(this, argumentType, location); haveReportedNullProblem = true; } } } if (location != null && checkNullAnnotations && !haveReportedNullProblem) { long nullBits = this.tagBits & TagBits.AnnotationNullMASK; if (nullBits != 0 && nullBits != (argumentType.tagBits & TagBits.AnnotationNullMASK)) { scope.problemReporter().nullityMismatchTypeArgument(this, argumentType, location); haveReportedNullProblem = true; } } return unchecked ? BoundCheckStatus.UNCHECKED : haveReportedNullProblem ? BoundCheckStatus.NULL_PROBLEM : BoundCheckStatus.OK; }