gt: 				this.tagBits |=  TagBits.HasMissingType;
context: /*******************************************************************************
   * Copyright (c) 2000, 2017 IBM Corporation and others.
   *
   * This program and the accompanying materials
   * are made available under the terms of the Eclipse Public License 2.0
   * which accompanies this distribution, and is available at
   * https://www.eclipse.org/legal/epl-2.0/
   *
   * SPDX-License-Identifier: EPL-2.0
   * 
   * Contributors:
   *     IBM Corporation - initial API and implementation
   *     Stephan Herrmann - Contributions for
   *								bug 186342 - [compiler][null] Using annotations for null checking
   *								bug 392099 - [1.8][compiler][null] Apply null annotation on types for null analysis
   *								bug 392384 - [1.8][compiler][null] Restore nullness info from type annotations in class files
   *								Bug 415043 - [1.8][null] Follow-up re null type annotations after bug 392099
   *								Bug 417295 - [1.8[[null] Massage type annotated null analysis to gel well with deep encoded type bindings.
   *								Bug 425152 - [1.8] [compiler] Lambda Expression not resolved but flow analyzed leading to NPE.
   *								Bug 429958 - [1.8][null] evaluate new DefaultLocation attribute of @NonNullByDefault
   *******************************************************************************/
  package org.eclipse.jdt.internal.compiler.lookup;
  
  import org.eclipse.jdt.internal.compiler.ast.NullAnnotationMatching;
  import org.eclipse.jdt.internal.compiler.ast.Wildcard;
  
  /**
   * Binding denoting a method after type parameter substitutions got performed.
   * On parameterized type bindings, all methods got substituted, regardless whether
   * their signature did involve generics or not, so as to get the proper declaringClass for
   * these methods.
   */
  public class ParameterizedMethodBinding extends MethodBinding {
  
  	protected MethodBinding originalMethod;
  
  	/**
  	 * Create method of parameterized type, substituting original parameters/exception/return type with type arguments.
  	 */
  	public ParameterizedMethodBinding(final ParameterizedTypeBinding parameterizedDeclaringClass, MethodBinding originalMethod) {
  		super(
  				originalMethod.modifiers,
  				originalMethod.selector,
  				originalMethod.returnType,
  				originalMethod.parameters,
  				originalMethod.thrownExceptions,
  				parameterizedDeclaringClass);
  		this.originalMethod = originalMethod;
  		/* missing type bit cannot be copied as is it might come from the return type or a parameter type that
  		 * is substituted by a raw type.
  		 */
  		this.tagBits = originalMethod.tagBits & ~TagBits.HasMissingType;
  		this.parameterNonNullness = originalMethod.parameterNonNullness;
  		this.defaultNullness = originalMethod.defaultNullness;
  
  		final TypeVariableBinding[] originalVariables = originalMethod.typeVariables;
  		Substitution substitution = null;
  		final int length = originalVariables.length;
  		final boolean isStatic = originalMethod.isStatic();
  		if (length == 0) {
  			this.typeVariables = Binding.NO_TYPE_VARIABLES;
  			if (!isStatic) substitution = parameterizedDeclaringClass;
  		} else {
  			// at least fix up the declaringElement binding + bound substitution if non static
  			final TypeVariableBinding[] substitutedVariables = new TypeVariableBinding[length];
  			for (int i = 0; i < length; i++) { // copy original type variable to relocate
  				TypeVariableBinding originalVariable = originalVariables[i];
  				substitutedVariables[i] = new TypeVariableBinding(originalVariable.sourceName, this, originalVariable.rank, parameterizedDeclaringClass.environment);
  				substitutedVariables[i].tagBits |= (originalVariable.tagBits & (TagBits.AnnotationNullMASK|TagBits.HasNullTypeAnnotation));
  			}
  			this.typeVariables = substitutedVariables;
  
  			// need to substitute old var refs with new ones (double substitution: declaringClass + new type variables)
  			substitution = new Substitution() {
  				@Override
  				public LookupEnvironment environment() {
  					return parameterizedDeclaringClass.environment;
  				}
  				@Override
  				public boolean isRawSubstitution() {
  					return !isStatic && parameterizedDeclaringClass.isRawSubstitution();
  				}
  				@Override
  				public TypeBinding substitute(TypeVariableBinding typeVariable) {
  					// check this variable can be substituted given copied variables
  					if (typeVariable.rank < length && TypeBinding.equalsEquals(originalVariables[typeVariable.rank], typeVariable)) {
  						TypeBinding substitute = substitutedVariables[typeVariable.rank];
  						return typeVariable.hasTypeAnnotations() ? environment().createAnnotatedType(substitute, typeVariable.getTypeAnnotations()) : substitute;
  					}
  					if (!isStatic)
  						return parameterizedDeclaringClass.substitute(typeVariable);
  					return typeVariable;
  				}
  			};
  
  			// initialize new variable bounds
  			for (int i = 0; i < length; i++) {
  				TypeVariableBinding originalVariable = originalVariables[i];
  				TypeVariableBinding substitutedVariable = substitutedVariables[i];
  				TypeBinding substitutedSuperclass = Scope.substitute(substitution, originalVariable.superclass);
  				ReferenceBinding[] substitutedInterfaces = Scope.substitute(substitution, originalVariable.superInterfaces);
  				if (originalVariable.firstBound != null) {
  					TypeBinding firstBound;
  					firstBound = TypeBinding.equalsEquals(originalVariable.firstBound, originalVariable.superclass)
  						? substitutedSuperclass // could be array type or interface
  						: substitutedInterfaces[0];
  					substitutedVariable.setFirstBound(firstBound);
  				}
  				switch (substitutedSuperclass.kind()) {
  					case Binding.ARRAY_TYPE :
  						substitutedVariable.setSuperClass(parameterizedDeclaringClass.environment.getResolvedJavaBaseType(TypeConstants.JAVA_LANG_OBJECT, null));
  						substitutedVariable.setSuperInterfaces(substitutedInterfaces);
  						break;
  					default:
  						if (substitutedSuperclass.isInterface()) {
  							substitutedVariable.setSuperClass(parameterizedDeclaringClass.environment.getResolvedType(TypeConstants.JAVA_LANG_OBJECT, null));
  							int interfaceCount = substitutedInterfaces.length;
  							System.arraycopy(substitutedInterfaces, 0, substitutedInterfaces = new ReferenceBinding[interfaceCount+1], 1, interfaceCount);
  							substitutedInterfaces[0] = (ReferenceBinding) substitutedSuperclass;
  							substitutedVariable.setSuperInterfaces(substitutedInterfaces);
  						} else {
  							substitutedVariable.setSuperClass((ReferenceBinding) substitutedSuperclass); // typeVar was extending other typeVar which got substituted with interface
  							substitutedVariable.setSuperInterfaces(substitutedInterfaces);
  						}
  				}
  			}
  		}
  		if (substitution != null) {
  			this.returnType = Scope.substitute(substitution, this.returnType);
  			this.parameters = Scope.substitute(substitution, this.parameters);
  			this.thrownExceptions = Scope.substitute(substitution, this.thrownExceptions);
  			// error case where exception type variable would have been substituted by a non-reference type (207573)
  			if (this.thrownExceptions == null) this.thrownExceptions = Binding.NO_EXCEPTIONS;
  
  			// after substitution transfer nullness information from type annotations:
  			if (parameterizedDeclaringClass.environment.globalOptions.isAnnotationBasedNullAnalysisEnabled) {
  				long returnNullBits = NullAnnotationMatching.validNullTagBits(this.returnType.tagBits);
  				if (returnNullBits != 0L) {
  					this.tagBits &= ~TagBits.AnnotationNullMASK;
  					this.tagBits |= returnNullBits;
  				}
  				int parametersLen = this.parameters.length;
  				for (int i=0; i<parametersLen; i++) {
  					long paramTagBits = NullAnnotationMatching.validNullTagBits(this.parameters[i].tagBits);
  					if (paramTagBits != 0) {
  						if (this.parameterNonNullness == null)
  							this.parameterNonNullness = new Boolean[parametersLen];
  						this.parameterNonNullness[i] = Boolean.valueOf(paramTagBits == TagBits.AnnotationNonNull);
  					}
  				}
  			}
  		}
  		checkMissingType: {
  			if ((this.tagBits & TagBits.HasMissingType) != 0)
  				break checkMissingType;
  			if ((this.returnType.tagBits & TagBits.HasMissingType) != 0) {
  				this.tagBits |=  TagBits.HasMissingType;
  				break checkMissingType;
  			}
  			for (int i = 0, max = this.parameters.length; i < max; i++) {
  				if ((this.parameters[i].tagBits & TagBits.HasMissingType) != 0) {
  					this.tagBits |=  TagBits.HasMissingType;
  					break checkMissingType;
  				}
  			}
  			for (int i = 0, max = this.thrownExceptions.length; i < max; i++) {
  				if ((this.thrownExceptions[i].tagBits & TagBits.HasMissingType) != 0) {
  					this.tagBits |=  TagBits.HasMissingType;
  					break checkMissingType;
  				}
  			}
  		}
  	}
  
  	/**
  	 * Create method of parameterized type, substituting original parameters/exception/return type with type arguments.
  	 * This is a CODE ASSIST method ONLY.
  	 */
  	public ParameterizedMethodBinding(final ReferenceBinding declaringClass, MethodBinding originalMethod, char[][] alternateParamaterNames, final LookupEnvironment environment) {
  		super(
  				originalMethod.modifiers,
  				originalMethod.selector,
  				 originalMethod.returnType,
  				originalMethod.parameters,
  				originalMethod.thrownExceptions,
  				declaringClass);
  		this.originalMethod = originalMethod;
  		/* missing type bit cannot be copied as is it might come from the return type or a parameter type that
  		 * is substituted by a raw type.
  		 */
  		this.tagBits = originalMethod.tagBits & ~TagBits.HasMissingType;
  		this.parameterNonNullness = originalMethod.parameterNonNullness;
  		this.defaultNullness = originalMethod.defaultNullness;
  
  		final TypeVariableBinding[] originalVariables = originalMethod.typeVariables;
  		Substitution substitution = null;
  		final int length = originalVariables.length;
  		if (length == 0) {
  			this.typeVariables = Binding.NO_TYPE_VARIABLES;
  		} else {
  			// at least fix up the declaringElement binding + bound substitution if non static
  			final TypeVariableBinding[] substitutedVariables = new TypeVariableBinding[length];
  			for (int i = 0; i < length; i++) { // copy original type variable to relocate
  				TypeVariableBinding originalVariable = originalVariables[i];
  				substitutedVariables[i] = new TypeVariableBinding(
  						alternateParamaterNames == null ?
  								originalVariable.sourceName :
  								alternateParamaterNames[i],
  							this,
  							originalVariable.rank,
  							environment);
  				substitutedVariables[i].tagBits |= (originalVariable.tagBits & (TagBits.AnnotationNullMASK|TagBits.HasNullTypeAnnotation));
  			}
  			this.typeVariables = substitutedVariables;
  
  			// need to substitute old var refs with new ones (double substitution: declaringClass + new type variables)
  			substitution = new Substitution() {
  				@Override
  				public LookupEnvironment environment() {
  					return environment;
  				}
  				@Override
  				public boolean isRawSubstitution() {
  					return false;
  				}
  				@Override
  				public TypeBinding substitute(TypeVariableBinding typeVariable) {
  			        // check this variable can be substituted given copied variables
  			        if (typeVariable.rank < length && TypeBinding.equalsEquals(originalVariables[typeVariable.rank], typeVariable)) {
  			        	TypeBinding substitute = substitutedVariables[typeVariable.rank];
  						return typeVariable.hasTypeAnnotations() ? environment().createAnnotatedType(substitute, typeVariable.getTypeAnnotations()) : substitute;
  			        }
  			        return typeVariable;
  				}
  			};
  
  			// initialize new variable bounds
  			for (int i = 0; i < length; i++) {
  				TypeVariableBinding originalVariable = originalVariables[i];
  				TypeVariableBinding substitutedVariable = substitutedVariables[i];
  				TypeBinding substitutedSuperclass = Scope.substitute(substitution, originalVariable.superclass);
  				ReferenceBinding[] substitutedInterfaces = Scope.substitute(substitution, originalVariable.superInterfaces);
  				if (originalVariable.firstBound != null) {
  					TypeBinding firstBound;
  					firstBound = TypeBinding.equalsEquals(originalVariable.firstBound, originalVariable.superclass)
  						? substitutedSuperclass // could be array type or interface
  						: substitutedInterfaces[0];
  					substitutedVariable.setFirstBound(firstBound);
  				}
  				switch (substitutedSuperclass.kind()) {
  					case Binding.ARRAY_TYPE :
  						substitutedVariable.setSuperClass(environment.getResolvedJavaBaseType(TypeConstants.JAVA_LANG_OBJECT, null));
  						substitutedVariable.setSuperInterfaces(substitutedInterfaces);
  						break;
  					default:
  						if (substitutedSuperclass.isInterface()) {
  							substitutedVariable.setSuperClass(environment.getResolvedType(TypeConstants.JAVA_LANG_OBJECT, null));
  							int interfaceCount = substitutedInterfaces.length;
  							System.arraycopy(substitutedInterfaces, 0, substitutedInterfaces = new ReferenceBinding[interfaceCount+1], 1, interfaceCount);
  							substitutedInterfaces[0] = (ReferenceBinding) substitutedSuperclass;
  							substitutedVariable.setSuperInterfaces(substitutedInterfaces);
  						} else {
  							substitutedVariable.setSuperClass((ReferenceBinding) substitutedSuperclass); // typeVar was extending other typeVar which got substituted with interface
  							substitutedVariable.setSuperInterfaces(substitutedInterfaces);
  						}
  				}
  			}
  		}
  		if (substitution != null) {
  			this.returnType = Scope.substitute(substitution, this.returnType);
  			this.parameters = Scope.substitute(substitution, this.parameters);
  			this.thrownExceptions = Scope.substitute(substitution, this.thrownExceptions);
  		    // error case where exception type variable would have been substituted by a non-reference type (207573)
  		    if (this.thrownExceptions == null) this.thrownExceptions = Binding.NO_EXCEPTIONS;
  		}
  		checkMissingType: {
  			if ((this.tagBits & TagBits.HasMissingType) != 0)
  				break checkMissingType;
  			if ((this.returnType.tagBits & TagBits.HasMissingType) != 0) {
  