use of org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCExpression in project ceylon by eclipse.
the class ExpressionTransformer method transform.
public JCExpression transform(Tree.IsOp op) {
// make sure we do not insert null checks if we're going to allow testing for null
Type expectedType = getOptionalTypeForInteropIfAllowed(op.getType().getTypeModel(), op.getTerm().getTypeModel(), op.getTerm());
// we don't need any erasure type cast for an "is" test
JCExpression expression = transformExpression(op.getTerm(), BoxingStrategy.BOXED, expectedType);
at(op);
Naming.SyntheticName varName = naming.temp();
JCExpression test = makeOptimizedTypeTest(null, varName, op.getType().getTypeModel(), op.getTerm().getTypeModel());
return makeLetExpr(varName, List.<JCStatement>nil(), make().Type(syms().objectType), expression, test);
}
use of org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCExpression in project ceylon by eclipse.
the class ExpressionTransformer method applyErasureAndBoxing.
JCExpression applyErasureAndBoxing(JCExpression result, Type exprType, boolean exprErased, boolean exprBoxed, boolean exprUntrustedType, boolean exprSmall, BoxingStrategy boxingStrategy, Type expectedType, int flags) {
if (exprType != null)
exprType = exprType.resolveAliases();
if (expectedType != null)
expectedType = expectedType.resolveAliases();
boolean canCast = false;
boolean coerced = (flags & EXPR_IS_COERCED) != 0;
if (expectedType != null && // don't cast if we're coercing
!coerced && // don't add cast to an erased type
!willEraseToObject(expectedType)) {
// only try to cast boxed types, no point otherwise
if (exprBoxed) {
boolean expectedTypeIsNotRaw = (flags & EXPR_EXPECTED_TYPE_NOT_RAW) != 0;
boolean expectedTypeHasConstrainedTypeParameters = (flags & EXPR_EXPECTED_TYPE_HAS_CONSTRAINED_TYPE_PARAMETERS) != 0;
boolean expectedTypeHasDependentCovariantTypeParameters = (flags & EXPR_EXPECTED_TYPE_HAS_DEPENDENT_COVARIANT_TYPE_PARAMETERS) != 0;
boolean downCast = (flags & EXPR_DOWN_CAST) != 0;
boolean forceCast = (flags & EXPR_FORCE_CAST) != 0;
int companionFlags = (flags & EXPR_WANTS_COMPANION) != 0 ? AbstractTransformer.JT_COMPANION : 0;
// special case for returning Null expressions
if (isNull(exprType)) {
// don't add cast for null
if (!isNullValue(exprType) || // temp vars whose type erase to Object
(flags & EXPR_IS_NOT_BASE_MEMBER) != 0 || // of different types using the "of" operator
downCast || // also add casts if we really want them
forceCast) {
// in some cases we may have an instance of Null, which is of type java.lang.Object, being
// returned in a context where we expect a String? (aka ceylon.language.String) so even though
// the instance at hand will really be null, we need a up-cast to it
JCExpression targetType = makeJavaType(expectedType, AbstractTransformer.JT_RAW | companionFlags);
result = make().TypeCast(targetType, result);
}
} else if (exprType.isExactlyNothing()) {
// type param erasure
JCExpression targetType = makeJavaType(expectedType, AbstractTransformer.JT_NO_PRIMITIVES | companionFlags);
result = make().TypeCast(make().QualIdent(syms().objectType.tsym), result);
result = make().TypeCast(targetType, result);
} else if (// expression was forcibly erased
exprErased || // we want to cast
forceCast || // bounds that are different from what we think the expression type should be
exprUntrustedType || // see https://github.com/ceylon/ceylon-compiler/issues/1557
expectedTypeHasDependentCovariantTypeParameters || // some type parameter somewhere needs a cast
needsCast(exprType, expectedType, expectedTypeIsNotRaw, expectedTypeHasConstrainedTypeParameters, downCast) || // if the exprType is raw and the expected type isn't
(exprType.isRaw() && (expectedTypeIsNotRaw || !isTurnedToRaw(expectedType)))) {
// save this before we simplify it because we lose that flag doing so
boolean exprIsRaw = exprType.isRaw();
boolean expectedTypeIsRaw = isTurnedToRaw(expectedType) && !expectedTypeIsNotRaw;
// (unless the other type is already raw)
if ((!exprIsRaw && hasTypeParameters(expectedType)) || (downCast && !expectedTypeIsRaw && hasTypeParameters(exprType))) {
Type rawType = hasTypeParameters(expectedType) ? expectedType : exprType;
JCExpression rawTypeExpr = makeJavaType(rawType, AbstractTransformer.JT_TYPE_ARGUMENT | AbstractTransformer.JT_RAW | companionFlags);
result = make().TypeCast(rawTypeExpr, result);
// expr is now raw
exprIsRaw = true;
// let's not add another downcast if we got a cast: one is enough
downCast = false;
// same for forced erasure
exprErased = false;
exprUntrustedType = false;
}
// simplify the type
// (without the underlying type, because the cast is always to a non-primitive)
boolean wasOptional = isOptional(expectedType);
exprType = simplifyType(expectedType).withoutUnderlyingType();
// if the expected type was optional, respect that otherwise it fubars boxing
if (wasOptional) {
exprType = typeFact().getOptionalType(exprType);
}
// if the expr is not raw, we need a cast
// if the expr is raw:
// don't even try making an actual cast if there are bounded type parameters in play, because going raw is much safer
// also don't try making the cast if the expected type is raw because anything goes
boolean needsTypedCast = !exprIsRaw || (!expectedTypeHasConstrainedTypeParameters && !expectedTypeHasDependentCovariantTypeParameters && !expectedTypeIsRaw);
if (needsTypedCast || // make sure that downcasts get at least one cast
downCast || // same for forced erasure
exprUntrustedType) {
// it figures out that there's no intersection between the two types, but we know better
if (exprUntrustedType && !exprIsRaw) {
result = make().TypeCast(syms().objectType, result);
}
// Do the actual cast
JCExpression targetType = makeJavaType(expectedType, AbstractTransformer.JT_TYPE_ARGUMENT | companionFlags);
result = make().TypeCast(targetType, result);
}
} else
canCast = true;
} else
canCast = true;
}
// If expr type if Self<T> and expected type is T we need to cast before any unboxing
if (exprType.getDeclaration().getSelfType() != null && expectedType != null && expectedType.isExactly(exprType.getTypeArguments().get(exprType.getDeclaration().getSelfType().getDeclaration()))) {
result = applySelfTypeCasts(result, exprType, exprBoxed, BoxingStrategy.BOXED, expectedType);
exprType = expectedType;
}
// we must do the boxing after the cast to the proper type
JCExpression ret = boxUnboxIfNecessary(result, exprBoxed ? BoxingStrategy.BOXED : BoxingStrategy.UNBOXED, exprType, boxingStrategy, expectedType);
// very special case for nothing that we need to "unbox" to a primitive type
if (exprType != null && exprType.isExactlyNothing() && boxingStrategy == BoxingStrategy.UNBOXED) {
// in this case we have to use the expected type
ret = unboxType(ret, expectedType);
}
// now check if we need variance casts
if (canCast) {
ret = applyVarianceCasts(ret, exprType, exprBoxed, boxingStrategy, expectedType, flags);
}
ret = applySelfTypeCasts(ret, exprType, exprBoxed, boxingStrategy, expectedType);
ret = applyJavaTypeConversions(ret, exprType, expectedType, boxingStrategy, exprBoxed, exprSmall, flags);
// _after_ we reset it in transformExpression()
if (coerced)
ret = applyJavaCoercions(ret, exprType, expectedType);
return ret;
}
use of org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCExpression in project ceylon by eclipse.
the class ExpressionTransformer method transform.
public JCTree transform(Tree.ObjectExpression expr) {
at(expr);
List<JCTree> klass = classGen().transformObjectExpression(expr);
at(expr);
JCExpression newCall = make().NewClass(null, null, makeUnquotedIdent(Naming.escapeClassName(expr.getAnonymousClass().getName()) + "_"), List.<JCTree.JCExpression>nil(), null);
return make().LetExpr((List) klass, newCall);
}
use of org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCExpression in project ceylon by eclipse.
the class ExpressionTransformer method transform.
// Postfix operator
public JCExpression transform(Tree.PostfixOperatorExpression expr) {
OperatorTranslation operator = Operators.getOperator(expr.getClass());
if (operator == null) {
return makeErroneous(expr, "compiler bug " + expr.getNodeType() + " is not yet supported");
}
OptimisationStrategy optimisationStrategy = operator.getUnOpOptimisationStrategy(expr, expr.getTerm(), this);
boolean canOptimise = optimisationStrategy.useJavaOperator();
// only fully optimise if we don't have to access the getter/setter
if (canOptimise && CodegenUtil.isDirectAccessVariable(expr.getTerm())) {
JCExpression term = transformExpression(expr.getTerm(), BoxingStrategy.UNBOXED, expr.getTypeModel(), EXPR_WIDEN_PRIM);
return at(expr).Unary(operator.javacOperator, term);
}
Tree.Term term = unwrapExpressionUntilTerm(expr.getTerm());
Type returnType = term.getTypeModel();
List<JCVariableDecl> decls = List.nil();
List<JCStatement> stats = List.nil();
JCExpression result = null;
// we can optimise that case a bit sometimes
boolean boxResult = !canOptimise;
// (let $tmp = attr; attr = $tmp.getSuccessor(); $tmp;)
if (term instanceof Tree.BaseMemberExpression || // special case for java statics Foo.attr where Foo does not need to be evaluated
(term instanceof Tree.QualifiedMemberExpression && ((Tree.QualifiedMemberExpression) term).getStaticMethodReference())) {
JCExpression getter;
if (term instanceof Tree.BaseMemberExpression)
getter = transform((Tree.BaseMemberExpression) term, null);
else
getter = transformMemberExpression((Tree.QualifiedMemberExpression) term, null, null);
at(expr);
// Type $tmp = attr
JCExpression exprType = makeJavaType(returnType, boxResult ? JT_NO_PRIMITIVES : 0);
Name varName = naming.tempName("op");
// make sure we box the results if necessary
getter = applyErasureAndBoxing(getter, term, boxResult ? BoxingStrategy.BOXED : BoxingStrategy.UNBOXED, returnType);
JCVariableDecl tmpVar = make().VarDef(make().Modifiers(0), varName, exprType, getter);
decls = decls.prepend(tmpVar);
// attr = $tmp.getSuccessor()
JCExpression successor;
if (canOptimise) {
// use +1/-1 if we can optimise a bit
successor = make().Binary(operator == OperatorTranslation.UNARY_POSTFIX_INCREMENT ? JCTree.Tag.PLUS : JCTree.Tag.MINUS, make().Ident(varName), makeInteger(1));
successor = unAutoPromote(successor, returnType, expr.getSmall());
} else {
successor = make().Apply(null, makeSelect(make().Ident(varName), operator.getCeylonMethodName()), List.<JCExpression>nil());
// make sure the result is boxed if necessary, the result of successor/predecessor is always boxed
successor = boxUnboxIfNecessary(successor, true, term.getTypeModel(), CodegenUtil.getBoxingStrategy(term));
}
JCExpression assignment = makeAssignment(expr, term, transformAssignmentLhs(expr, term), successor);
stats = stats.prepend(at(expr).Exec(assignment));
// $tmp
result = make().Ident(varName);
} else if (term instanceof Tree.QualifiedMemberExpression) {
// e.attr++
// (let $tmpE = e, $tmpV = $tmpE.attr; $tmpE.attr = $tmpV.getSuccessor(); $tmpV;)
Tree.QualifiedMemberExpression qualified = (Tree.QualifiedMemberExpression) term;
boolean isSuper = isSuperOrSuperOf(qualified.getPrimary());
boolean isPackage = isPackageQualified(qualified);
// transform the primary, this will get us a boxed primary
JCExpression e = transformQualifiedMemberPrimary(qualified);
at(expr);
// Type $tmpE = e
JCExpression exprType = makeJavaType(qualified.getTarget().getQualifyingType(), JT_NO_PRIMITIVES);
Name varEName = naming.tempName("opE");
JCVariableDecl tmpEVar = make().VarDef(make().Modifiers(0), varEName, exprType, e);
// Type $tmpV = $tmpE.attr
JCExpression attrType = makeJavaType(returnType, boxResult ? JT_NO_PRIMITIVES : 0);
Name varVName = naming.tempName("opV");
JCExpression getter;
if (isSuper) {
getter = transformMemberExpression(qualified, transformSuper(qualified), null);
} else if (isPackage) {
getter = transformMemberExpression(qualified, null, null);
} else {
getter = transformMemberExpression(qualified, make().Ident(varEName), null);
}
// make sure we box the results if necessary
getter = applyErasureAndBoxing(getter, term, boxResult ? BoxingStrategy.BOXED : BoxingStrategy.UNBOXED, returnType);
JCVariableDecl tmpVVar = make().VarDef(make().Modifiers(0), varVName, attrType, getter);
decls = decls.prepend(tmpVVar);
if (!isSuper && !isPackage) {
// define all the variables
decls = decls.prepend(tmpEVar);
}
// $tmpE.attr = $tmpV.getSuccessor()
JCExpression successor;
if (canOptimise) {
// use +1/-1 if we can optimise a bit
successor = make().Binary(operator == OperatorTranslation.UNARY_POSTFIX_INCREMENT ? JCTree.Tag.PLUS : JCTree.Tag.MINUS, make().Ident(varVName), makeInteger(1));
successor = unAutoPromote(successor, returnType, expr.getSmall());
} else {
successor = make().Apply(null, makeSelect(make().Ident(varVName), operator.getCeylonMethodName()), List.<JCExpression>nil());
// make sure the result is boxed if necessary, the result of successor/predecessor is always boxed
successor = boxUnboxIfNecessary(successor, true, term.getTypeModel(), CodegenUtil.getBoxingStrategy(term));
}
JCExpression assignment = makeAssignment(expr, term, qualifyLhs(expr, term, isSuper ? transformSuper(qualified) : make().Ident(varEName)), successor);
stats = stats.prepend(at(expr).Exec(assignment));
// $tmpV
result = make().Ident(varVName);
} else {
return makeErroneous(term, "compiler bug: " + term.getNodeType() + " is not supported yet");
}
return make().LetExpr(decls, stats, result);
}
use of org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCExpression in project ceylon by eclipse.
the class ExpressionTransformer method comprehensionAsSequential.
public JCExpression comprehensionAsSequential(Tree.Comprehension comprehension, Type expectedType) {
JCExpression sequential = iterableToSequential(transformComprehension(comprehension));
Type elementType = comprehension.getInitialComprehensionClause().getTypeModel();
Type sequentialType = typeFact().getSequentialType(elementType);
return sequentialEmptiness(sequential, expectedType, sequentialType);
}
Aggregations