use of com.redhat.ceylon.model.typechecker.model.Interface in project ceylon-compiler by ceylon.
the class ExpressionTransformer method transformSuperOf.
private JCExpression transformSuperOf(Node node, Tree.Primary superPrimary, String forMemberName) {
Tree.Term superOf = eliminateParens(superPrimary);
if (!(superOf instanceof Tree.OfOp)) {
throw new BugException();
}
Tree.Type superType = ((Tree.OfOp) superOf).getType();
if (!(eliminateParens(((Tree.OfOp) superOf).getTerm()) instanceof Tree.Super)) {
throw new BugException();
}
TypeDeclaration inheritedFrom = superType.getTypeModel().getDeclaration();
if (inheritedFrom instanceof Interface) {
inheritedFrom = (TypeDeclaration) inheritedFrom.getMember(forMemberName, null, false).getContainer();
}
return widenSuper(node, inheritedFrom);
}
use of com.redhat.ceylon.model.typechecker.model.Interface in project ceylon-compiler by ceylon.
the class ExpressionTransformer method lostTypeParameterInInheritance.
private boolean lostTypeParameterInInheritance(Type exprType, Type commonType) {
if (exprType.getDeclaration() instanceof ClassOrInterface == false || commonType.getDeclaration() instanceof ClassOrInterface == false)
return false;
ClassOrInterface exprDecl = (ClassOrInterface) exprType.getDeclaration();
ClassOrInterface commonDecl = (ClassOrInterface) commonType.getDeclaration();
// do not search interfaces if the common declaration is a class, because interfaces cannot be subtypes of a class
boolean searchInterfaces = commonDecl instanceof Interface;
return lostTypeParameterInInheritance(exprDecl, commonDecl, searchInterfaces, false);
}
use of com.redhat.ceylon.model.typechecker.model.Interface in project ceylon-compiler by ceylon.
the class ExpressionTransformer method transform.
//
// Operator-Assignment expressions
public JCExpression transform(final Tree.ArithmeticAssignmentOp op) {
final AssignmentOperatorTranslation operator = Operators.getAssignmentOperator(op.getClass());
if (operator == null) {
return makeErroneous(op, "compiler bug: " + op.getNodeType() + " is not a supported arithmetic assignment operator");
}
// see if we can optimise it
if (op.getUnboxed() && CodegenUtil.isDirectAccessVariable(op.getLeftTerm())) {
return optimiseAssignmentOperator(op, operator);
}
// we can use unboxed types if both operands are unboxed
final boolean boxResult = !op.getUnboxed();
// find the proper type
Interface compoundType = op.getUnit().getNumericDeclaration();
if (op instanceof Tree.AddAssignOp) {
compoundType = op.getUnit().getSummableDeclaration();
} else if (op instanceof Tree.SubtractAssignOp) {
compoundType = op.getUnit().getInvertableDeclaration();
} else if (op instanceof Tree.RemainderAssignOp) {
compoundType = op.getUnit().getIntegralDeclaration();
}
final Type leftType = getSupertype(op.getLeftTerm(), compoundType);
final Type resultType = getMostPreciseType(op.getLeftTerm(), getTypeArgument(leftType, 0));
// Normally we don't look at the RHS type because it can lead to unknown types, but if we want to extract its
// underlying type we have to, and we deal with any eventual unknown type. Presumably unknown types will not have
// any useful underlying type anyways.
// Note that looking at the RHS allows us to not have the issue of using the LHS type wrongly for the RHS type when
// the LHS type is Float and the RHS type is Integer with implicit Float coercion
Type rightSupertype = getSupertype(op.getRightTerm(), compoundType);
if (rightSupertype == null || rightSupertype.isUnknown()) {
// supertype could be null if, e.g. right type is Nothing
rightSupertype = leftType;
}
Type rightTypeArgument = getTypeArgument(rightSupertype);
if (rightTypeArgument == null || rightTypeArgument.isUnknown())
rightTypeArgument = getTypeArgument(leftType);
final Type rightType = getMostPreciseType(op.getLeftTerm(), rightTypeArgument);
// we work on boxed types
return transformAssignAndReturnOperation(op, op.getLeftTerm(), boxResult, leftType, resultType, new AssignAndReturnOperationFactory() {
@Override
public JCExpression getNewValue(JCExpression previousValue) {
// make this call: previousValue OP RHS
JCExpression ret = transformOverridableBinaryOperator(op.getLeftTerm(), op.getRightTerm(), rightType, operator.binaryOperator, boxResult ? OptimisationStrategy.NONE : OptimisationStrategy.OPTIMISE, previousValue, op.getTypeModel());
return ret;
}
});
}
use of com.redhat.ceylon.model.typechecker.model.Interface in project ceylon-compiler by ceylon.
the class ExpressionTransformer method isNaturalTarget.
/**
* Whether an annotation (with the given {@code annotationCtorDecl}
* annotation constructor) used on the given declaration ({@code useSite})
* should be added to the Java annotations of the given generated program
* elements ({@code target})
* @param annotationCtorDecl
* @param useSite
* @param target
* @return
*/
private boolean isNaturalTarget(// use site is either a Declaration, or a Package, or a Module,
Function annotationCtorDecl, // module imports
Object useSite, OutputElement target) {
EnumSet<AnnotationTarget> interopTargets;
if (annotationCtorDecl instanceof AnnotationProxyMethod) {
AnnotationProxyMethod annotationProxyMethod = (AnnotationProxyMethod) annotationCtorDecl;
if (annotationProxyMethod.getAnnotationTarget() == target) {
// Foo__WHATEVER, so honour the WHATEVER
return true;
}
interopTargets = annotationProxyMethod.getProxyClass().getAnnotationTarget();
} else {
interopTargets = null;
}
if (useSite instanceof Declaration) {
if (ModelUtil.isConstructor((Declaration) useSite)) {
if (useSite instanceof Functional) {
return target == OutputElement.CONSTRUCTOR;
} else if (useSite instanceof Value) {
return target == OutputElement.GETTER;
}
} else if (useSite instanceof Class) {
if (((Class) useSite).getParameterList() != null && interopTargets != null && interopTargets.contains(AnnotationTarget.CONSTRUCTOR) && !interopTargets.contains(AnnotationTarget.TYPE)) {
return target == OutputElement.CONSTRUCTOR;
}
return target == OutputElement.TYPE;
} else if (useSite instanceof Interface) {
return target == OutputElement.TYPE;
} else if (useSite instanceof Value) {
Value value = (Value) useSite;
TypeDeclaration decltype = typeFact().getValueDeclarationType().getDeclaration();
if (value.isParameter() && !value.isShared() && !(value.isCaptured() && value.isMember())) {
return target == OutputElement.PARAMETER;
} else if (annotationCtorDecl instanceof AnnotationProxyMethod) {
if (value.isLate() || value.isVariable()) {
return target == OutputElement.SETTER;
} else if (!value.isTransient()) {
return target == OutputElement.FIELD;
} else {
return target == OutputElement.GETTER;
}
} else {
return target == OutputElement.GETTER;
}
} else if (useSite instanceof Setter) {
return target == OutputElement.SETTER;
} else if (useSite instanceof Function) {
return target == OutputElement.METHOD;
} else if (useSite instanceof Constructor) {
return target == OutputElement.CONSTRUCTOR;
} else if (useSite instanceof TypeAlias) {
return target == OutputElement.TYPE;
}
} else if (useSite instanceof Package) {
return target == OutputElement.TYPE;
} else if (useSite instanceof Module) {
return target == OutputElement.TYPE;
} else if (useSite instanceof Tree.ImportModule) {
return target == OutputElement.FIELD;
}
throw new RuntimeException("" + useSite);
}
use of com.redhat.ceylon.model.typechecker.model.Interface in project ceylon-compiler by ceylon.
the class ExpressionTransformer method transform.
public JCTree transform(Tree.IndexExpression access) {
// depends on the operator
Tree.ElementOrRange elementOrRange = access.getElementOrRange();
boolean isElement = elementOrRange instanceof Tree.Element;
// let's see what types there are
Type leftType = access.getPrimary().getTypeModel();
// find the corresponding supertype
Interface leftSuperTypeDeclaration;
if (isElement)
leftSuperTypeDeclaration = typeFact().getCorrespondenceDeclaration();
else
leftSuperTypeDeclaration = typeFact().getRangedDeclaration();
Type leftCorrespondenceOrRangeType = leftType.getSupertype(leftSuperTypeDeclaration);
Type rightType = getTypeArgument(leftCorrespondenceOrRangeType, 0);
// now find the access code
JCExpression safeAccess;
if (isElement) {
// can we use getFromFirst() to avoid boxing the index?
boolean listOptim = leftType.isSubtypeOf(typeFact().getListDeclaration().appliedType(null, Collections.singletonList(typeFact().getAnythingType())));
Type leftTypeForGetCall = listOptim ? leftType.getSupertype(typeFact().getListDeclaration()) : leftCorrespondenceOrRangeType;
Tree.Primary primary = access.getPrimary();
JCExpression lhs;
boolean isSuper = isSuper(primary);
if (isSuper || isSuperOf(primary)) {
TypeDeclaration leftDeclaration = null;
// has a concrete super implementation
if (listOptim) {
Declaration member = leftType.getDeclaration().getMember("getFromFirst", null, false);
if (member == null || member.isFormal()) {
listOptim = false;
} else {
leftDeclaration = (TypeDeclaration) member.getContainer();
}
}
// if we did not already find the right supertype, try with "get"
if (leftDeclaration == null) {
Declaration member = leftType.getDeclaration().getMember("get", null, false);
leftDeclaration = (TypeDeclaration) member.getContainer();
}
if (isSuper)
lhs = transformSuper(access, leftDeclaration);
else
lhs = transformSuperOf(access, access.getPrimary(), listOptim ? "getFromFirst" : "get");
} else {
lhs = transformExpression(access.getPrimary(), BoxingStrategy.BOXED, leftTypeForGetCall);
}
Tree.Element element = (Tree.Element) elementOrRange;
// do the index
JCExpression index = transformExpression(element.getExpression(), listOptim ? BoxingStrategy.UNBOXED : BoxingStrategy.BOXED, rightType);
// tmpVar.item(index)
safeAccess = at(access).Apply(List.<JCTree.JCExpression>nil(), makeSelect(lhs, listOptim ? "getFromFirst" : "get"), List.of(index));
// Because tuple index access has the type of the indexed element
// (not the union of types in the sequential) a typecast may be required.
Type sequentialElementType = getTypeArgument(leftCorrespondenceOrRangeType, 1);
Type expectedType = access.getTypeModel();
int flags = 0;
if (!expectedType.isExactly(sequentialElementType) && // could be optional too, for regular Correspondence item access
!expectedType.isExactly(typeFact().getOptionalType(sequentialElementType)))
flags |= EXPR_DOWN_CAST;
safeAccess = applyErasureAndBoxing(safeAccess, sequentialElementType, CodegenUtil.hasTypeErased(access), true, BoxingStrategy.BOXED, expectedType, flags);
} else {
// do the indices
Tree.ElementRange range = (Tree.ElementRange) elementOrRange;
JCExpression start = transformExpression(range.getLowerBound(), BoxingStrategy.BOXED, rightType);
// is this a span or segment?
String method;
final List<JCExpression> args;
if (range.getLowerBound() != null && range.getLength() != null) {
method = "measure";
JCExpression length = transformExpression(range.getLength(), BoxingStrategy.UNBOXED, typeFact().getIntegerType());
args = List.of(start, length);
} else if (range.getLowerBound() == null) {
method = "spanTo";
JCExpression end = transformExpression(range.getUpperBound(), BoxingStrategy.BOXED, rightType);
args = List.of(end);
} else if (range.getUpperBound() == null) {
method = "spanFrom";
args = List.of(start);
} else if (range.getLowerBound() != null && range.getUpperBound() != null) {
method = "span";
JCExpression end = transformExpression(range.getUpperBound(), BoxingStrategy.BOXED, rightType);
args = List.of(start, end);
} else {
method = "unknown";
args = List.<JCExpression>of(makeErroneous(range, "compiler bug: unhandled range"));
}
JCExpression lhs;
Tree.Primary primary = access.getPrimary();
boolean isSuper = isSuper(primary);
if (isSuper || isSuperOf(primary)) {
Declaration member = leftType.getDeclaration().getMember(method, null, false);
TypeDeclaration leftDeclaration = (TypeDeclaration) member.getContainer();
if (isSuper)
lhs = transformSuper(access, leftDeclaration);
else
lhs = transformSuperOf(access, access.getPrimary(), method);
} else {
lhs = transformExpression(access.getPrimary(), BoxingStrategy.BOXED, leftCorrespondenceOrRangeType);
}
// Because tuple open span access has the type of the indexed element
// (not a sequential of the union of types in the ranged) a typecast may be required.
Type rangedSpanType = getTypeArgument(leftCorrespondenceOrRangeType, 2);
Type expectedType = access.getTypeModel();
int flags = 0;
if (!expectedType.isExactly(rangedSpanType)) {
flags |= EXPR_DOWN_CAST;
// make sure we barf properly if we missed a heuristics
if (method.equals("spanFrom")) {
// make a "Util.<method>(lhs, start, end)" call
at(access);
safeAccess = utilInvocation().tuple_spanFrom(args.prepend(lhs));
} else {
safeAccess = makeErroneous(access, "compiler bug: only the spanFrom method should be specialised for Tuples");
}
} else {
// make a "lhs.<method>(start, end)" call
safeAccess = at(access).Apply(List.<JCTree.JCExpression>nil(), makeSelect(lhs, method), args);
}
safeAccess = applyErasureAndBoxing(safeAccess, rangedSpanType, CodegenUtil.hasTypeErased(access), true, BoxingStrategy.BOXED, expectedType, flags);
}
return safeAccess;
}
Aggregations