use of dyvilx.tools.compiler.ast.type.IType in project Dyvil by Dyvil.
the class AbstractMethod method writeReceiver.
protected void writeReceiver(MethodWriter writer, IValue receiver) throws BytecodeException {
if (receiver == null) {
return;
}
if (!this.isStatic()) {
receiver.writeNullCheckedExpression(writer, this.enclosingClass.getReceiverType());
return;
}
if (receiver.isIgnoredClassAccess()) {
final IType type = receiver.getType();
if (type.hasTag(IType.TYPE_VAR)) {
// Static virtual call
type.writeClassExpression(writer, true);
}
return;
}
if (this.hasModifier(Modifiers.INFIX) && !this.parameters.isEmpty()) {
receiver.writeExpression(writer, this.parameters.get(0).getCovariantType());
return;
}
// static
receiver.writeExpression(writer, this.enclosingClass.getReceiverType());
writer.visitInsn(Opcodes.AUTO_POP);
}
use of dyvilx.tools.compiler.ast.type.IType in project Dyvil by Dyvil.
the class AbstractMethod method checkMutating.
private void checkMutating(MarkerList markers, IValue receiver) {
final IType receiverType = receiver.getType();
if (receiverType.getMutability() != Mutability.IMMUTABLE) {
return;
}
final Annotation mutatingAnnotation = this.getAnnotation(Types.MUTATING_CLASS);
if (mutatingAnnotation == null) {
return;
}
final IValue value = mutatingAnnotation.getArguments().get(0, Names.value);
final String stringValue = value != null ? value.stringValue() : Mutating.DEFAULT_MESSAGE;
StringBuilder builder = new StringBuilder(stringValue);
int index = builder.indexOf("{method}");
if (index >= 0) {
builder.replace(index, index + 8, this.name.unqualified);
}
index = builder.indexOf("{type}");
if (index >= 0) {
builder.replace(index, index + 6, receiverType.toString());
}
markers.add(new SemanticError(receiver.getPosition(), builder.toString()));
}
use of dyvilx.tools.compiler.ast.type.IType in project Dyvil by Dyvil.
the class AbstractMethod method checkImplicitMatch.
@Override
public void checkImplicitMatch(MatchList<IMethod> list, IValue value, IType type) {
if (!this.isImplicitConversion()) {
// The method has to be 'implicit static'
return;
}
final ParameterList parameterList = this.getParameters();
if (parameterList.size() != 1) {
// and only take exactly one parameter
return;
}
if (type != null && !Types.isSuperType(type, this.getType().asParameterType())) {
// The method's return type has to be a sub-type of the target type
return;
}
final IType parType = parameterList.get(0).getCovariantType();
// Note: this explicitly uses null as the context parameter to avoid nested implicit conversions
final int match = TypeChecker.getTypeMatch(value, parType, null);
// >= to allow the "light" conversions that are built in based on type, e.g. primitive widening or (un)boxing
if (match >= IValue.CONVERSION_MATCH) {
list.add(new Candidate<>(this, match, parType, false));
}
}
use of dyvilx.tools.compiler.ast.type.IType in project Dyvil by Dyvil.
the class AbstractMethod method checkTypeVarsInferred.
private void checkTypeVarsInferred(MarkerList markers, SourcePosition position, GenericData genericData) {
if (this.typeParameters == null) {
return;
}
final int count = this.typeParameters.size();
genericData.lock(count);
for (int i = 0; i < count; i++) {
final ITypeParameter typeParameter = this.typeParameters.get(i);
final IType typeArgument = genericData.resolveType(typeParameter);
if (typeArgument == null || typeArgument instanceof CovariantTypeVarType) {
final IType inferredType = typeParameter.getUpperBound();
markers.add(Markers.semantic(position, "method.typevar.infer", this.name, typeParameter.getName(), inferredType));
genericData.addMapping(typeParameter, inferredType);
} else if (!typeParameter.isAssignableFrom(typeArgument, genericData)) {
final Marker marker = Markers.semanticError(position, "method.typevar.incompatible", this.name, typeParameter.getName());
marker.addInfo(Markers.getSemantic("type.generic.argument", typeArgument));
marker.addInfo(Markers.getSemantic("type_parameter.declaration", typeParameter));
markers.add(marker);
}
}
}
use of dyvilx.tools.compiler.ast.type.IType in project Dyvil by Dyvil.
the class AbstractMethod method checkMatch.
@Override
public void checkMatch(MatchList<IMethod> list, IValue receiver, Name name, ArgumentList arguments) {
if (name != this.name && name != null) {
return;
}
final ParameterList parameters = this.getParameters();
final int parameterStartIndex;
final int argumentStartIndex;
final int argumentCount;
final int parameterCount = parameters.size();
final int[] matchValues;
final IType[] matchTypes;
boolean invalid = false;
final int mod = this.attributes.flags() & Modifiers.INFIX;
if (receiver == null) {
if (mod == Modifiers.INFIX) {
// disallow non-qualified access to infix methods
invalid = true;
}
if (arguments == null) {
list.add(new Candidate<>(this));
return;
}
argumentCount = arguments.size();
matchValues = new int[argumentCount];
matchTypes = new IType[argumentCount];
argumentStartIndex = 0;
parameterStartIndex = 0;
} else if (mod != 0 && receiver.isClassAccess()) {
// Static access to static method
final IType receiverType = receiver.getType();
if (!Types.isSuperType(this.getReceiverType(), receiverType)) {
// Disallow access from the wrong type
return;
}
if (arguments == null) {
list.add(new Candidate<>(this, IValue.EXACT_MATCH, receiverType, false));
return;
}
parameterStartIndex = 0;
argumentCount = arguments.size();
argumentStartIndex = 1;
matchValues = new int[1 + argumentCount];
matchTypes = new IType[1 + argumentCount];
matchValues[0] = 1;
matchTypes[0] = receiverType;
} else {
if (// a
mod == Modifiers.STATIC && !receiver.isClassAccess() || // b
mod == 0 && receiver.isClassAccess() && !receiver.getType().getTheClass().isObject()) {
// Disallow non-static access to static method (a)
// and static access to instance method (unless it's an object class) (b)
invalid = true;
}
final IType receiverType;
if (mod == Modifiers.INFIX && !parameters.isEmpty()) {
// Infix access to infix method
receiverType = parameters.get(0).getCovariantType();
parameterStartIndex = 1;
} else {
// Infix access to instance method
receiverType = this.getReceiverType();
parameterStartIndex = 0;
}
final int receiverMatch = TypeChecker.getTypeMatch(receiver, receiverType, list);
if (receiverMatch == IValue.MISMATCH) {
return;
}
if (arguments == null) {
list.add(new Candidate<>(this, receiverMatch, receiverType, invalid));
return;
}
argumentCount = arguments.size();
argumentStartIndex = 1;
matchValues = new int[1 + argumentCount];
matchTypes = new IType[1 + argumentCount];
matchValues[0] = receiverMatch;
matchTypes[0] = receiverType;
}
final int parametersLeft = parameterCount - parameterStartIndex;
if (argumentCount > parametersLeft && !this.isVariadic()) {
return;
}
int defaults = 0;
int varargs = 0;
for (int argumentIndex = 0; argumentIndex < parametersLeft; argumentIndex++) {
final IParameter parameter = parameters.get(parameterStartIndex + argumentIndex);
final int partialVarargs = arguments.checkMatch(matchValues, matchTypes, argumentStartIndex, argumentIndex, parameter, list);
switch(partialVarargs) {
case ArgumentList.MISMATCH:
return;
case ArgumentList.DEFAULT:
defaults++;
continue;
default:
varargs += partialVarargs;
}
}
for (int matchValue : matchValues) {
if (matchValue == IValue.MISMATCH) {
// Mismatch
return;
}
}
list.add(new Candidate<>(this, matchValues, matchTypes, defaults, varargs, invalid));
}
Aggregations