use of com.redhat.ceylon.model.typechecker.model.FunctionOrValue in project ceylon-compiler by ceylon.
the class CeylonTransformer method transformAttribute.
public List<JCTree> transformAttribute(TypedDeclaration declarationModel, String attrName, String attrClassName, final Tree.Declaration annotated, final Tree.Block block, final Tree.SpecifierOrInitializerExpression expression, final Tree.TypedDeclaration decl, final Tree.AttributeSetterDefinition setterDecl) {
// For everything else generate a getter/setter method
AttributeDefinitionBuilder builder = AttributeDefinitionBuilder.wrapped(this, attrClassName, null, attrName, declarationModel, declarationModel.isToplevel()).is(Flags.PUBLIC, declarationModel.isShared());
final JCExpression initialValue;
final HasErrorException expressionError;
if (expression != null) {
expressionError = errors().getFirstExpressionErrorAndMarkBrokenness(expression.getExpression());
if (expressionError != null) {
initialValue = make().Erroneous();
} else {
initialValue = transformValueInit(declarationModel, attrName, expression);
}
} else {
expressionError = null;
initialValue = transformValueInit(declarationModel, attrName, expression);
}
// For captured local variable Values, use a VariableBox
if (Decl.isBoxedVariable(declarationModel)) {
if (expressionError != null) {
return List.<JCTree>of(this.makeThrowUnresolvedCompilationError(expressionError));
} else {
return List.<JCTree>of(makeVariableBoxDecl(initialValue, declarationModel));
}
}
// For late-bound getters we only generate a declaration
if (block == null && expression == null && !Decl.isToplevel(declarationModel)) {
JCExpression typeExpr = makeJavaType(getGetterInterfaceType(declarationModel));
JCTree.JCVariableDecl var = makeVar(attrClassName, typeExpr, null);
return List.<JCTree>of(var);
}
// Set the local declarations annotation
if (decl != null) {
List<JCAnnotation> scopeAnnotations;
if (Decl.isToplevel(declarationModel) && setterDecl != null) {
scopeAnnotations = makeAtLocalDeclarations(decl, setterDecl);
} else {
scopeAnnotations = makeAtLocalDeclarations(decl);
}
builder.classAnnotations(scopeAnnotations);
} else if (block != null) {
List<JCAnnotation> scopeAnnotations = makeAtLocalDeclarations(block);
builder.classAnnotations(scopeAnnotations);
}
// Remember the setter class if we generate a getter
if (Decl.isGetter(declarationModel) && declarationModel.isVariable() && Decl.isLocal(declarationModel)) {
// we must have a setter class
Setter setter = ((Value) declarationModel).getSetter();
if (setter != null) {
String setterClassName = Naming.getAttrClassName(setter, 0);
JCExpression setterClassNameExpr = naming.makeUnquotedIdent(setterClassName);
builder.setterClass(makeSelect(setterClassNameExpr, "class"));
}
}
if (declarationModel instanceof Setter || (declarationModel instanceof FunctionOrValue && ((FunctionOrValue) declarationModel).isParameter())) {
// For local setters
JCBlock setterBlock = makeSetterBlock(declarationModel, block, expression);
builder.setterBlock(setterBlock);
builder.skipGetter();
if (Decl.isLocal(decl)) {
// we need to find back the Setter model for local setters, because
// in transformAttribute(Tree.TypedDeclaration decl, Tree.AttributeSetterDefinition setterDecl)
// we turn the declaration model from the Setter to its single parameter
Setter setter = (Setter) declarationModel.getContainer();
String getterClassName = Naming.getAttrClassName(setter.getGetter(), 0);
JCExpression getterClassNameExpr = naming.makeUnquotedIdent(getterClassName);
builder.isSetter(makeSelect(getterClassNameExpr, "class"));
}
} else {
if (Decl.isValue(declarationModel)) {
// For local and toplevel value attributes
if (!declarationModel.isVariable() && !declarationModel.isLate()) {
builder.immutable();
}
} else {
// For local and toplevel getters
boolean prevSyntheticClassBody;
if (Decl.isLocal(declarationModel)) {
prevSyntheticClassBody = expressionGen().withinSyntheticClassBody(true);
} else {
prevSyntheticClassBody = expressionGen().isWithinSyntheticClassBody();
}
JCBlock getterBlock = makeGetterBlock(declarationModel, block, expression);
prevSyntheticClassBody = expressionGen().withinSyntheticClassBody(prevSyntheticClassBody);
builder.getterBlock(getterBlock);
if (Decl.isLocal(declarationModel)) {
// For local getters
builder.immutable();
} else {
// For toplevel getters
if (setterDecl != null) {
JCBlock setterBlock = makeSetterBlock(setterDecl.getDeclarationModel(), setterDecl.getBlock(), setterDecl.getSpecifierExpression());
builder.setterBlock(setterBlock);
//builder.userAnnotationsSetter(expressionGen().transformAnnotations(true, OutputElement.METHOD, setterDecl));
builder.userAnnotationsSetter(expressionGen().transformAnnotations(OutputElement.SETTER, setterDecl));
} else {
builder.immutable();
}
}
}
}
if (annotated != null) {
builder.userAnnotations(expressionGen().transformAnnotations(OutputElement.GETTER, annotated));
}
if (Decl.isLocal(declarationModel)) {
if (expressionError != null) {
return List.<JCTree>of(this.makeThrowUnresolvedCompilationError(expressionError));
}
builder.classAnnotations(makeAtLocalDeclaration(declarationModel.getQualifier(), false));
if (initialValue != null)
builder.valueConstructor();
JCExpression typeExpr;
if (declarationModel instanceof Setter || (declarationModel instanceof FunctionOrValue && ((FunctionOrValue) declarationModel).isParameter())) {
typeExpr = makeQuotedIdent(attrClassName);
} else {
typeExpr = makeJavaType(getGetterInterfaceType(declarationModel));
}
return builder.build().append(makeLocalIdentityInstance(typeExpr, attrClassName, attrClassName, declarationModel.isShared(), initialValue));
} else {
if (expressionError != null) {
builder.initialValueError(expressionError);
} else if (initialValue != null) {
builder.initialValue(initialValue);
}
builder.is(Flags.STATIC, true);
return builder.build();
}
}
use of com.redhat.ceylon.model.typechecker.model.FunctionOrValue in project ceylon-compiler by ceylon.
the class MethodOrValueReferenceVisitor method usedIn.
/**
* Returns 1 if the declaration is captured in the given statements, 0 otherwise.
*/
private int usedIn(List<Statement> stmts) {
for (Tree.Statement stmt : stmts) {
// count declarations as usage
if (stmt instanceof Tree.TypedDeclaration && ((Tree.TypedDeclaration) stmt).getDeclarationModel() == declaration)
return 1;
stmt.visit(this);
if (declaration.isCaptured())
break;
}
boolean used = declaration.isCaptured();
FunctionOrValue fov = ((FunctionOrValue) declaration);
fov.setCaptured(false);
if (fov instanceof Value) {
Value val = (Value) fov;
if (val.getSetter() != null)
val.getSetter().setCaptured(false);
}
return used ? 1 : 0;
}
use of com.redhat.ceylon.model.typechecker.model.FunctionOrValue in project ceylon-compiler by ceylon.
the class MethodOrValueReferenceVisitor method visitConstructorPlan.
/**
* Marks declarations as captured if they are used in more than one generated constructor, according
* to the given plan and knowledge on how we split up constructor delegates.
*/
private void visitConstructorPlan(ConstructorPlan constructorPlan) {
// if there is no delegation all statements are put in the same method so we can't capture
if (constructorPlan.delegate == null && !constructorPlan.isDelegate)
return;
boolean cs = enterCapturingScope();
int useCount = usedIn(constructorPlan, false);
FunctionOrValue fov = ((FunctionOrValue) declaration);
fov.setCaptured(useCount > 1);
if (fov instanceof Value) {
Value val = (Value) fov;
if (val.getSetter() != null)
val.getSetter().setCaptured(useCount > 1);
}
exitCapturingScope(cs);
}
use of com.redhat.ceylon.model.typechecker.model.FunctionOrValue in project ceylon-compiler by ceylon.
the class MethodOrValueReferenceVisitor method visit.
@Override
public void visit(Tree.ClassDefinition that) {
if (!that.getDeclarationModel().hasConstructors()) {
boolean cs = enterCapturingScope();
super.visit(that);
exitCapturingScope(cs);
} else {
// super special case for unshared members when we have constructors
if (!declaration.isCaptured() && declaration instanceof FunctionOrValue && declaration.isClassMember()) {
Map<Constructor, ConstructorPlan> constructorPlans = new HashMap<Constructor, ConstructorPlan>();
List<Tree.Statement> statements = new ArrayList<>(that.getClassBody().getStatements().size());
// find every constructor, and build a model of how they delegate
for (Tree.Statement stmt : that.getClassBody().getStatements()) {
if (stmt instanceof Tree.Constructor) {
Tree.Constructor ctor = (Tree.Constructor) stmt;
// build a new plan for it
ConstructorPlan plan = new ConstructorPlan();
plan.constructor = ctor;
constructorPlans.put(ctor.getConstructor(), plan);
// find every constructor which delegates to another constructor
if (ctor.getDelegatedConstructor() != null && ctor.getDelegatedConstructor().getInvocationExpression() != null) {
if (ctor.getDelegatedConstructor().getInvocationExpression().getPrimary() instanceof Tree.ExtendedTypeExpression) {
Tree.ExtendedTypeExpression ete = (Tree.ExtendedTypeExpression) ctor.getDelegatedConstructor().getInvocationExpression().getPrimary();
// are we delegating to a constructor (not a supertype) of the same class (this class)?
if (Decl.isConstructor(ete.getDeclaration()) && Decl.getConstructedClass(ete.getDeclaration()).equals(that.getDeclarationModel())) {
// remember the delegation
Constructor delegate = Decl.getConstructor(ete.getDeclaration());
ConstructorPlan delegatePlan = constructorPlans.get(delegate);
plan.delegate = delegatePlan;
// mark the delegate as delegated
delegatePlan.isDelegate = true;
// we have all the statements before us and after our delegate
plan.before.addAll(delegatePlan.after);
}
}
}
// if we have no delegate, we start with every common statement
if (plan.delegate == null)
plan.before.addAll(statements);
// also add all the constructor's statements
if (ctor.getBlock() != null) {
plan.before.addAll(ctor.getBlock().getStatements());
}
} else {
statements.add(stmt);
// make sure all existing constructors get this statement too
for (ConstructorPlan constructorPlan : constructorPlans.values()) constructorPlan.after.add(stmt);
}
}
// try every constructor plan and see if it's used in two methods
for (ConstructorPlan constructorPlan : constructorPlans.values()) {
visitConstructorPlan(constructorPlan);
// are we done?
if (declaration.isCaptured())
break;
}
}
// do regular capturing after that (for members), if required
if (!declaration.isCaptured())
super.visit(that);
}
}
use of com.redhat.ceylon.model.typechecker.model.FunctionOrValue in project ceylon-compiler by ceylon.
the class MethodOrValueReferenceVisitor method isCapturableMplParameter.
/**
* Because methods with MPL use nested anonymous AbstractCallables
* if the declaration is a parameter in all but the last parameter list
* it should be captured.
*/
private boolean isCapturableMplParameter(Declaration d) {
if (!(d instanceof FunctionOrValue)) {
return false;
}
com.redhat.ceylon.model.typechecker.model.Parameter param = ((FunctionOrValue) d).getInitializerParameter();
if (param == null) {
return false;
}
Declaration paramDecl = param.getDeclaration();
if (paramDecl instanceof Functional) {
List<com.redhat.ceylon.model.typechecker.model.ParameterList> parameterLists = ((Functional) paramDecl).getParameterLists();
for (int i = 0; i < parameterLists.size() - 1; i++) {
if (parameterLists.get(i).getParameters().contains(param)) {
return true;
}
}
}
return false;
}
Aggregations