use of org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCExpression in project ceylon by eclipse.
the class ExpressionTransformer method transformExpression.
JCExpression transformExpression(final Tree.Term expr, BoxingStrategy boxingStrategy, Type expectedType, int flags) {
if (expr == null) {
return null;
}
at(expr);
if (inStatement && boxingStrategy != BoxingStrategy.INDIFFERENT) {
// We're not directly inside the ExpressionStatement anymore
inStatement = false;
}
// Cope with things like ((expr))
// FIXME: shouldn't that be in the visitor?
Tree.Term term = expr;
while (term instanceof Tree.Expression) {
term = ((Tree.Expression) term).getTerm();
}
JCExpression result;
if (term instanceof Tree.IfExpression) {
flags |= EXPR_IS_NOT_BASE_MEMBER;
}
CeylonVisitor v = gen().visitor;
final ListBuffer<JCTree> prevDefs = v.defs;
final boolean prevInInitializer = v.inInitializer;
final ClassDefinitionBuilder prevClassBuilder = v.classBuilder;
final Type prevExpectedType = this.expectedType;
final boolean prevCoerced = this.coerced;
try {
v.defs = new ListBuffer<JCTree>();
v.inInitializer = false;
v.classBuilder = gen().current();
this.expectedType = expectedType;
this.coerced = (flags & EXPR_IS_COERCED) != 0;
term.visit(v);
if (v.hasResult()) {
result = v.getSingleResult();
if (result == null) {
throw new BugException(term, "visitor yielded multiple results");
}
} else {
throw new BugException(term, "visitor didn't yield any result");
}
} catch (BugException e) {
result = e.makeErroneous(this, expr);
} finally {
v.classBuilder = prevClassBuilder;
v.inInitializer = prevInInitializer;
v.defs = prevDefs;
this.coerced = prevCoerced;
this.expectedType = prevExpectedType;
}
if ((flags & EXPR_TARGET_ACCEPTS_NULL) == 0 && expectedType != null && hasUncheckedNulls(expr) && expectedType.isSubtypeOf(typeFact().getObjectType()) && !knownNullSafe(term)) {
result = utilInvocation().checkNull(result);
flags |= EXPR_HAS_NULL_CHECK_FENCE;
}
result = applyErasureAndBoxing(result, expr, boxingStrategy, expectedType, flags);
return result;
}
use of org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCExpression in project ceylon by eclipse.
the class ExpressionTransformer method transformInvocation.
private JCExpression transformInvocation(Invocation invocation, CallBuilder callBuilder, TransformedInvocationPrimary transformedPrimary) {
invocation.location(callBuilder);
boolean needsCast = false;
if (Decl.isConstructorPrimary(invocation.getPrimary())) {
Tree.StaticMemberOrTypeExpression qte = (Tree.StaticMemberOrTypeExpression) invocation.getPrimary();
// instantiator
Constructor ctor = ModelUtil.getConstructor(qte.getDeclaration());
if (Strategy.generateInstantiator(ctor)) {
needsCast = Strategy.isInstantiatorUntyped(ctor);
if (qte instanceof Tree.QualifiedMemberExpression && ((Tree.QualifiedMemberExpression) qte).getPrimary() instanceof Tree.QualifiedTypeExpression && isCeylonCallable(getReturnTypeOfCallable(invocation.getPrimary().getTypeModel()))) {
callBuilder.invoke(naming.makeQualIdent(transformedPrimary.expr, "$call$"));
} else {
callBuilder.typeArguments(List.<JCExpression>nil());
java.util.List<Type> typeModels = qte.getTypeArguments().getTypeModels();
if (typeModels != null) {
for (Type tm : typeModels) {
callBuilder.typeArgument(makeJavaType(tm, AbstractTransformer.JT_TYPE_ARGUMENT));
}
}
callBuilder.invoke(naming.makeInstantiatorMethodName(transformedPrimary.expr, ModelUtil.getConstructedClass(ctor)));
}
} else if (typeFact().isJavaArrayType(ModelUtil.getConstructedClass(ctor).getType())) {
callBuilder.arrayWith(invocation.getReturnType().getQualifyingType(), makeJavaType(invocation.getReturnType(), JT_CLASS_NEW));
} else {
if (ModelUtil.getConstructedClass(invocation.getPrimaryDeclaration()).isMember() && invocation.getPrimary() instanceof Tree.QualifiedMemberOrTypeExpression && !(((Tree.QualifiedMemberOrTypeExpression) invocation.getPrimary()).getPrimary() instanceof Tree.BaseTypeExpression)) {
callBuilder.instantiate(new ExpressionAndType(transformedPrimary.expr, null), makeJavaType(invocation.getReturnType(), JT_CLASS_NEW | (transformedPrimary.expr == null ? 0 : JT_NON_QUALIFIED)));
} else {
callBuilder.instantiate(makeJavaType(invocation.getReturnType(), JT_CLASS_NEW));
}
}
} else if (invocation.getQmePrimary() != null && isJavaArray(invocation.getQmePrimary().getTypeModel()) && transformedPrimary.selector != null && (transformedPrimary.selector.equals("get") || transformedPrimary.selector.equals("set"))) {
if (transformedPrimary.selector.equals("get"))
callBuilder.arrayRead(transformedPrimary.expr);
else if (transformedPrimary.selector.equals("set")) {
callBuilder.arrayWrite(transformedPrimary.expr);
Type arrayType = invocation.getQmePrimary().getTypeModel().resolveAliases();
if (isJavaObjectArray(arrayType) && invocation instanceof PositionalInvocation) {
Type elementType = arrayType.getTypeArgumentList().get(0);
Type argumentType = ((PositionalInvocation) invocation).getArgumentType(1);
if (!argumentType.isSubtypeOf(typeFact().getOptionalType(elementType)))
callBuilder.javaArrayWriteNeedsCast(true);
}
} else
return makeErroneous(invocation.getNode(), "compiler bug: extraneous array selector: " + transformedPrimary.selector);
} else if (invocation.isUnknownArguments()) {
// if we have an unknown parameter list, like Callble<Ret,Args>, need to prepend the callable
// to the argument list, and invoke Util.apply
// note that ATM the typechecker only allows a single argument to be passed in spread form in this
// case so we don't need to look at parameter types
JCExpression callableTypeExpr = makeJavaType(invocation.getPrimary().getTypeModel());
ExpressionAndType callableArg = new ExpressionAndType(transformedPrimary.expr, callableTypeExpr);
Type returnType = invocation.getReturnType();
JCExpression returnTypeExpr = makeJavaType(returnType, JT_NO_PRIMITIVES);
callBuilder.prependArgumentAndType(callableArg);
callBuilder.typeArgument(returnTypeExpr);
callBuilder.invoke(make().Select(make().QualIdent(syms().ceylonUtilType.tsym), names().fromString("apply")));
} else if (invocation.isOnValueType()) {
JCExpression primTypeExpr = makeJavaType(invocation.getQmePrimary().getTypeModel(), JT_NO_PRIMITIVES | JT_VALUE_TYPE);
callBuilder.invoke(naming.makeQuotedQualIdent(primTypeExpr, transformedPrimary.selector));
} else {
callBuilder.invoke(naming.makeQuotedQualIdent(transformedPrimary.expr, transformedPrimary.selector));
}
JCExpression result = callBuilder.build();
if (needsCast) {
result = make().TypeCast(makeJavaType(invocation.getReturnType()), result);
}
return result;
}
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.MemberLiteral expr) {
at(expr);
Declaration declaration = expr.getDeclaration();
if (declaration == null)
return makeErroneous(expr, "compiler bug: missing declaration");
if (declaration.isToplevel()) {
return makeTopLevelValueOrFunctionLiteral(expr);
} else if (expr.getWantsDeclaration()) {
return makeMemberValueOrFunctionDeclarationLiteral(expr, declaration);
} else {
// get its produced ref
Reference producedReference = expr.getTarget();
// it's a member we get from its container type
Type containerType = producedReference.getQualifyingType();
// if we have no container type it means we have an object member
boolean objectMember = containerType.getDeclaration().isAnonymous();
JCExpression memberCall;
if (objectMember) {
// We don't care about the type args for the cast, nor for the reified container expr, because
// we take the real reified container type from the container instance, and that one has the type
// arguments
containerType = ((Class) declaration.getContainer()).getType();
}
JCExpression typeCall = makeTypeLiteralCall(containerType, false, expr.getTypeModel());
// make sure we cast it to ClassOrInterface
String metatypeName;
if (Decl.isConstructor(declaration)) {
Class constructedClass = ModelUtil.getConstructedClass(declaration);
Declaration container = getDeclarationContainer(constructedClass);
if (constructedClass.isToplevel() || container instanceof TypeDeclaration == false) {
metatypeName = "Class";
} else {
metatypeName = "MemberClass";
}
} else {
metatypeName = "ClassOrInterface";
}
TypeDeclaration classOrInterfaceDeclaration = (TypeDeclaration) typeFact().getLanguageModuleModelDeclaration(metatypeName);
JCExpression classOrInterfaceTypeExpr = makeJavaType(classOrInterfaceDeclaration.appliedReference(null, Arrays.asList(containerType)).getType());
typeCall = make().TypeCast(classOrInterfaceTypeExpr, typeCall);
// we will need a TD for the container
// Note that we don't use Basic for the container for object members, because that's not how we represent
// anonymous types.
JCExpression reifiedContainerExpr = makeReifiedTypeArgument(containerType);
// make a raw call and cast
if (Decl.isConstructor(declaration)) {
Type callableType = producedReference.getFullType();
/*JCExpression reifiedArgumentsExpr;
if (Decl.isEnumeratedConstructor(Decl.getConstructor(declaration))) {
reifiedArgumentsExpr = makeReifiedTypeArgument(typeFact().getCallableTuple(callableType.getQualifyingType()));
} else {
reifiedArgumentsExpr = makeReifiedTypeArgument(typeFact().getCallableTuple(callableType));
}*/
JCExpression reifiedArguments;
if (ModelUtil.isEnumeratedConstructor(ModelUtil.getConstructor(declaration))) {
reifiedArguments = makeReifiedTypeArgument(typeFact().getNothingType());
} else {
reifiedArguments = makeReifiedTypeArgument(typeFact().getCallableTuple(callableType));
}
List<JCExpression> arguments = List.of(reifiedArguments, ceylonLiteral(declaration.getName()));
JCExpression classModel = makeSelect(typeCall, "getDeclaredConstructor");
memberCall = make().Apply(null, classModel, arguments);
} else if (declaration instanceof Function) {
// we need to get types for each type argument
JCExpression closedTypesExpr = null;
if (expr.getTypeArgumentList() != null) {
java.util.List<Type> typeModels = expr.getTypeArgumentList().getTypeModels();
if (typeModels != null) {
closedTypesExpr = getClosedTypesSequential(typeModels);
}
}
// we also need type descriptors for ret and args
Type callableType = producedReference.getFullType();
JCExpression reifiedReturnTypeExpr = makeReifiedTypeArgument(typeFact().getCallableReturnType(callableType));
JCExpression reifiedArgumentsExpr = makeReifiedTypeArgument(typeFact().getCallableTuple(callableType));
List<JCExpression> arguments;
if (closedTypesExpr != null)
arguments = List.of(reifiedContainerExpr, reifiedReturnTypeExpr, reifiedArgumentsExpr, ceylonLiteral(declaration.getName()), closedTypesExpr);
else
arguments = List.of(reifiedContainerExpr, reifiedReturnTypeExpr, reifiedArgumentsExpr, ceylonLiteral(declaration.getName()));
memberCall = make().Apply(null, makeSelect(typeCall, "getMethod"), arguments);
} else if (declaration instanceof Value) {
JCExpression reifiedGetExpr = makeReifiedTypeArgument(producedReference.getType());
String getterName = "getAttribute";
Type ptype;
if (!((Value) declaration).isVariable())
ptype = typeFact().getNothingType();
else
ptype = producedReference.getType();
JCExpression reifiedSetExpr = makeReifiedTypeArgument(ptype);
memberCall = make().Apply(null, makeSelect(typeCall, getterName), List.of(reifiedContainerExpr, reifiedGetExpr, reifiedSetExpr, ceylonLiteral(declaration.getName())));
} else {
return makeErroneous(expr, "Unsupported member type: " + declaration);
}
// if(objectMember){
// // now get the instance and bind it
// // I don't think we need any expected type since objects can't be erased
// JCExpression object = transformExpression(expr.getObjectExpression());
// // reset the location after we transformed the expression
// memberCall = at(expr).Apply(null, makeSelect(memberCall, "bind"), List.of(object));
// }
// cast the member call because we invoke it with no Java generics
memberCall = make().TypeCast(makeJavaType(expr.getTypeModel(), JT_RAW | JT_NO_PRIMITIVES), memberCall);
memberCall = make().TypeCast(makeJavaType(expr.getTypeModel(), JT_NO_PRIMITIVES), memberCall);
return memberCall;
}
}
use of org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCExpression in project ceylon by eclipse.
the class ExpressionTransformer method transformOverridableUnaryOperator.
private JCExpression transformOverridableUnaryOperator(Tree.UnaryOperatorExpression op, Type expectedType) {
at(op);
Tree.Term term = op.getTerm();
OperatorTranslation operator = Operators.getOperator(op.getClass());
if (operator == null) {
return makeErroneous(op, "compiler bug: " + op.getClass() + " is an unhandled operator class");
}
JCExpression ret;
if (operator.getUnOpOptimisationStrategy(op, op.getTerm(), this).useJavaOperator()) {
// optimisation for unboxed types
JCExpression expr = transformExpression(term, BoxingStrategy.UNBOXED, expectedType, EXPR_WIDEN_PRIM);
// unary + is essentially a NOOP
if (operator == OperatorTranslation.UNARY_POSITIVE)
return expr;
ret = make().Unary(operator.javacOperator, expr);
ret = unAutoPromote(ret, op.getTypeModel(), op.getSmall());
} else {
if (operator == OperatorTranslation.UNARY_POSITIVE) {
// is the self type of Invertible, so use the type of op
return transformExpression(term, BoxingStrategy.BOXED, op.getTypeModel());
}
ret = make().Apply(null, makeSelect(transformExpression(term, BoxingStrategy.BOXED, expectedType), Naming.getGetterName(operator.getCeylonMethodName())), List.<JCExpression>nil());
}
return ret;
}
use of org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCExpression in project ceylon by eclipse.
the class ExpressionTransformer method transformArgumentsForCallableSpecifier.
private List<ExpressionAndType> transformArgumentsForCallableSpecifier(CallableSpecifierInvocation invocation) {
List<ExpressionAndType> result = List.<ExpressionAndType>nil();
int argIndex = 0;
for (Parameter parameter : invocation.getMethod().getFirstParameterList().getParameters()) {
Type exprType = expressionGen().getTypeForParameter(parameter, null, TP_TO_BOUND);
Parameter declaredParameter = invocation.getMethod().getFirstParameterList().getParameters().get(argIndex);
JCExpression arg = naming.makeName(parameter.getModel(), Naming.NA_IDENT);
arg = expressionGen().applyErasureAndBoxing(arg, exprType, !parameter.getModel().getUnboxed(), // Callables always have boxed params
BoxingStrategy.BOXED, declaredParameter.getType());
result = result.append(new ExpressionAndType(arg, makeJavaType(declaredParameter.getType())));
argIndex++;
}
return result;
}
Aggregations