Permalink
Browse files

Merge branch 'master' of github.com:ceylon/ceylon-compiler

  • Loading branch information...
2 parents 196fd04 + a2074b4 commit 967db3c845f708985859244b8c40818c4006b69d David Festal committed May 25, 2012
Showing with 357 additions and 92 deletions.
  1. +1 −1 bin/java.bat
  2. +0 −19 src/com/redhat/ceylon/compiler/java/codegen/AbstractTransformer.java
  3. +23 −0 src/com/redhat/ceylon/compiler/java/codegen/BoxingVisitor.java
  4. +1 −5 src/com/redhat/ceylon/compiler/java/codegen/CallableBuilder.java
  5. +2 −4 src/com/redhat/ceylon/compiler/java/codegen/CeylonVisitor.java
  6. +85 −15 src/com/redhat/ceylon/compiler/java/codegen/ClassTransformer.java
  7. +1 −2 src/com/redhat/ceylon/compiler/java/codegen/ExpressionTransformer.java
  8. +15 −3 src/com/redhat/ceylon/compiler/java/codegen/InvocationBuilder.java
  9. +23 −8 src/com/redhat/ceylon/compiler/java/codegen/StatementTransformer.java
  10. +4 −0 src/com/redhat/ceylon/compiler/java/util/Decl.java
  11. +2 −8 test-src/com/redhat/ceylon/compiler/java/test/expression/invoke/IndirectTypeParam.src
  12. +0 −2 ...-src/com/redhat/ceylon/compiler/java/test/expression/invoke/MethodArgumentNamedInvocationVoid.src
  13. +2 −2 test-src/com/redhat/ceylon/compiler/java/test/interop/Satisfies.src
  14. +4 −0 test-src/com/redhat/ceylon/compiler/java/test/structure/StructureTest.java
  15. +4 −0 test-src/com/redhat/ceylon/compiler/java/test/structure/StructureTest2.java
  16. +33 −0 test-src/com/redhat/ceylon/compiler/java/test/structure/method/ActualMethodShortcut.ceylon
  17. +46 −0 test-src/com/redhat/ceylon/compiler/java/test/structure/method/ActualMethodShortcut.src
  18. +6 −10 test-src/com/redhat/ceylon/compiler/java/test/structure/method/TwoParamListsTP.src
  19. +8 −13 test-src/com/redhat/ceylon/compiler/java/test/structure/method/TwoParamListsVoid.src
  20. +52 −0 test-src/com/redhat/ceylon/compiler/java/test/structure/type/GenericBottom.ceylon
  21. +45 −0 test-src/com/redhat/ceylon/compiler/java/test/structure/type/GenericBottom.src
