<commit_before>package be.kuleuven.cs.distrinet.jnome.core.expression.invocation;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import be.kuleuven.cs.distrinet.chameleon.core.element.Element;
import be.kuleuven.cs.distrinet.chameleon.core.language.WrongLanguageException;
import be.kuleuven.cs.distrinet.chameleon.core.lookup.LookupException;
import be.kuleuven.cs.distrinet.chameleon.exception.ChameleonProgrammerException;
import be.kuleuven.cs.distrinet.chameleon.oo.expression.MethodInvocation;
import be.kuleuven.cs.distrinet.chameleon.oo.language.ObjectOrientedLanguage;
import be.kuleuven.cs.distrinet.chameleon.oo.method.MethodHeader;
import be.kuleuven.cs.distrinet.chameleon.oo.type.IntersectionType;
import be.kuleuven.cs.distrinet.chameleon.oo.type.Type;
import be.kuleuven.cs.distrinet.chameleon.oo.type.generics.ActualTypeArgument;
import be.kuleuven.cs.distrinet.chameleon.oo.type.generics.ActualTypeArgumentWithTypeReference;
import be.kuleuven.cs.distrinet.chameleon.oo.type.generics.BasicTypeArgument;
import be.kuleuven.cs.distrinet.chameleon.oo.type.generics.EqualityConstraint;
import be.kuleuven.cs.distrinet.chameleon.oo.type.generics.ExtendsWildcard;
import be.kuleuven.cs.distrinet.chameleon.oo.type.generics.InstantiatedParameterType;
import be.kuleuven.cs.distrinet.chameleon.oo.type.generics.InstantiatedTypeParameter;
import be.kuleuven.cs.distrinet.chameleon.oo.type.generics.SuperWildcard;
import be.kuleuven.cs.distrinet.chameleon.oo.type.generics.TypeParameter;
import be.kuleuven.cs.distrinet.chameleon.support.expression.AssignmentExpression;
import be.kuleuven.cs.distrinet.chameleon.util.Util;
import be.kuleuven.cs.distrinet.chameleon.workspace.View;
import be.kuleuven.cs.distrinet.jnome.core.language.Java;
import be.kuleuven.cs.distrinet.jnome.core.type.JavaTypeReference;
import be.kuleuven.cs.distrinet.rejuse.predicate.AbstractPredicate;
import be.kuleuven.cs.distrinet.rejuse.predicate.TypePredicate;

import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSet.Builder;
import com.google.common.collect.Sets;

public class SecondPhaseConstraintSet extends ConstraintSet<SecondPhaseConstraint> {

	public SecondPhaseConstraintSet(MethodInvocation invocation, MethodHeader invokedMethod, FirstPhaseConstraintSet origin) {
		super(invocation,invokedMethod);
		_assignments = new TypeAssignmentSet(typeParameters());
		_origin = origin;
	}
	
	private FirstPhaseConstraintSet _origin;

	private List<JavaTypeReference> Us(TypeParameter Tj, Class<? extends SecondPhaseConstraint> kind) throws LookupException {
		List<JavaTypeReference> Us = new ArrayList<JavaTypeReference>();
		for(SecondPhaseConstraint constraint: constraints()) {
			if((kind.isInstance(constraint)) && constraint.typeParameter().sameAs(Tj)) {
				Us.add(constraint.URef());
			}
		}
		return Us;
	}
	


	
	private Type leastUpperBound(List<? extends JavaTypeReference> Us, Java language) throws LookupException {
		return language.subtypeRelation().leastUpperBound(Us);
	}

	private void processSuperTypeConstraints() throws LookupException {
		Java language = null;
		for(TypeParameter p: typeParameters()) {
			boolean hasSuperConstraints = false;
			for(SecondPhaseConstraint constraint: constraints()) {
				if(constraint instanceof SupertypeConstraint && constraint.typeParameter().sameAs(p)) {
					hasSuperConstraints = true;
					break;
				}
			}
			if(hasSuperConstraints) {
				List<JavaTypeReference> Us = Us(p, SupertypeConstraint.class);
				if(language == null) {
					language = p.language(Java.class);
				}
				add(new ActualTypeAssignment(p, leastUpperBound(Us,language)));
			}
		}
	}
	
	private void processEqualityConstraints() throws LookupException {
		boolean searching = true;
		while(searching) {
			// Keep processing until there are no equality constraints.
			List<? extends SecondPhaseConstraint> constraints = constraints();
			new TypePredicate<EqualTypeConstraint>(EqualTypeConstraint.class).filter(constraints);
		  EqualTypeConstraint eq = first(EqualTypeConstraint.class);
			if(eq != null) {
			  eq.process();
			} else {
				searching = false;
			}
		}
	}
	
	
	public TypeAssignmentSet assignments() {
		return _assignments;
	}
	
	public void add(TypeAssignment assignment) {
		_assignments.add(assignment);
	}
	
	private TypeAssignmentSet _assignments;

