<commit_before>package net.sandius.rembulan.compiler.types;

import net.sandius.rembulan.compiler.gen.LuaTypes;
import net.sandius.rembulan.util.Check;
import net.sandius.rembulan.util.PartialOrderComparisonResult;
import net.sandius.rembulan.util.ReadOnlyArray;

import java.util.ArrayList;

public class TypeSeq implements GradualTypeLike<TypeSeq> {

	protected final ReadOnlyArray<Type> fixed;
	protected final boolean varargs;

	public TypeSeq(ReadOnlyArray<Type> fixed, boolean varargs) {
		Check.notNull(fixed);
		this.fixed = fixed;
		this.varargs = varargs;
	}

	private static final TypeSeq EMPTY_FIXED = new TypeSeq(ReadOnlyArray.wrap(new Type[0]), false);
	private static final TypeSeq EMPTY_VARARG = new TypeSeq(ReadOnlyArray.wrap(new Type[0]), true);

	public static TypeSeq empty() {
		return EMPTY_FIXED;
	}

	public static TypeSeq vararg() {
		return EMPTY_VARARG;
	}

	public static TypeSeq of(Type... fixed) {
		return new TypeSeq(ReadOnlyArray.wrap(fixed), false);
	}

	public TypeSeq withVararg() {
		return hasVarargs() ? this : new TypeSeq(fixed, true);
	}

	@Override
	public boolean equals(Object o) {
		if (this == o) return true;
		if (o == null || getClass() != o.getClass()) return false;

		TypeSeq that = (TypeSeq) o;

		if (varargs != that.varargs) return false;
		return fixed.equals(that.fixed);
	}

	@Override
	public int hashCode() {
		int result = fixed.shallowHashCode();
		result = 31 * result + (varargs ? 1 : 0);
		return result;
	}

	@Override
	public String toString() {
		StringBuilder bld = new StringBuilder();
		for (int i = 0; i < fixed.size(); i++) {
			bld.append(fixed.get(i).toString());
		}
		if (varargs) {
			bld.append("+");
		}
		return bld.toString();
	}

	public ReadOnlyArray<Type> fixed() {
		return fixed;
	}

	public boolean hasVarargs() {
		return varargs;
	}

	public boolean isVarargOnly() {
		return fixed().isEmpty() && hasVarargs();
	}

	public Type get(int idx) {
		Check.nonNegative(idx);

		if (idx < fixed().size()) return fixed().get(idx);  // it's a fixed arg
		else if (hasVarargs()) return LuaTypes.ANY;  // it's a vararg
		else return LuaTypes.NIL;  // it's not there
	}

	public boolean isSubsumedBy(TypeSeq that) {
		Check.notNull(that);

		// that is more general than this

		for (int i = 0; i < Math.max(this.fixed().size(), that.fixed().size()); i++) {
			if (!this.get(i).isSubtypeOf(that.get(i))) {
				return false;
			}<commit_msg>Generalising the implementation of varargs to allow tails with arbitrary types.<commit_after>package net.sandius.rembulan.compiler.types;

import net.sandius.rembulan.compiler.gen.LuaTypes;
import net.sandius.rembulan.util.Check;
import net.sandius.rembulan.util.PartialOrderComparisonResult;
import net.sandius.rembulan.util.ReadOnlyArray;

import java.util.ArrayList;

public class TypeSeq implements GradualTypeLike<TypeSeq> {

	protected final ReadOnlyArray<Type> fixed;
	protected final Type tailType;

	@Deprecated
	public TypeSeq(ReadOnlyArray<Type> fixed, Type tailType) {
		Check.notNull(fixed);
		Check.notNull(tailType);
		this.fixed = fixed;
		this.tailType = tailType;
	}

	@Deprecated
	public TypeSeq(ReadOnlyArray<Type> fixed, boolean varargs) {
		this(fixed, varargs ? LuaTypes.ANY : LuaTypes.NIL);
	}

	private static final TypeSeq EMPTY_FIXED = new TypeSeq(ReadOnlyArray.wrap(new Type[0]), false);
	private static final TypeSeq EMPTY_VARARG = new TypeSeq(ReadOnlyArray.wrap(new Type[0]), true);

	public static TypeSeq empty() {
		return EMPTY_FIXED;
	}

	public static TypeSeq vararg() {
		return EMPTY_VARARG;
	}

	public static TypeSeq of(Type... fixed) {
		return new TypeSeq(ReadOnlyArray.wrap(fixed), false);
	}

	public TypeSeq withVararg() {
		return hasVarargs() ? this : new TypeSeq(fixed, true);
	}

	@Override
	public boolean equals(Object o) {
		if (this == o) return true;
		if (o == null || getClass() != o.getClass()) return false;

		TypeSeq that = (TypeSeq) o;

		return this.tailType.equals(that.tailType) && this.fixed.equals(that.fixed);
	}

	@Override
	public int hashCode() {
		int result = fixed.shallowHashCode();
		result = 31 * result + tailType.hashCode();
		return result;
	}

	@Override
	public String toString() {
		StringBuilder bld = new StringBuilder();
		for (int i = 0; i < fixed.size(); i++) {
			bld.append(fixed.get(i).toString());
		}

		if (tailType.equals(LuaTypes.ANY)) {
			bld.append("+");
		}
		else if (tailType.equals(LuaTypes.NIL)) {
			// do nothing
		}
		else {
			bld.append(tailType.toString()).append("*");
		}
		return bld.toString();
	}

	public ReadOnlyArray<Type> fixed() {
		return fixed;
	}

	public boolean hasVarargs() {
		return !tailType.equals(LuaTypes.NIL);
	}

	public boolean isVarargOnly() {
		return fixed().isEmpty() && hasVarargs();
	}

	public Type get(int idx) {
		Check.nonNegative(idx);

		if (idx < fixed().size()) return fixed().get(idx);  // it's a fixed arg
		else if (hasVarargs()) return LuaTypes.ANY;  // it's a vararg
		else return LuaTypes.NIL;  // it's not there
	}

	public boolean isSubsumedBy(TypeSeq that) {
		Check.notNull(that);

		// that is more general than this

		for (int i = 0; i < Math.max(this.fixed().size(), that.fixed().size()); i++) {
			if (!this.get(i).isSubtypeOf(that.get(i))) {
				return false;
			}
{'fraction_non_alphanumeric': 0.1370568051849028, 'fraction_numerical': 0.002668699961875715, 'mean_word_length': 4.114035087719298, 'pattern_counts': {'":': 0, '<': 18, '<?xml version=': 0, '>': 12, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, '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': '1092471', 'n_tokens_mistral': 1935, 'n_tokens_neox': 1792, 'n_words': 451}