View
@@ -29,5 +29,5 @@ if "%JAVA_CURRENT%" == "" (
:: get the javahome
::
FOR /F "usebackq skip=2 tokens=3*" %%A IN (`REG QUERY "%JAVA_CURRENT%" /v JavaHome 2^>nul`) DO (
- set "JAVA_HOME=%%A %%B"
+ set "JAVA_HOME=%%A%%B"
)
@@ -1982,23 +1982,4 @@ private int getPosition(Node node) {
}
return lb.toList();
}
-
- /**
- * Add a {@code return null;} to the given statements.
- *
- * In Java a Ceylon {@code Callable<Void>} is represented as
- * @{code Callable<java.lang.Object>} returning {@code null}. This means
- * we have to add a {@code return null;} statement to the transformed block.
- */
- List<JCStatement> addReturnNull(List<JCStatement> stmts) {
- // just appending 'return null' doesn't work because stmts might
- // contain a return or throw (i.e. definitely return), thus causing
- // an error from javac, so use if(true){...} return null;
- return List.<JCStatement>of(
- make().If(make().Literal(Boolean.TRUE),
- make().Block(0, stmts),
- null),
- make().Return(makeNull()));
-
- }
}
@@ -22,6 +22,7 @@
import com.redhat.ceylon.compiler.java.util.Util;
import com.redhat.ceylon.compiler.typechecker.model.Declaration;
+import com.redhat.ceylon.compiler.typechecker.model.ProducedType;
import com.redhat.ceylon.compiler.typechecker.model.TypedDeclaration;
import com.redhat.ceylon.compiler.typechecker.tree.Tree.ArithmeticAssignmentOp;
import com.redhat.ceylon.compiler.typechecker.tree.Tree.ArithmeticOp;
@@ -49,9 +50,11 @@
import com.redhat.ceylon.compiler.typechecker.tree.Tree.PowerOp;
import com.redhat.ceylon.compiler.typechecker.tree.Tree.PrefixOperatorExpression;
import com.redhat.ceylon.compiler.typechecker.tree.Tree.QualifiedMemberExpression;
+import com.redhat.ceylon.compiler.typechecker.tree.Tree.SpecifierStatement;
import com.redhat.ceylon.compiler.typechecker.tree.Tree.StringLiteral;
import com.redhat.ceylon.compiler.typechecker.tree.Tree.StringTemplate;
import com.redhat.ceylon.compiler.typechecker.tree.Tree.Term;
+import com.redhat.ceylon.compiler.typechecker.tree.Tree;
import com.redhat.ceylon.compiler.typechecker.tree.Visitor;
public class BoxingVisitor extends Visitor {
@@ -190,11 +193,31 @@ public void visit(LogicalOp that) {
// this is not conditional
Util.markUnBoxed(that);
}
+
+ @Override
+ public void visit(SpecifierStatement that) {
+ super.visit(that);
+ underlyingType(that.getBaseMemberExpression());
+ }
@Override
public void visit(AssignOp that) {
super.visit(that);
propagateFromTerm(that, that.getLeftTerm());
+ underlyingType(that.getLeftTerm());
+ }
+
+ private void underlyingType(Tree.Term term) {
+ if (term instanceof Tree.MemberOrTypeExpression) {
+ Tree.MemberOrTypeExpression leftTerm = (Tree.MemberOrTypeExpression)term;
+ TypedDeclaration decl = (TypedDeclaration) leftTerm.getDeclaration();
+ if ("hash".equals(decl.getName())
+ && transformer.typeFact().getObjectDeclaration().equals(decl.getRefinedDeclaration().getContainer())) {
+ ProducedType expectedType = decl.getTypeDeclaration().getType();
+ expectedType.setUnderlyingType("int");
+ leftTerm.setTypeModel(expectedType);
+ }
+ }
}
@Override
@@ -114,11 +114,7 @@ public static CallableBuilder mpl(
body = List.<JCStatement>nil();
}
body = prependVarsForArgs(gen, parameterList, body);
- // We void methods need to have their Callables return null
- // so adjust here.
- if (gen.isVoid(gen.getCallableReturnType(typeModel))) {
- body = gen.addReturnNull(body);
- }
+
cb.body = body;
return cb;
}
@@ -21,6 +21,7 @@
package com.redhat.ceylon.compiler.java.codegen;
import com.redhat.ceylon.compiler.java.util.Decl;
+import com.redhat.ceylon.compiler.typechecker.model.Declaration;
import com.redhat.ceylon.compiler.typechecker.model.Value;
import com.redhat.ceylon.compiler.typechecker.tree.NaturalVisitor;
import com.redhat.ceylon.compiler.typechecker.tree.Node;
@@ -234,10 +235,7 @@ public void visit(Tree.Continue stat) {
}
public void visit(Tree.SpecifierStatement op) {
- if (op.getRefinement()) {
- gen.classGen().transformRefinementSpecifierStatement(op, classBuilder);
- }
- append(gen.expressionGen().transform(op));
+ appendList(gen.classGen().transformRefinementSpecifierStatement(op, classBuilder));
}
public void visit(Tree.OperatorExpression op) {
@@ -47,6 +47,7 @@
import com.redhat.ceylon.compiler.typechecker.model.Interface;
import com.redhat.ceylon.compiler.typechecker.model.Method;
import com.redhat.ceylon.compiler.typechecker.model.Parameter;
+import com.redhat.ceylon.compiler.typechecker.model.ParameterList;
import com.redhat.ceylon.compiler.typechecker.model.ProducedType;
import com.redhat.ceylon.compiler.typechecker.model.Scope;
import com.redhat.ceylon.compiler.typechecker.model.Setter;
@@ -60,6 +61,7 @@
import com.redhat.ceylon.compiler.typechecker.tree.Tree.AttributeDeclaration;
import com.redhat.ceylon.compiler.typechecker.tree.Tree.AttributeGetterDefinition;
import com.redhat.ceylon.compiler.typechecker.tree.Tree.AttributeSetterDefinition;
+import com.redhat.ceylon.compiler.typechecker.tree.Tree.Block;
import com.redhat.ceylon.compiler.typechecker.tree.Tree.DefaultArgument;
import com.redhat.ceylon.compiler.typechecker.tree.Tree.MethodDeclaration;
import com.redhat.ceylon.compiler.typechecker.tree.Tree.MethodDefinition;
@@ -477,26 +479,76 @@ private void buildCompanion(final Tree.ClassOrInterface def,
}
}
- public void transformRefinementSpecifierStatement(SpecifierStatement op, ClassDefinitionBuilder classBuilder) {
+ public List<JCStatement> transformRefinementSpecifierStatement(SpecifierStatement op, ClassDefinitionBuilder classBuilder) {
+ List<JCStatement> result = List.<JCStatement>nil();
// Check if this is a shortcut form of formal attribute refinement
if (op.getRefinement()) {
- // Now build a "fake" declaration for the attribute
Tree.BaseMemberExpression expr = (Tree.BaseMemberExpression)op.getBaseMemberExpression();
- Value attr = (Value)expr.getDeclaration();
- Tree.AttributeDeclaration decl = new Tree.AttributeDeclaration(null);
- decl.setDeclarationModel(attr);
- decl.setIdentifier(expr.getIdentifier());
- decl.setScope(op.getScope());
-
- // Make sure the boxing information is set correctly
- BoxingDeclarationVisitor v = new BoxingDeclarationVisitor(this);
- v.visit(decl);
-
- // Generate the attribute
- transform(decl, classBuilder);
+ Declaration decl = expr.getDeclaration();
+ if (decl instanceof Value) {
+ // Now build a "fake" declaration for the attribute
+ Tree.AttributeDeclaration attrDecl = new Tree.AttributeDeclaration(null);
+ attrDecl.setDeclarationModel((Value)decl);
+ attrDecl.setIdentifier(expr.getIdentifier());
+ attrDecl.setScope(op.getScope());
+
+ // Make sure the boxing information is set correctly
+ BoxingDeclarationVisitor v = new BoxingDeclarationVisitor(this);
+ v.visit(attrDecl);
+
+ // Generate the attribute
+ transform(attrDecl, classBuilder);
+
+ // Generate the specifier statement
+ result = result.append(expressionGen().transform(op));
+ } else if (decl instanceof Method) {
+ // Now build a "fake" declaration for the method
+ Tree.MethodDeclaration methDecl = new Tree.MethodDeclaration(null);
+ Method m = (Method)decl;
+ methDecl.setDeclarationModel(m);
+ methDecl.setIdentifier(expr.getIdentifier());
+ methDecl.setScope(op.getScope());
+ methDecl.setSpecifierExpression(op.getSpecifierExpression());
+ for (ParameterList pl : m.getParameterLists()) {
+ Tree.ParameterList tpl = new Tree.ParameterList(null);
+ for (Parameter p : pl.getParameters()) {
+ Tree.Parameter tp = null;
+ if (p instanceof ValueParameter) {
+ Tree.ValueParameterDeclaration tvpd = new Tree.ValueParameterDeclaration(null);
+ tvpd.setDeclarationModel((ValueParameter)p);
+ tp = tvpd;
+ } else if (p instanceof FunctionalParameter) {
+ Tree.FunctionalParameterDeclaration tfpd = new Tree.FunctionalParameterDeclaration(null);
+ tfpd.setDeclarationModel((FunctionalParameter)p);
+ tp = tfpd;
+ }
+ tp.setScope(p.getContainer());
+ tp.setIdentifier(makeIdentifier(p.getName()));
+ tpl.addParameter(tp);
+ }
+ methDecl.addParameterList(tpl);
+ }
+
+ // Make sure the boxing information is set correctly
+ BoxingDeclarationVisitor v = new BoxingDeclarationVisitor(this);
+ v.visit(methDecl);
+
+ // Generate the attribute
+ classBuilder.method(methDecl);
+ }
+ } else {
+ // Normal case, just generate the specifier statement
+ result = result.append(expressionGen().transform(op));
}
+ return result;
}
+ private Tree.Identifier makeIdentifier(String name) {
+ Tree.Identifier id = new Tree.Identifier(null);
+ id.setText(name);
+ return id;
+ }
+
public void transform(AttributeDeclaration decl, ClassDefinitionBuilder classBuilder) {
final Value model = decl.getDeclarationModel();
boolean useField = Strategy.useField(model);
@@ -921,7 +973,25 @@ private int transformObjectDeclFlags(Value cdecl) {
Scope container = model.getContainer();
boolean isInterface = container instanceof com.redhat.ceylon.compiler.typechecker.model.Interface;
if(!isInterface){
- body = statementGen().transform(((Tree.MethodDefinition)def).getBlock()).getStatements();
+ boolean prevNoExpressionlessReturn = statementGen().noExpressionlessReturn;
+ try {
+ statementGen().noExpressionlessReturn = Decl.isMpl(model);
+
+ final Block block = ((Tree.MethodDefinition) def).getBlock();
+ body = statementGen().transform(block).getStatements();
+ // We void methods need to have their Callables return null
+ // so adjust here.
+ if (Decl.isMpl(model) &&
+ !block.getDefinitelyReturns()) {
+ if (Decl.isUnboxedVoid(model)) {
+ body = body.append(make().Return(makeNull()));
+ } else {
+ body = body.append(make().Return(makeErroneous(block, "non-void method doesn't definitely return")));
+ }
+ }
+ } finally {
+ statementGen().noExpressionlessReturn = prevNoExpressionlessReturn;
+ }
}
} else if (def instanceof MethodDeclaration
&& ((MethodDeclaration) def).getSpecifierExpression() != null) {
@@ -191,7 +191,6 @@ JCExpression applyErasureAndBoxing(JCExpression result, ProducedType exprType,
boolean canCast = false;
if (expectedType != null
- && !(simplifyType(expectedType).getDeclaration() instanceof TypeParameter)
// don't add cast to an erased type
&& !willEraseToObject(expectedType)
// don't add cast for null
@@ -1551,7 +1550,7 @@ private JCExpression transformAssignment(Node op, Tree.Term leftTerm, Tree.Term
inStatement = false;
// right side
- final JCExpression rhs = transformExpression(rightTerm, Util.getBoxingStrategy(decl), decl.getType());
+ final JCExpression rhs = transformExpression(rightTerm, Util.getBoxingStrategy(decl), leftTerm.getTypeModel());
if (tmpInStatement) {
return transformAssignment(op, leftTerm, rhs);
@@ -879,10 +879,22 @@ private void appendVarsForNamedArguments(
// TODO MPL
Method model = methodArg.getDeclarationModel();
ProducedType callableType = gen.typeFact().getCallableType(model.getType());
- List<JCStatement> body = gen.statementGen().transform(methodArg.getBlock()).getStatements();
- if (gen.isVoid(model.getType())) {
- body = gen.addReturnNull(body);
+ List<JCStatement> body;
+ boolean prevNoExpressionlessReturn = gen.statementGen().noExpressionlessReturn;
+ try {
+ gen.statementGen().noExpressionlessReturn = gen.isVoid(model.getType());
+ body = gen.statementGen().transform(methodArg.getBlock()).getStatements();
+ if (!methodArg.getBlock().getDefinitelyReturns()) {
+ if (gen.isVoid(model.getType())) {
+ body = body.append(gen.make().Return(gen.makeNull()));
+ } else {
+ body = body.append(gen.make().Return(gen.makeErroneous(methodArg.getBlock(), "non-void method doesn't definitely return")));
+ }
+ }
+ } finally {
+ gen.statementGen().noExpressionlessReturn = prevNoExpressionlessReturn;
}
+
CallableBuilder callableBuilder = CallableBuilder.methodArgument(gen.gen(),
callableType,
model.getParameterLists().get(0),
@@ -72,6 +72,13 @@
// Is null if we're currently in a while-loop or not in any loop at all
private Name currentForFailVariable = null;
+ /**
+ * If false generating plain {@code return;} statements is OK.
+ * If true then generate {@code return null;} statements instead of
+ * expressionless {@code return;}.
+ */
+ boolean noExpressionlessReturn = false;
+
public static StatementTransformer getInstance(Context context) {
StatementTransformer trans = context.get(StatementTransformer.class);
if (trans == null) {
@@ -415,14 +422,22 @@ JCStatement transform(Tree.Return ret) {
JCExpression returnExpr = null;
at(ret);
if (expr != null) {
- // we can cast to TypedDeclaration here because return with expressions are only in Method or Value
- TypedDeclaration declaration = (TypedDeclaration)ret.getDeclaration();
- // make sure we use the best declaration for boxing and type
- TypedDeclaration nonWideningTypeDeclaration = nonWideningTypeDecl(declaration);
- ProducedType nonWideningType = nonWideningType(declaration, nonWideningTypeDeclaration);
- returnExpr = expressionGen().transformExpression(expr.getTerm(),
- Util.getBoxingStrategy(nonWideningTypeDeclaration),
- nonWideningType);
+ boolean prevNoExpressionlessReturn = noExpressionlessReturn;
+ try {
+ noExpressionlessReturn = false;
+ // we can cast to TypedDeclaration here because return with expressions are only in Method or Value
+ TypedDeclaration declaration = (TypedDeclaration)ret.getDeclaration();
+ // make sure we use the best declaration for boxing and type
+ TypedDeclaration nonWideningTypeDeclaration = nonWideningTypeDecl(declaration);
+ ProducedType nonWideningType = nonWideningType(declaration, nonWideningTypeDeclaration);
+ returnExpr = expressionGen().transformExpression(expr.getTerm(),
+ Util.getBoxingStrategy(nonWideningTypeDeclaration),
+ nonWideningType);
+ } finally {
+ noExpressionlessReturn = prevNoExpressionlessReturn;
+ }
+ } else if (noExpressionlessReturn) {
+ returnExpr = makeNull();
}
return at(ret).Return(returnExpr);
}
@@ -315,4 +315,8 @@ public static boolean isUnboxedVoid(Declaration decl) {
return (decl instanceof Method)
&& ((Method)decl).isDeclaredVoid();
}
+
+ public static boolean isMpl(Method decl) {
+ return decl.getParameterLists().size() > 1;
+ }
}
@@ -53,10 +53,7 @@ final class indirectTypeParam {
@.java.lang.Override
public .java.lang.Object $call() {
- if (true) {
- throw new .ceylon.language.Exception(null, null);
- }
- return null;
+ throw new .ceylon.language.Exception(null, null);
}
};
}
@@ -73,10 +70,7 @@ final class indirectTypeParam {
@.java.lang.Override
public .java.lang.Object $call() {
- if (true) {
- return mpl.<.ceylon.language.Integer>mpl(i);
- }
- return null;
+ return mpl.<.ceylon.language.Integer>mpl(i);
}
};
}
@@ -24,8 +24,6 @@ final class methodArgumentNamedIncovationVoid {
@.java.lang.Override
public .java.lang.Object $call(final .java.lang.Object $param$0) {
final .ceylon.language.Integer i = (.ceylon.language.Integer)$param$0;
- if (true) {
- }
return null;
}
};
@@ -110,7 +110,7 @@ class JavaInterfaceImpl implements .com.redhat.ceylon.compiler.java.test.interop
@.java.lang.Override
public final <M>M methodTypeParamMethod(final M b) {
- return .ceylon.language.bottom.getBottom();
+ return (M).ceylon.language.bottom.getBottom();
}
JavaInterfaceImpl() {
@@ -120,4 +120,4 @@ class JavaInterfaceImpl implements .com.redhat.ceylon.compiler.java.test.interop
.ceylon.language.process.getProcess().setupArguments(args);
new .com.redhat.ceylon.compiler.java.test.interop.JavaInterfaceImpl();
}
-}
+}
Oops, something went wrong.

0 comments on commit 967db3c

Please sign in to comment.