  public void process() throws LookupException {
  	processEqualityConstraints();
  	processSuperTypeConstraints();
  	processUnresolvedParameters();
  }
  
  private void processUnresolvedParameters() throws LookupException {
  	// JLS 15.12.2.8
  	// In context of assignment with type S.
  	if(inContextOfAssignmentConversion()) {
  		processUnresolved(S());
  	} else {
  		// Perform under the assumption that S is java.lang.Object
  		if(! typeParameters().isEmpty()) {
  			TypeParameter typeParameter = typeParameters().get(0);
  			View view = typeParameter.view();
				ObjectOrientedLanguage language = (ObjectOrientedLanguage) view.language();
  			processUnresolved((JavaTypeReference) language.createTypeReferenceInNamespace(language.getDefaultSuperClassFQN(),view.namespace()));
  		}
  	}
  }

  private JavaTypeReference box(JavaTypeReference ref) throws WrongLanguageException, LookupException {
  	return ref.language(Java.class).box(ref, ref.namespace());
  }
  
	private void processUnresolved(JavaTypeReference Sref) throws LookupException {
		JavaTypeReference RRef = (JavaTypeReference) invokedGenericMethod().returnTypeReference();
		FirstPhaseConstraintSet constraints = new FirstPhaseConstraintSet(invocation(), invokedGenericMethod());
		View view = RRef.view();
		JavaTypeReference SprimeRef = box(Sref);
		Java java = view.language(Java.class);
		if(! RRef.getElement().sameAs(java.voidType(RRef.view().namespace()))) {
		  // the constraint S >> R', provided R is not void	
			JavaTypeReference RprimeRef = substitutedReference(RRef);
			constraints.add(new GGConstraint(SprimeRef, RprimeRef.getType()));
		}
		// additional constraints Bi[T1=B(T1) ... Tn=B(Tn)] >> Ti where Bi is the declared bound of Ti
		for(TypeParameter param: typeParameters()) {
			JavaTypeReference Bi = (JavaTypeReference) param.upperBoundReference();
			JavaTypeReference BiAfterSubstitution= substitutedReference(Bi);
			
			Type Ti = (Type) param.selectionDeclaration();
			Type BTi = assignments().type(param);
			if(BTi == null) {
				BTi = Ti;
			}<commit_msg>only process unresolved parameters when there are any<commit_after>package be.kuleuven.cs.distrinet.jnome.core.expression.invocation;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import be.kuleuven.cs.distrinet.chameleon.core.element.Element;
import be.kuleuven.cs.distrinet.chameleon.core.language.WrongLanguageException;
import be.kuleuven.cs.distrinet.chameleon.core.lookup.LookupException;
import be.kuleuven.cs.distrinet.chameleon.exception.ChameleonProgrammerException;
import be.kuleuven.cs.distrinet.chameleon.oo.expression.MethodInvocation;
import be.kuleuven.cs.distrinet.chameleon.oo.language.ObjectOrientedLanguage;
import be.kuleuven.cs.distrinet.chameleon.oo.method.MethodHeader;
import be.kuleuven.cs.distrinet.chameleon.oo.type.IntersectionType;
import be.kuleuven.cs.distrinet.chameleon.oo.type.Type;
import be.kuleuven.cs.distrinet.chameleon.oo.type.generics.ActualTypeArgument;
import be.kuleuven.cs.distrinet.chameleon.oo.type.generics.ActualTypeArgumentWithTypeReference;
import be.kuleuven.cs.distrinet.chameleon.oo.type.generics.BasicTypeArgument;
import be.kuleuven.cs.distrinet.chameleon.oo.type.generics.EqualityConstraint;
import be.kuleuven.cs.distrinet.chameleon.oo.type.generics.ExtendsWildcard;
import be.kuleuven.cs.distrinet.chameleon.oo.type.generics.InstantiatedParameterType;
import be.kuleuven.cs.distrinet.chameleon.oo.type.generics.InstantiatedTypeParameter;
import be.kuleuven.cs.distrinet.chameleon.oo.type.generics.SuperWildcard;
import be.kuleuven.cs.distrinet.chameleon.oo.type.generics.TypeParameter;
import be.kuleuven.cs.distrinet.chameleon.support.expression.AssignmentExpression;
import be.kuleuven.cs.distrinet.chameleon.util.Util;
import be.kuleuven.cs.distrinet.chameleon.workspace.View;
import be.kuleuven.cs.distrinet.jnome.core.language.Java;
import be.kuleuven.cs.distrinet.jnome.core.type.JavaTypeReference;
import be.kuleuven.cs.distrinet.rejuse.predicate.AbstractPredicate;
import be.kuleuven.cs.distrinet.rejuse.predicate.TypePredicate;

import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSet.Builder;
import com.google.common.collect.Sets;

public class SecondPhaseConstraintSet extends ConstraintSet<SecondPhaseConstraint> {

	public SecondPhaseConstraintSet(MethodInvocation invocation, MethodHeader invokedMethod, FirstPhaseConstraintSet origin) {
		super(invocation,invokedMethod);
		_assignments = new TypeAssignmentSet(typeParameters());
		_origin = origin;
	}
	
	private FirstPhaseConstraintSet _origin;

	private List<JavaTypeReference> Us(TypeParameter Tj, Class<? extends SecondPhaseConstraint> kind) throws LookupException {
		List<JavaTypeReference> Us = new ArrayList<JavaTypeReference>();
		for(SecondPhaseConstraint constraint: constraints()) {
			if((kind.isInstance(constraint)) && constraint.typeParameter().sameAs(Tj)) {
				Us.add(constraint.URef());
			}
		}
		return Us;
	}
	


	
	private Type leastUpperBound(List<? extends JavaTypeReference> Us, Java language) throws LookupException {
		return language.subtypeRelation().leastUpperBound(Us);
	}

	private void processSuperTypeConstraints() throws LookupException {
		Java language = null;
		for(TypeParameter p: typeParameters()) {
			boolean hasSuperConstraints = false;
			for(SecondPhaseConstraint constraint: constraints()) {
				if(constraint instanceof SupertypeConstraint && constraint.typeParameter().sameAs(p)) {
					hasSuperConstraints = true;
					break;
				}
			}
			if(hasSuperConstraints) {
				List<JavaTypeReference> Us = Us(p, SupertypeConstraint.class);
				if(language == null) {
					language = p.language(Java.class);
				}
				add(new ActualTypeAssignment(p, leastUpperBound(Us,language)));
			}
		}
	}
	
	private void processEqualityConstraints() throws LookupException {
		boolean searching = true;
		while(searching) {
			// Keep processing until there are no equality constraints.
			List<? extends SecondPhaseConstraint> constraints = constraints();
			new TypePredicate<EqualTypeConstraint>(EqualTypeConstraint.class).filter(constraints);
		  EqualTypeConstraint eq = first(EqualTypeConstraint.class);
			if(eq != null) {
			  eq.process();
			} else {
				searching = false;
			}
		}
	}
	
	
	public TypeAssignmentSet assignments() {
		return _assignments;
	}
	
	public void add(TypeAssignment assignment) {
		_assignments.add(assignment);
	}
	
	private TypeAssignmentSet _assignments;

  public void process() throws LookupException {
  	processEqualityConstraints();
  	processSuperTypeConstraints();
  	processUnresolvedParameters();
  }
  
  private void processUnresolvedParameters() throws LookupException {
  	// JLS 15.12.2.8
  	// In context of assignment with type S.
  	if(inContextOfAssignmentConversion()) {
  		processUnresolved(S());
  	} else {
  		// Perform under the assumption that S is java.lang.Object
  		if(! unresolvedParameters().isEmpty()) {
//  			TypeParameter typeParameter = typeParameters().get(0);
  			View view = invocation().view();
				ObjectOrientedLanguage language = (ObjectOrientedLanguage) view.language();
  			processUnresolved((JavaTypeReference) language.createTypeReferenceInNamespace(language.getDefaultSuperClassFQN(),view.namespace()));
  		}
  	}
  }

  private JavaTypeReference box(JavaTypeReference ref) throws WrongLanguageException, LookupException {
  	return ref.language(Java.class).box(ref, ref.namespace());
  }
  
	private void processUnresolved(JavaTypeReference Sref) throws LookupException {
		JavaTypeReference RRef = (JavaTypeReference) invokedGenericMethod().returnTypeReference();
		FirstPhaseConstraintSet constraints = new FirstPhaseConstraintSet(invocation(), invokedGenericMethod());
		View view = RRef.view();
		JavaTypeReference SprimeRef = box(Sref);
		Java java = view.language(Java.class);
		if(! RRef.getElement().sameAs(java.voidType(RRef.view().namespace()))) {
		  // the constraint S >> R', provided R is not void	
			JavaTypeReference RprimeRef = substitutedReference(RRef);
			constraints.add(new GGConstraint(SprimeRef, RprimeRef.getType()));
		}
		// additional constraints Bi[T1=B(T1) ... Tn=B(Tn)] >> Ti where Bi is the declared bound of Ti
		for(TypeParameter param: typeParameters()) {
			JavaTypeReference Bi = (JavaTypeReference) param.upperBoundReference();
			JavaTypeReference BiAfterSubstitution= substitutedReference(Bi);
			
			Type Ti = (Type) param.selectionDeclaration();
			Type BTi = assignments().type(param);
			if(BTi == null) {
				BTi = Ti;
			}
{'fraction_non_alphanumeric': 0.10738772051459826, 'fraction_numerical': 0.0013866420152530623, 'mean_word_length': 5.439484126984127, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 29, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 2, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '538730', 'n_tokens_mistral': 4341, 'n_tokens_neox': 4038, 'n_words': 677}