use of org.eclipse.ceylon.model.typechecker.model.Functional in project ceylon by eclipse.
the class ExpressionVisitor method inferParameterTypes.
/**
* Infer parameter types for anonymous functions in a
* positional argument list, and set up references from
* arguments back to parameter models.
*/
private boolean[] inferParameterTypes(Tree.Primary p, Tree.PositionalArgumentList pal, boolean error) {
Type type = p.getTypeModel();
Tree.Term term = unwrapExpressionUntilTerm(p);
if (term instanceof Tree.MemberOrTypeExpression) {
Tree.MemberOrTypeExpression mte = (Tree.MemberOrTypeExpression) term;
Declaration dec = mte.getDeclaration();
if (dec == null || dec.isDynamic()) {
if (type == null || type.isUnknown()) {
inferDynamicParameters(pal);
}
} else if (dec instanceof Functional) {
setupTargetParametersDirectly(pal, mte, dec, error);
return inferParameterTypesDirectly(pal, mte, dec, error);
} else if (dec instanceof Value) {
Value value = (Value) dec;
return inferParameterTypesIndirectly(pal, value.getType(), error);
}
} else {
if (type == null || type.isUnknown()) {
inferDynamicParameters(pal);
} else {
return inferParameterTypesIndirectly(pal, type, error);
}
}
int size = pal.getPositionalArguments().size();
return new boolean[size];
}
use of org.eclipse.ceylon.model.typechecker.model.Functional in project ceylon by eclipse.
the class ClassTransformer method transformSpecifiedMethodBody.
List<JCStatement> transformSpecifiedMethodBody(Tree.MethodDeclaration def, SpecifierExpression specifierExpression) {
final Function model = def.getDeclarationModel();
Tree.MethodDeclaration methodDecl = def;
boolean isLazy = specifierExpression instanceof Tree.LazySpecifierExpression;
boolean returnNull = false;
JCExpression bodyExpr;
Tree.Term term = null;
if (specifierExpression != null && specifierExpression.getExpression() != null) {
term = Decl.unwrapExpressionsUntilTerm(specifierExpression.getExpression());
HasErrorException error = errors().getFirstExpressionErrorAndMarkBrokenness(term);
if (error != null) {
return List.<JCStatement>of(this.makeThrowUnresolvedCompilationError(error));
}
}
if (!isLazy && term instanceof Tree.FunctionArgument) {
// Function specified with lambda: Don't bother generating a
// Callable, just transform the expr to use as the method body.
Tree.FunctionArgument fa = (Tree.FunctionArgument) term;
Type resultType = model.getType();
returnNull = Decl.isUnboxedVoid(model);
final java.util.List<Tree.Parameter> lambdaParams = fa.getParameterLists().get(0).getParameters();
final java.util.List<Tree.Parameter> defParams = def.getParameterLists().get(0).getParameters();
List<Substitution> substitutions = List.nil();
for (int ii = 0; ii < lambdaParams.size(); ii++) {
substitutions = substitutions.append(naming.addVariableSubst((TypedDeclaration) lambdaParams.get(ii).getParameterModel().getModel(), defParams.get(ii).getParameterModel().getName()));
}
List<JCStatement> body = null;
if (fa.getExpression() != null)
bodyExpr = gen().expressionGen().transformExpression(fa.getExpression(), returnNull ? BoxingStrategy.INDIFFERENT : CodegenUtil.getBoxingStrategy(model), resultType);
else {
body = gen().statementGen().transformBlock(fa.getBlock());
// useless but satisfies branch checking
bodyExpr = null;
}
for (Substitution subs : substitutions) {
subs.close();
}
// if we have a whole body we're done
if (body != null)
return body;
} else if (!isLazy && typeFact().isCallableType(term.getTypeModel())) {
returnNull = isAnything(term.getTypeModel()) && term.getUnboxed();
Function method = methodDecl.getDeclarationModel();
boolean lazy = specifierExpression instanceof Tree.LazySpecifierExpression;
boolean inlined = CodegenUtil.canOptimiseMethodSpecifier(term, method);
Invocation invocation;
if ((lazy || inlined) && term instanceof Tree.MemberOrTypeExpression && ((Tree.MemberOrTypeExpression) term).getDeclaration() instanceof Functional) {
Declaration primaryDeclaration = ((Tree.MemberOrTypeExpression) term).getDeclaration();
Reference producedReference = ((Tree.MemberOrTypeExpression) term).getTarget();
invocation = new MethodReferenceSpecifierInvocation(this, (Tree.MemberOrTypeExpression) term, primaryDeclaration, producedReference, method, specifierExpression);
} else if (!lazy && !inlined) {
// must be a callable we stored
String name = naming.getMethodSpecifierAttributeName(method);
invocation = new CallableSpecifierInvocation(this, method, naming.makeUnquotedIdent(name), term, term);
} else if (isCeylonCallableSubtype(term.getTypeModel())) {
invocation = new CallableSpecifierInvocation(this, method, expressionGen().transformExpression(term), term, term);
} else {
throw new BugException(term, "unhandled primary: " + term == null ? "null" : term.getNodeType());
}
invocation.handleBoxing(true);
invocation.setErased(CodegenUtil.hasTypeErased(term) || getReturnTypeOfCallable(term.getTypeModel()).isNothing());
bodyExpr = expressionGen().transformInvocation(invocation);
} else {
Substitution substitution = null;
JCStatement varDef = null;
// Handle implementations of Java variadic methods
Parameter lastParameter = Decl.getLastParameterFromFirstParameterList(model);
if (lastParameter != null && Decl.isJavaVariadicIncludingInheritance(lastParameter)) {
SyntheticName alias = naming.alias(lastParameter.getName());
substitution = naming.addVariableSubst(lastParameter.getModel(), alias.getName());
varDef = substituteSequentialForJavaVariadic(alias, lastParameter);
}
bodyExpr = expressionGen().transformExpression(model, term);
if (varDef != null) {
// Turn into Let for java variadic methods
bodyExpr = make().LetExpr(List.of(varDef), bodyExpr);
substitution.close();
}
// The innermost of an MPL method declared void needs to return null
returnNull = Decl.isUnboxedVoid(model) && Decl.isMpl(model);
}
if (CodegenUtil.downcastForSmall(term, model)) {
bodyExpr = expressionGen().applyErasureAndBoxing(bodyExpr, term.getTypeModel(), false, !CodegenUtil.isUnBoxed(term), CodegenUtil.getBoxingStrategy(model), model.getType(), ExpressionTransformer.EXPR_UNSAFE_PRIMITIVE_TYPECAST_OK);
}
List<JCStatement> body;
if (!Decl.isUnboxedVoid(model) || Decl.isMpl(model) || Strategy.useBoxedVoid(model)) {
if (returnNull) {
body = List.<JCStatement>of(make().Exec(bodyExpr), make().Return(makeNull()));
} else {
body = List.<JCStatement>of(make().Return(bodyExpr));
}
} else {
body = List.<JCStatement>of(make().Exec(bodyExpr));
}
return body;
}
use of org.eclipse.ceylon.model.typechecker.model.Functional in project ceylon by eclipse.
the class ClassTransformer method makeDelegateToCompanion.
/**
* Generates a method which delegates to the companion instance $Foo$impl
*/
private MethodDefinitionBuilder makeDelegateToCompanion(Interface iface, Reference typedMember, Type currentType, final long mods, final java.util.List<TypeParameter> typeParameters, final java.util.List<java.util.List<Type>> producedTypeParameterBounds, final Type methodType, final String methodName, final java.util.List<Parameter> parameters, boolean typeErased, final String targetMethodName, Parameter defaultedParam, boolean includeBody) {
final MethodDefinitionBuilder concreteWrapper = MethodDefinitionBuilder.systemMethod(gen(), methodName);
concreteWrapper.modifiers(mods);
concreteWrapper.ignoreModelAnnotations();
if ((mods & PRIVATE) == 0) {
concreteWrapper.isOverride(true);
}
if (typeParameters != null) {
concreteWrapper.reifiedTypeParametersFromModel(typeParameters);
}
Iterator<java.util.List<Type>> iterator = producedTypeParameterBounds.iterator();
if (typeParameters != null) {
for (TypeParameter tp : typeParameters) {
concreteWrapper.typeParameter(tp, iterator.next());
}
}
boolean explicitReturn = false;
Declaration member = (defaultedParam != null ? typedMember.getTypedParameter(defaultedParam) : typedMember).getDeclaration();
Type returnType = null;
if (!isAnything(methodType) || ((member instanceof Function || member instanceof Value) && !Decl.isUnboxedVoid(member)) || (member instanceof Function && Strategy.useBoxedVoid((Function) member))) {
explicitReturn = true;
if (CodegenUtil.isHashAttribute(member)) {
// delegates for hash attributes are int
concreteWrapper.resultType(new TransformedType(make().Type(syms().intType)));
returnType = typedMember.getType();
} else if (typedMember instanceof TypedReference && defaultedParam == null) {
TypedReference typedRef = (TypedReference) typedMember;
// This is very much like for method refinement: if the supertype is erased -> go raw.
// Except for some reason we only need to do it with multiple inheritance with different type
// arguments, so let's not go overboard
int flags = 0;
if (CodegenUtil.hasTypeErased((TypedDeclaration) member.getRefinedDeclaration()) || CodegenUtil.hasTypeErased((TypedDeclaration) member) && isInheritedTwiceWithDifferentTypeArguments(currentType, iface)) {
flags |= AbstractTransformer.JT_RAW;
}
concreteWrapper.resultTypeNonWidening(currentType, typedRef, typedMember.getType(), flags);
// FIXME: this is redundant with what we computed in the previous line in concreteWrapper.resultTypeNonWidening
TypedReference nonWideningTypedRef = gen().nonWideningTypeDecl(typedRef, currentType);
returnType = gen().nonWideningType(typedRef, nonWideningTypedRef);
} else if (defaultedParam != null) {
TypedReference typedParameter = typedMember.getTypedParameter(defaultedParam);
NonWideningParam nonWideningParam = concreteWrapper.getNonWideningParam(typedParameter, currentType.getDeclaration() instanceof Class ? WideningRules.FOR_MIXIN : WideningRules.NONE);
returnType = nonWideningParam.nonWideningType;
if (member instanceof Function)
returnType = typeFact().getCallableType(returnType);
concreteWrapper.resultType(new TransformedType(makeJavaType(returnType, nonWideningParam.flags)));
} else {
concreteWrapper.resultType(new TransformedType(makeJavaType((Type) typedMember)));
returnType = (Type) typedMember;
}
}
ListBuffer<JCExpression> arguments = new ListBuffer<JCExpression>();
if (typeParameters != null) {
for (TypeParameter tp : typeParameters) {
arguments.add(naming.makeUnquotedIdent(naming.getTypeArgumentDescriptorName(tp)));
}
}
Declaration declaration = typedMember.getDeclaration();
if (declaration instanceof Constructor && !Decl.isDefaultConstructor((Constructor) declaration) && defaultedParam == null) {
concreteWrapper.parameter(makeConstructorNameParameter((Constructor) declaration));
arguments.add(naming.makeUnquotedIdent(Unfix.$name$));
}
int ii = 0;
for (Parameter param : parameters) {
Parameter parameter;
if (declaration instanceof Functional) {
parameter = ((Functional) declaration).getFirstParameterList().getParameters().get(ii++);
} else if (declaration instanceof Setter) {
parameter = ((Setter) declaration).getParameter();
} else {
throw BugException.unhandledDeclarationCase(declaration);
}
final TypedReference typedParameter = typedMember.getTypedParameter(parameter);
concreteWrapper.parameter(null, param, typedParameter, null, FINAL, WideningRules.FOR_MIXIN);
arguments.add(naming.makeName(param.getModel(), Naming.NA_MEMBER | Naming.NA_ALIASED));
}
if (includeBody) {
JCExpression qualifierThis = makeUnquotedIdent(getCompanionFieldName(iface));
// our impl accessor to get the expected bounds of the qualifying type
if (explicitReturn) {
Type javaType = getBestSatisfiedType(currentType, iface);
Type ceylonType = typedMember.getQualifyingType();
// don't even bother if the impl accessor is turned to raw because casting it to raw doesn't help
if (!isTurnedToRaw(ceylonType) && // if it's exactly the same we don't need any cast
!javaType.isExactly(ceylonType))
// this will add the proper cast to the impl accessor
qualifierThis = expressionGen().applyErasureAndBoxing(qualifierThis, currentType, false, true, BoxingStrategy.BOXED, ceylonType, ExpressionTransformer.EXPR_WANTS_COMPANION);
}
JCExpression expr = make().Apply(// TODO Type args
null, makeSelect(qualifierThis, (targetMethodName != null) ? targetMethodName : methodName), arguments.toList());
if (isUnimplementedMemberClass(currentType, typedMember)) {
concreteWrapper.body(makeThrowUnresolvedCompilationError(// TODO encapsulate the error message
"formal member '" + declaration.getName() + "' of '" + iface.getName() + "' not implemented in class hierarchy"));
current().broken();
} else if (!explicitReturn) {
concreteWrapper.body(gen().make().Exec(expr));
} else {
// deal with erasure and stuff
BoxingStrategy boxingStrategy;
boolean exprBoxed;
if (member instanceof TypedDeclaration) {
TypedDeclaration typedDecl = (TypedDeclaration) member;
exprBoxed = !CodegenUtil.isUnBoxed(typedDecl);
boxingStrategy = CodegenUtil.getBoxingStrategy(typedDecl);
} else {
// must be a class or interface
exprBoxed = true;
boxingStrategy = BoxingStrategy.UNBOXED;
}
// to force an additional cast
if (isTurnedToRaw(typedMember.getQualifyingType()) || // in invariant locations
needsRawCastForMixinSuperCall(iface, methodType) || needsCastForErasedInstantiator(iface, methodName, member))
typeErased = true;
expr = gen().expressionGen().applyErasureAndBoxing(expr, methodType, typeErased, exprBoxed, boxingStrategy, returnType, 0);
concreteWrapper.body(gen().make().Return(expr));
}
}
return concreteWrapper;
}
use of org.eclipse.ceylon.model.typechecker.model.Functional in project ceylon by eclipse.
the class ExpressionTransformer method transformSuperInvocation.
//
// Invocations
public void transformSuperInvocation(Tree.ExtendedType extendedType, ClassDefinitionBuilder classBuilder) {
HasErrorException error = errors().getFirstExpressionErrorAndMarkBrokenness(extendedType);
if (error != null) {
classBuilder.getInitBuilder().delegateCall(this.makeThrowUnresolvedCompilationError(error));
return;
}
if (extendedType.getInvocationExpression() != null && extendedType.getInvocationExpression().getPositionalArgumentList() != null) {
Declaration primaryDeclaration = ((Tree.MemberOrTypeExpression) extendedType.getInvocationExpression().getPrimary()).getDeclaration();
java.util.List<ParameterList> paramLists = ((Functional) primaryDeclaration).getParameterLists();
if (paramLists.isEmpty()) {
classBuilder.getInitBuilder().delegateCall(at(extendedType).Exec(makeErroneous(extendedType, "compiler bug: missing parameter list in extends clause: " + primaryDeclaration.getName() + " must be invoked")));
} else {
boolean prevFnCall = withinInvocation(true);
try {
JCStatement superExpr = transformConstructorDelegation(extendedType, new CtorDelegation(null, primaryDeclaration), extendedType.getInvocationExpression(), classBuilder, false);
classBuilder.getInitBuilder().delegateCall(superExpr);
} finally {
withinInvocation(prevFnCall);
}
}
}
}
use of org.eclipse.ceylon.model.typechecker.model.Functional in project ceylon by eclipse.
the class ExpressionTransformer method transformExpression.
//
// Any sort of expression
JCExpression transformExpression(final TypedDeclaration declaration, final Tree.Term expr) {
// make sure we use the best declaration for boxing and type
TypedReference typedRef = getTypedReference(declaration);
TypedReference nonWideningTypedRef = nonWideningTypeDecl(typedRef);
Type nonWideningType = nonWideningType(typedRef, nonWideningTypedRef);
// the non-widening type of the innermost callable
if (declaration instanceof Functional && Decl.isMpl((Functional) declaration)) {
for (int i = ((Functional) declaration).getParameterLists().size(); i > 1; i--) {
nonWideningType = getReturnTypeOfCallable(nonWideningType);
}
}
// respect the refining definition of optionality
nonWideningType = propagateOptionality(declaration.getType(), nonWideningType);
BoxingStrategy boxing = CodegenUtil.getBoxingStrategy(nonWideningTypedRef.getDeclaration());
int flags = 0;
if (declaration.hasUncheckedNullType() || declaration == coercedFunctionalInterfaceNeedsNoNullChecks)
flags = ExpressionTransformer.EXPR_TARGET_ACCEPTS_NULL;
if (CodegenUtil.downcastForSmall(expr, declaration))
flags |= ExpressionTransformer.EXPR_UNSAFE_PRIMITIVE_TYPECAST_OK;
return transformExpression(expr, boxing, nonWideningType, flags);
}
Aggregations