use of com.sun.tools.javac.tree.JCTree.JCExpression in project ceylon-compiler by ceylon.
the class AbstractTransformer method makeVariableBoxType.
/**
* Creates a {@code VariableBox<T>}, {@code VariableBoxBoolean},
* {@code VariableBoxLong} etc depending on the given declaration model.
*/
private JCExpression makeVariableBoxType(TypedDeclaration declarationModel) {
JCExpression boxClass;
boolean unboxed = CodegenUtil.isUnBoxed(declarationModel);
if (unboxed && isCeylonBoolean(declarationModel.getType())) {
boxClass = make().Type(syms().ceylonVariableBoxBooleanType);
} else if (unboxed && isCeylonInteger(declarationModel.getType())) {
boxClass = make().Type(syms().ceylonVariableBoxLongType);
} else if (unboxed && isCeylonFloat(declarationModel.getType())) {
boxClass = make().Type(syms().ceylonVariableBoxDoubleType);
} else if (unboxed && isCeylonCharacter(declarationModel.getType())) {
boxClass = make().Type(syms().ceylonVariableBoxIntType);
} else if (unboxed && isCeylonByte(declarationModel.getType())) {
boxClass = make().Type(syms().ceylonVariableBoxByteType);
} else {
boxClass = make().Ident(syms().ceylonVariableBoxType.tsym);
int flags = unboxed ? 0 : JT_TYPE_ARGUMENT;
boxClass = make().TypeApply(boxClass, List.<JCExpression>of(makeJavaType(declarationModel.getType(), flags)));
}
return boxClass;
}
use of com.sun.tools.javac.tree.JCTree.JCExpression in project ceylon-compiler by ceylon.
the class AbstractTransformer method makeAtContainer.
List<JCAnnotation> makeAtContainer(Type type) {
JCExpression classAttribute = make().Assign(naming.makeUnquotedIdent("klass"), makeClassLiteral(type));
List<JCExpression> attributes = List.of(classAttribute);
return makeModelAnnotation(syms().ceylonAtContainerType, attributes);
}
use of com.sun.tools.javac.tree.JCTree.JCExpression in project ceylon-compiler by ceylon.
the class AbstractTransformer method makeTypeArgs.
private ListBuffer<JCExpression> makeTypeArgs(boolean isCeylonCallable, int flags, Map<TypeParameter, Type> tas, java.util.List<TypeParameter> tps, Type simpleType) {
ListBuffer<JCExpression> typeArgs = new ListBuffer<JCExpression>();
for (TypeParameter tp : tps) {
Type ta = tas.get(tp);
// error handling
if (ta == null)
continue;
boolean isDependedOn = hasDependentTypeParameters(tps, tp);
// record whether we were initially working with Anything, because getNonNullType turns it into Object
// and we need to treat "in Anything" specially below
boolean isAnything = isAnything(ta);
// we want, so we make sure it's not Null
if (isOptional(ta) && !isNull(ta)) {
// For an optional type T?:
// - The Ceylon type Foo<T?> results in the Java type Foo<T>.
ta = getNonNullType(ta);
}
// In a type argument Foo<X&Object> or Foo<X?> transform to just Foo<X>
ta = simplifyType(ta);
if (typeFact().isUnion(ta) || typeFact().isIntersection(ta)) {
// conform with where raw types would be used between expressions and constructors
if (((flags & (JT_EXTENDS | JT_SATISFIES)) != 0 && tp.getSelfTypedDeclaration() != null)) {
// A bit ugly, but we need to escape from the loop and create a raw type, no generics
if ((flags & (JT_EXTENDS | JT_SATISFIES)) != 0)
throw new BugException("rawSupertype() should prevent this method going raw when JT_EXTENDS | JT_SATISFIES");
typeArgs = null;
break;
} else if ((flags & (__JT_FULL_TYPE | JT_EXTENDS | JT_SATISFIES)) == 0) {
if ((flags & (JT_EXTENDS | JT_SATISFIES)) != 0)
throw new BugException("rawSupertype() should prevent this method going raw when JT_EXTENDS | JT_SATISFIES");
typeArgs = null;
break;
}
// otherwise just go on
}
if (isCeylonBoolean(ta) && !isTypeParameter(ta)) {
ta = typeFact.getBooleanType();
}
JCExpression jta;
if (!tp.getSatisfiedTypes().isEmpty()) {
boolean needsCastForBounds = false;
for (Type bound : tp.getSatisfiedTypes()) {
bound = bound.substitute(tas, null);
needsCastForBounds |= expressionGen().needsCast(ta, bound, false, false, false);
}
if (needsCastForBounds) {
// replace with the first bound
ta = tp.getSatisfiedTypes().get(0).substitute(tas, null);
if (tp.getSatisfiedTypes().size() > 1 || isBoundsSelfDependant(tp) || willEraseToObject(ta) || // we should reject it for all non-covariant types, unless we're in satisfies/extends
((flags & (JT_SATISFIES | JT_EXTENDS)) == 0 && !simpleType.isCovariant(tp))) {
if ((flags & (JT_EXTENDS | JT_SATISFIES)) != 0)
throw new BugException("rawSupertype() should prevent this method going raw when JT_EXTENDS | JT_SATISFIES");
// A bit ugly, but we need to escape from the loop and create a raw type, no generics
typeArgs = null;
break;
}
}
}
if (ta.isExactlyNothing() || // use the same erasure rules as bottom: prefer wildcards
((flags & (__JT_FULL_TYPE | JT_EXTENDS | JT_SATISFIES)) != 0 && (typeFact().isUnion(ta) || typeFact().isIntersection(ta)))) {
// For the bottom type Bottom:
if ((flags & (JT_CLASS_NEW)) != 0) {
// A bit ugly, but we need to escape from the loop and create a raw type, no generics
if ((flags & (JT_EXTENDS | JT_SATISFIES)) != 0)
throw new BugException("rawSupertype() should prevent this method going raw when JT_EXTENDS | JT_SATISFIES");
typeArgs = null;
break;
} else {
// Foo<Object> (see https://github.com/ceylon/ceylon-compiler/issues/633 for why)
if ((flags & (JT_SATISFIES | JT_EXTENDS)) != 0) {
if (ta.isExactlyNothing()) {
jta = make().Type(syms().objectType);
} else {
if (!tp.getSatisfiedTypes().isEmpty()) {
// union or intersection: Use the common upper bound of the types
jta = makeJavaType(tp.getSatisfiedTypes().get(0), JT_TYPE_ARGUMENT);
} else {
jta = make().Type(syms().objectType);
}
}
} else if (ta.isExactlyNothing()) {
// see https://github.com/ceylon/ceylon-compiler/issues/1003
if (simpleType.isContravariant(tp)) {
typeArgs = null;
break;
} else if (tp.isCovariant() && !isDependedOn) {
// DO NOT trust use-site covariance for Nothing, because we consider "out Nothing" to be the same
// as "Nothing". Only look at declaration-site covariance
jta = make().Wildcard(make().TypeBoundKind(BoundKind.EXTENDS), make().Type(syms().objectType));
} else {
jta = make().Type(syms().objectType);
}
} else {
// - Foo<? super T> if Foo is contravariant in T
if (((flags & JT_CLASS_NEW) == 0) && simpleType.isContravariant(tp)) {
jta = make().Wildcard(make().TypeBoundKind(BoundKind.SUPER), makeJavaType(ta, JT_TYPE_ARGUMENT));
} else if (((flags & JT_CLASS_NEW) == 0) && simpleType.isCovariant(tp) && !isDependedOn) {
jta = make().Wildcard(make().TypeBoundKind(BoundKind.EXTENDS), makeJavaType(ta, JT_TYPE_ARGUMENT));
} else {
jta = makeJavaType(ta, JT_TYPE_ARGUMENT);
}
}
}
} else {
// For an ordinary class or interface type T:
if ((flags & (JT_SATISFIES | JT_EXTENDS)) != 0) {
// - The Ceylon type Foo<T> appearing in an extends or satisfies clause
// results in the Java type Foo<T>
jta = makeJavaType(ta, JT_TYPE_ARGUMENT);
} else {
// - Foo<? super T> if Foo is contravariant in T
if (((flags & JT_CLASS_NEW) == 0) && simpleType.isContravariant(tp) && (!isAnything || tp.isContravariant())) {
// DO NOT trust use-site contravariance for Anything, because we consider "in Anything" to be the same
// as "Anything". Only look at declaration-site contravariance
jta = make().Wildcard(make().TypeBoundKind(BoundKind.SUPER), makeJavaType(ta, JT_TYPE_ARGUMENT));
} else if (((flags & JT_CLASS_NEW) == 0) && simpleType.isCovariant(tp) && !isDependedOn) {
jta = make().Wildcard(make().TypeBoundKind(BoundKind.EXTENDS), makeJavaType(ta, JT_TYPE_ARGUMENT));
} else {
jta = makeJavaType(ta, JT_TYPE_ARGUMENT);
}
}
}
typeArgs.add(jta);
if (isCeylonCallable) {
// In the runtime Callable only has a single type param
break;
}
}
return typeArgs;
}
use of com.sun.tools.javac.tree.JCTree.JCExpression in project ceylon-compiler by ceylon.
the class AbstractTransformer method makeLazyIterable.
/**
* Makes a lazy iterable literal, for a sequenced argument to a named invocation
* (<code>f{foo=""; expr1, expr2, *expr3}</code>) or
* for an iterable instantiation (<code>{expr1, expr2, *expr3}</code>)
*/
JCExpression makeLazyIterable(Tree.SequencedArgument sequencedArgument, Type seqElemType, Type absentType, int flags) {
java.util.List<PositionalArgument> list = sequencedArgument.getPositionalArguments();
int i = 0;
ListBuffer<JCStatement> returns = new ListBuffer<JCStatement>();
boolean spread = false;
boolean old = expressionGen().withinSyntheticClassBody(true);
try {
for (Tree.PositionalArgument arg : list) {
at(arg);
JCExpression jcExpression;
// last expression can be an Iterable<seqElemType>
if (arg instanceof Tree.SpreadArgument || arg instanceof Tree.Comprehension) {
// make sure we only have spread/comprehension as last
if (i != list.size() - 1) {
jcExpression = makeErroneous(arg, "compiler bug: spread or comprehension argument is not last in sequence literal");
} else {
Type type = typeFact().getIterableType(seqElemType);
spread = true;
if (arg instanceof Tree.SpreadArgument) {
Tree.Expression expr = ((Tree.SpreadArgument) arg).getExpression();
// always boxed since it is a sequence
jcExpression = expressionGen().transformExpression(expr, BoxingStrategy.BOXED, type);
} else {
jcExpression = expressionGen().transformComprehension((Comprehension) arg, type);
}
}
} else if (arg instanceof Tree.ListedArgument) {
Tree.Expression expr = ((Tree.ListedArgument) arg).getExpression();
// always boxed since we stuff them into a sequence
jcExpression = expressionGen().transformExpression(expr, BoxingStrategy.BOXED, seqElemType);
} else {
jcExpression = makeErroneous(arg, "compiler bug: " + arg.getNodeType() + " is not a supported sequenced argument");
}
at(arg);
// the last iterable goes first if spread
returns.add(make().Return(jcExpression));
i++;
}
at(sequencedArgument);
if (Strategy.preferLazySwitchingIterable(sequencedArgument.getPositionalArguments())) {
// use a LazySwitchingIterable
MethodDefinitionBuilder mdb = MethodDefinitionBuilder.systemMethod(this, Unfix.$evaluate$.toString());
mdb.isOverride(true);
mdb.modifiers(PROTECTED | FINAL);
mdb.resultType(null, make().Type(syms().objectType));
mdb.parameter(ParameterDefinitionBuilder.systemParameter(this, Unfix.$index$.toString()).type(make().Type(syms().intType), null));
JCSwitch swtch;
try (SavedPosition sp = noPosition()) {
ListBuffer<JCCase> cases = ListBuffer.<JCCase>lb();
i = 0;
for (JCStatement e : returns) {
cases.add(make().Case(make().Literal(i++), List.<JCStatement>of(e)));
}
cases.add(make().Case(null, List.<JCStatement>of(make().Return(makeNull()))));
swtch = make().Switch(naming.makeUnquotedIdent(Unfix.$index$), cases.toList());
}
mdb.body(swtch);
return make().NewClass(null, //of(makeJavaType(seqElemType), makeJavaType(absentType)),
List.<JCExpression>nil(), make().TypeApply(make().QualIdent(syms.ceylonLazyIterableType.tsym), List.<JCExpression>of(makeJavaType(seqElemType, JT_TYPE_ARGUMENT), makeJavaType(absentType, JT_TYPE_ARGUMENT))), // td,
List.of(// td,
makeReifiedTypeArgument(seqElemType), //td
makeReifiedTypeArgument(absentType), // numMethods
make().Literal(list.size()), // spread),
make().Literal(spread)), make().AnonymousClassDef(make().Modifiers(FINAL), List.<JCTree>of(mdb.build())));
} else {
// use a LazyInvokingIterable
ListBuffer<JCTree> methods = new ListBuffer<JCTree>();
MethodDefinitionBuilder mdb = MethodDefinitionBuilder.systemMethod(this, Unfix.$lookup$.toString());
mdb.isOverride(true);
mdb.modifiers(PROTECTED | FINAL);
mdb.resultType(null, naming.makeQualIdent(make().Type(syms().methodHandlesType), "Lookup"));
mdb.body(make().Return(make().Apply(List.<JCExpression>nil(), naming.makeQualIdent(make().Type(syms().methodHandlesType), "lookup"), List.<JCExpression>nil())));
methods.add(mdb.build());
mdb = MethodDefinitionBuilder.systemMethod(this, Unfix.$invoke$.toString());
mdb.isOverride(true);
mdb.modifiers(PROTECTED | FINAL);
mdb.resultType(null, make().Type(syms().objectType));
mdb.parameter(ParameterDefinitionBuilder.systemParameter(this, "handle").type(make().Type(syms().methodHandleType), null));
mdb.body(make().Return(make().Apply(List.<JCExpression>nil(), naming.makeQualIdent(naming.makeUnquotedIdent("handle"), "invokeExact"), List.<JCExpression>of(naming.makeThis()))));
methods.add(mdb.build());
i = 0;
for (JCStatement expr : returns) {
mdb = MethodDefinitionBuilder.systemMethod(this, "$" + i);
i++;
mdb.modifiers(PRIVATE | FINAL);
mdb.resultType(null, make().Type(syms().objectType));
mdb.body(expr);
methods.add(mdb.build());
}
return make().NewClass(null, //of(makeJavaType(seqElemType), makeJavaType(absentType)),
List.<JCExpression>nil(), make().TypeApply(make().QualIdent(syms.ceylonLazyInvokingIterableType.tsym), List.<JCExpression>of(makeJavaType(seqElemType, JT_TYPE_ARGUMENT), makeJavaType(absentType, JT_TYPE_ARGUMENT))), // td,
List.of(// td,
makeReifiedTypeArgument(seqElemType), //td
makeReifiedTypeArgument(absentType), // numMethods
make().Literal(list.size()), // spread),
make().Literal(spread)), make().AnonymousClassDef(make().Modifiers(FINAL), methods.toList()));
}
} finally {
expressionGen().withinSyntheticClassBody(old);
}
}
use of com.sun.tools.javac.tree.JCTree.JCExpression in project ceylon-compiler by ceylon.
the class CallBuilder method build.
public JCExpression build() {
if (built) {
throw new BugException("already built");
}
built = true;
JCExpression result;
List<JCExpression> arguments;
final JCExpression newEncl;
if ((cbOpts & CB_ALIAS_ARGS) != 0) {
if (instantiateQualfier != null && instantiateQualfier.expression != null) {
if (instantiateQualfier.type == null) {
throw new BugException(MISSING_TYPE);
}
SyntheticName qualName = getQualifierName(basename);
appendStatement(gen.makeVar(Flags.FINAL, qualName, instantiateQualfier.type, instantiateQualfier.expression));
newEncl = qualName.makeIdent();
} else {
newEncl = null;
}
arguments = List.<JCExpression>nil();
int argumentNum = 0;
for (ExpressionAndType argumentAndType : argumentsAndTypes) {
SyntheticName name = getArgumentName(basename, argumentNum);
if (argumentAndType.type == null) {
throw new BugException(MISSING_TYPE);
}
if ((cbOpts & CB_ALIAS_ARGS) != 0) {
appendStatement(gen.makeVar(Flags.FINAL, name, argumentAndType.type, argumentAndType.expression));
}
arguments = arguments.append(name.makeIdent());
argumentNum++;
}
} else {
newEncl = this.instantiateQualfier != null ? this.instantiateQualfier.expression : null;
arguments = ExpressionAndType.toExpressionList(this.argumentsAndTypes);
}
if (haveLocation) {
gen.at(this.location);
}
switch(kind) {
case APPLY:
result = gen.make().Apply(this.typeargs.toList(), this.methodOrClass, arguments);
break;
case NEW:
result = gen.make().NewClass(newEncl, null, this.methodOrClass, arguments, classDefs);
break;
case ARRAY_READ:
result = gen.make().Indexed(this.methodOrClass, arguments.head);
break;
case ARRAY_WRITE:
{
JCExpression array;
if (arrayWriteNeedsCast)
array = gen.make().TypeCast(gen.make().TypeArray(gen.make().Type(gen.syms().objectType)), this.methodOrClass);
else
array = this.methodOrClass;
result = gen.make().Assign(gen.make().Indexed(array, arguments.head), arguments.tail.head);
}
break;
case NEW_ARRAY:
// methodOrClass must be a ArrayType, so we get the element type out
JCExpression elementTypeExpr = ((JCTree.JCArrayTypeTree) this.methodOrClass).elemtype;
if (arrayInstanceReifiedType == null) {
result = gen.make().NewArray(elementTypeExpr, List.of(arguments.head), null);
if (arrayInstanceCast != null) {
result = gen.make().TypeCast(arrayInstanceCast, result);
}
} else {
List<JCExpression> dimensions = List.nil();
if (arrayInstanceDimensions > 1) {
for (int i = 1; i < arrayInstanceDimensions; i++) {
dimensions = dimensions.prepend(gen.makeInteger(0));
}
}
dimensions = dimensions.prepend(arguments.head);
dimensions = dimensions.prepend(arrayInstanceReifiedType);
result = gen.utilInvocation().makeArray(dimensions);
}
if (arguments.tail.nonEmpty()) {
// must fill it
result = gen.utilInvocation().fillArray(List.of(result, arguments.tail.head));
}
break;
case FIELD_READ:
result = this.methodOrClass;
break;
default:
throw BugException.unhandledEnumCase(kind);
}
if ((cbOpts & CB_LET) != 0) {
if (voidMethod) {
result = gen.make().LetExpr(statements.toList().append(gen.make().Exec(result)), gen.makeNull());
} else if (!statements.isEmpty()) {
result = gen.make().LetExpr(statements.toList(), result);
}
}
return result;
}
Aggregations