use of org.eclipse.ceylon.model.typechecker.model.FunctionOrValue in project ceylon by eclipse.
the class CallableBuilder method makeFunctionalInterfaceMethod.
public MethodDefinitionBuilder makeFunctionalInterfaceMethod() {
FunctionOrValue methodOrValue = (FunctionOrValue) functionalInterfaceMethod.getDeclaration();
MethodDefinitionBuilder callMethod = MethodDefinitionBuilder.method(gen, methodOrValue, 0);
callMethod.isOverride(true);
callMethod.modifiers(Flags.PUBLIC);
Type returnType = functionalInterfaceMethod.getType();
if (methodOrValue instanceof Value || !((Function) methodOrValue).isDeclaredVoid()) {
int flags = CodegenUtil.isUnBoxed(methodOrValue) ? 0 : JT_NO_PRIMITIVES;
callMethod.resultType(gen.makeJavaType(returnType, flags), null);
}
ListBuffer<JCExpression> args = new ListBuffer<>();
// this depends on how we're declared to Java
boolean turnedToRaw = gen.rawSupertype(functionalInterface, JT_EXTENDS | JT_CLASS_NEW);
boolean variadic = false;
if (methodOrValue instanceof Function) {
int index = 0;
java.util.List<Parameter> parameters = ((Function) methodOrValue).getFirstParameterList().getParameters();
for (int i = 0; i < parameters.size(); i++) {
Parameter param = parameters.get(i);
Parameter targetParam = paramLists.getParameters().get(i);
TypedReference typedParameter = functionalInterfaceMethod.getTypedParameter(param);
ParameterDefinitionBuilder pdb = ParameterDefinitionBuilder.systemParameter(gen, param.getName());
Type paramType = typedParameter.getType();
if (param.isSequenced()) {
paramType = gen.typeFact().getSequentialElementType(paramType);
variadic = true;
}
// This is very special-casey, but is required and I haven't found more subtle
if (turnedToRaw && gen.simplifyType(param.getType()).isTypeParameter()) {
paramType = gen.typeFact().getObjectType();
}
long flags = Flags.FINAL;
// that looks fishy, perhaps we need to call non-widening rules instead
JCExpression javaType = gen.makeJavaType(paramType, paramType.isRaw() ? AbstractTransformer.JT_RAW : 0);
if (param.isSequenced()) {
flags |= Flags.VARARGS;
javaType = gen.make().TypeArray(javaType);
}
pdb.type(new TransformedType(javaType));
pdb.modifiers(flags);
callMethod.parameter(pdb);
JCExpression arg;
if (param.isSequenced()) {
arg = gen.javaVariadicToSequential(paramType, param);
} else {
arg = gen.makeUnquotedIdent(param.getName());
Type argumentType = parameterTypes.get(index);
if (gen.isOptional(paramType) && argumentType.isSubtypeOf(gen.typeFact().getObjectType()) && !targetParam.getModel().hasUncheckedNullType()) {
arg = gen.utilInvocation().checkNull(arg);
}
Type simpleParamType = gen.simplifyType(paramType);
// make unboxed java strings pass for ceylon strings so we can box them
boolean unboxedString = gen.isJavaStringExactly(simpleParamType);
if (unboxedString)
simpleParamType = gen.typeFact().getStringType();
BoxingStrategy boxingStrategy = BoxingStrategy.BOXED;
// in rare cases we don't want boxes
if (unboxedString && gen.isJavaStringExactly(argumentType))
boxingStrategy = BoxingStrategy.UNBOXED;
arg = gen.expressionGen().applyErasureAndBoxing(arg, simpleParamType, !(CodegenUtil.isUnBoxed(param.getModel()) || unboxedString), boxingStrategy, argumentType);
}
args.append(arg);
index++;
}
} else {
// no-arg getter
}
String callMethodName;
if (variadic)
callMethodName = Naming.getCallableVariadicMethodName();
else
callMethodName = Naming.getCallableMethodName();
JCExpression call = gen.make().Apply(null, gen.makeUnquotedIdent(callMethodName), args.toList());
JCStatement body;
if (methodOrValue instanceof Function && ((Function) methodOrValue).isDeclaredVoid())
body = gen.make().Exec(call);
else {
Type callableReturnType = gen.getReturnTypeOfCallable(typeModel);
Type simpleReturnType = gen.simplifyType(returnType);
boolean unboxed = CodegenUtil.isUnBoxed(methodOrValue) || gen.isJavaStringExactly(simpleReturnType);
if (unboxed) {
call = gen.expressionGen().applyErasureAndBoxing(call, callableReturnType, true, BoxingStrategy.UNBOXED, returnType);
} else if (callableReturnType.isNull()) {
// if the callable returns null and the SAM does not, we need a cast
call = gen.expressionGen().applyErasureAndBoxing(call, callableReturnType, true, BoxingStrategy.INDIFFERENT, returnType);
}
body = gen.make().Return(call);
}
callMethod.body(body);
return callMethod;
}
use of org.eclipse.ceylon.model.typechecker.model.FunctionOrValue in project ceylon by eclipse.
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
ClassDefinitionBuilder classBuilder = ClassDefinitionBuilder.klass(this, attrClassName, null, false);
final HasErrorException expressionError;
if (expression != null) {
expressionError = errors().getFirstExpressionErrorAndMarkBrokenness(expression.getExpression());
} else {
expressionError = null;
}
BoxingStrategy boxingStrategy = null;
final JCExpression initialValue;
if (expressionError != null) {
initialValue = make().Erroneous();
} else {
if (Decl.isNonTransientValue(declarationModel) && !(expression instanceof Tree.LazySpecifierExpression)) {
if (expression != null) {
boxingStrategy = useJavaBox(declarationModel, declarationModel.getType()) && javaBoxExpression(expression.getExpression().getTypeModel(), declarationModel.getType()) ? BoxingStrategy.JAVA : CodegenUtil.getBoxingStrategy(declarationModel);
initialValue = expressionGen().transform(expression, boxingStrategy, declarationModel.getType());
} else {
Parameter p = CodegenUtil.findParamForDecl(attrName, declarationModel);
if (p != null) {
boxingStrategy = CodegenUtil.getBoxingStrategy(p.getModel());
initialValue = naming.makeName(p.getModel(), Naming.NA_MEMBER | Naming.NA_ALIASED);
} else {
initialValue = null;
}
}
} else {
initialValue = null;
}
}
boolean memoized = declarationModel.isLate() && expression != null;
AttributeDefinitionBuilder builder = AttributeDefinitionBuilder.wrapped(this, attrName, declarationModel, declarationModel.isToplevel(), memoized ? initialValue : null);
builder.is(Flags.PUBLIC, declarationModel.isShared());
if (isJavaStrictfp(declarationModel)) {
builder.is(Flags.STRICTFP, true);
}
if (isJavaSynchronized(declarationModel)) {
builder.is(Flags.SYNCHRONIZED, true);
}
if (isJavaNative(declarationModel)) {
builder.is(Flags.NATIVE, true);
builder.isJavaNative(true);
}
// For captured local variable Values, use a VariableBox
if (Decl.isBoxedVariable(declarationModel)) {
classBuilder.restoreClassBuilder();
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 && !declarationModel.isToplevel()) {
JCExpression typeExpr = makeJavaType(getGetterInterfaceType(declarationModel));
JCTree.JCVariableDecl var = makeVar(attrClassName, typeExpr, null);
classBuilder.restoreClassBuilder();
return List.<JCTree>of(var);
}
// Set the local declarations annotation
List<JCAnnotation> scopeAnnotations = null;
if (decl != null) {
scopeAnnotations = declarationModel.isToplevel() && setterDecl != null ? makeAtLocalDeclarations(decl, setterDecl) : makeAtLocalDeclarations(decl);
} else if (block != null) {
scopeAnnotations = makeAtLocalDeclarations(block);
}
if (scopeAnnotations != null)
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.getDeclarationModel())) {
// 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 = Decl.isLocal(declarationModel) ? expressionGen().withinSyntheticClassBody(true) : 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));
builder.fieldAnnotations(expressionGen().transformAnnotations(OutputElement.FIELD, annotated));
}
if (Decl.isLocal(declarationModel)) {
if (expressionError != null) {
classBuilder.restoreClassBuilder();
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.buildWithWrapperClass(classBuilder).append(makeLocalIdentityInstance(typeExpr, attrClassName, attrClassName, declarationModel.isShared(), initialValue));
} else {
if (expressionError != null) {
builder.initialValueError(expressionError);
} else if (!memoized && initialValue != null) {
builder.initialValue(initialValue, boxingStrategy);
}
builder.is(Flags.STATIC, true);
return builder.buildWithWrapperClass(classBuilder);
}
}
use of org.eclipse.ceylon.model.typechecker.model.FunctionOrValue in project ceylon by eclipse.
the class ExpressionTransformer method transformAssignment.
private JCExpression transformAssignment(Node op, Tree.Term leftTerm, Tree.Term rightTerm) {
// Remember and disable inStatement for RHS
boolean tmpInStatement = inStatement;
inStatement = false;
// FIXME: can this be anything else than a Tree.MemberOrTypeExpression or Tree.ParameterizedExpression or Tree.IndexExpression?
final JCExpression rhs;
BoxingStrategy boxing;
if (leftTerm instanceof Tree.MemberOrTypeExpression) {
TypedDeclaration decl = (TypedDeclaration) ((Tree.MemberOrTypeExpression) leftTerm).getDeclaration();
boxing = CodegenUtil.getBoxingStrategy(decl);
if (decl instanceof Value) {
Value val = (Value) decl;
if (val.getSetter() != null && val.getSetter().getUnboxed() != null) {
boxing = CodegenUtil.getBoxingStrategy(val.getSetter());
}
}
Type targetType = tmpInStatement ? leftTerm.getTypeModel() : rightTerm.getTypeModel();
// if we're dealing with widening do not trust the type of the declaration and get the real type
if (CodegenUtil.hasUntrustedType(decl)) {
TypedReference typedRef = (TypedReference) ((Tree.MemberOrTypeExpression) leftTerm).getTarget();
TypedReference nonWideningTypedRef = nonWideningTypeDecl(typedRef);
targetType = nonWideningType(typedRef, nonWideningTypedRef);
}
int flags = decl.hasUncheckedNullType() ? EXPR_TARGET_ACCEPTS_NULL : 0;
flags |= leftTerm.getSmall() && !rightTerm.getSmall() ? EXPR_UNSAFE_PRIMITIVE_TYPECAST_OK : 0;
if (decl.isMember() && useFieldInAssignment(op, null, decl) && !ModelUtil.isLocalToInitializer(decl) && useJavaBox(decl, ((TypedDeclaration) decl.getRefinedDeclaration()).getType())) {
boxing = BoxingStrategy.JAVA;
flags |= EXPR_HAS_NULL_CHECK_FENCE;
}
rhs = transformExpression(rightTerm, boxing, targetType, flags);
} else if (leftTerm instanceof Tree.IndexExpression) {
Tree.IndexExpression idx = (Tree.IndexExpression) leftTerm;
Unit unit = op.getUnit();
Type pt = idx.getPrimary().getTypeModel();
boxing = (unit.isJavaPrimitiveArrayType(pt)) ? BoxingStrategy.UNBOXED : BoxingStrategy.BOXED;
rhs = transformExpression(rightTerm, boxing, idx.getTypeModel(), 0);
} else if (leftTerm instanceof Tree.ParameterizedExpression) {
boxing = CodegenUtil.getBoxingStrategy(leftTerm);
Tree.ParameterizedExpression paramExpr = (Tree.ParameterizedExpression) leftTerm;
FunctionOrValue decl = (FunctionOrValue) ((Tree.MemberOrTypeExpression) paramExpr.getPrimary()).getDeclaration();
CallableBuilder callableBuilder = CallableBuilder.anonymous(gen(), paramExpr, decl, (Tree.Expression) rightTerm, paramExpr.getParameterLists(), paramExpr.getPrimary().getTypeModel(), decl instanceof Function ? !((Function) decl).isDeferred() : false);
rhs = callableBuilder.build();
} else {
return makeErroneous(leftTerm, "compiler bug: left term of type '" + leftTerm.getClass().getSimpleName() + "' is not yet supported");
}
if (tmpInStatement) {
return makeAssignment(op, leftTerm, transformAssignmentLhs(op, leftTerm), rhs);
} else {
Type valueType = rightTerm.getTypeModel();
if (isNull(valueType))
valueType = leftTerm.getTypeModel();
return transformAssignAndReturnOperation(op, leftTerm, boxing == BoxingStrategy.BOXED, leftTerm.getTypeModel(), valueType, new AssignAndReturnOperationFactory() {
@Override
public JCExpression getNewValue(JCExpression previousValue) {
return rhs;
}
});
}
}
use of org.eclipse.ceylon.model.typechecker.model.FunctionOrValue in project ceylon by eclipse.
the class CeylonDocTool method warningMissingThrows.
protected void warningMissingThrows(Declaration d) {
if (ignoreMissingThrows) {
return;
}
final Scope scope = d.getScope();
final PhasedUnit unit = getUnit(d);
final Node node = getNode(d);
if (scope == null || unit == null || unit.getUnit() == null || node == null || !(d instanceof FunctionOrValue)) {
return;
}
List<Type> documentedExceptions = new ArrayList<Type>();
for (Annotation annotation : d.getAnnotations()) {
if (annotation.getName().equals("throws")) {
String exceptionName = annotation.getPositionalArguments().get(0);
Declaration exceptionDecl = scope.getMemberOrParameter(unit.getUnit(), exceptionName, null, false);
if (exceptionDecl instanceof TypeDeclaration) {
documentedExceptions.add(((TypeDeclaration) exceptionDecl).getType());
}
}
}
final List<Type> thrownExceptions = new ArrayList<Type>();
node.visitChildren(new Visitor() {
@Override
public void visit(Tree.Throw that) {
Expression expression = that.getExpression();
if (expression != null) {
thrownExceptions.add(expression.getTypeModel());
} else {
thrownExceptions.add(unit.getUnit().getExceptionType());
}
}
@Override
public void visit(Tree.Declaration that) {
// the end of searching
}
});
for (Type thrownException : thrownExceptions) {
boolean isDocumented = false;
for (Type documentedException : documentedExceptions) {
if (thrownException.isSubtypeOf(documentedException)) {
isDocumented = true;
break;
}
}
if (!isDocumented) {
richLog.warning(CeylondMessages.msg("warn.missingThrows", thrownException.asString(), getWhere(d), getPosition(getNode(d))));
}
}
}
use of org.eclipse.ceylon.model.typechecker.model.FunctionOrValue in project ceylon by eclipse.
the class GenerateJsVisitor method assignment.
private void assignment(final TypeDeclaration outer, final Declaration d, final Tree.Expression expr) {
FunctionOrValue vdec = (FunctionOrValue) d;
final String atname = names.valueName(vdec);
if (outer instanceof Constructor) {
if (d.isClassOrInterfaceMember()) {
out(names.self(outer), ".", atname, "=");
} else {
out(names.name(d), "=");
}
expr.visit(this);
endLine(true);
}
if (d.isClassOrInterfaceMember()) {
defineAttribute(names.self(outer), names.name(d));
out("{");
if (vdec.isLate()) {
generateUnitializedAttributeReadCheck("this." + atname, names.name(d), null);
}
out("return this.", atname, ";}");
if (vdec.isVariable() || vdec.isLate()) {
final String par = getNames().createTempVariable();
out(",function(", par, "){");
generateImmutableAttributeReassignmentCheck(vdec, "this." + atname, names.name(d));
out("return this.", atname, "=", par, ";}");
} else {
out(",undefined");
}
out(",");
TypeUtils.encodeForRuntime(expr, d, this);
out(")");
endLine(true);
}
}
Aggregations