use of com.redhat.ceylon.model.typechecker.model.Parameter in project ceylon-compiler by ceylon.
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, DelegateType delegateType, 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 = 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(null, make().Type(syms().intType));
returnType = typedMember.getType();
} else if (typedMember instanceof TypedReference) {
TypedReference typedRef = (TypedReference) typedMember;
if (delegateType == DelegateType.OTHER) {
// 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 {
// for default value
NonWideningParam nonWideningParam = concreteWrapper.getNonWideningParam(typedRef, currentType.getDeclaration() instanceof Class ? WideningRules.FOR_MIXIN : WideningRules.NONE);
returnType = nonWideningParam.nonWideningType;
if (member instanceof Function)
returnType = typeFact().getCallableType(returnType);
concreteWrapper.resultType(null, makeJavaType(returnType, nonWideningParam.flags));
}
} else {
concreteWrapper.resultType(null, makeJavaType((Type) typedMember));
returnType = (Type) typedMember;
}
}
ListBuffer<JCExpression> arguments = ListBuffer.<JCExpression>lb();
if (typeParameters != null) {
for (TypeParameter tp : typeParameters) {
arguments.add(naming.makeUnquotedIdent(naming.getTypeArgumentDescriptorName(tp)));
}
}
if (typedMember.getDeclaration() instanceof Constructor && !Decl.isDefaultConstructor((Constructor) typedMember.getDeclaration())) {
concreteWrapper.parameter(makeConstructorNameParameter((Constructor) typedMember.getDeclaration()));
arguments.add(naming.makeUnquotedIdent(Unfix.$name$));
}
for (Parameter param : parameters) {
final TypedReference typedParameter = typedMember.getTypedParameter(param);
concreteWrapper.parameter(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 '" + typedMember.getDeclaration().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 com.redhat.ceylon.model.typechecker.model.Parameter in project ceylon-compiler by ceylon.
the class ClassTransformer method transformMethod.
private List<MethodDefinitionBuilder> transformMethod(final Function methodModel, Tree.TypeParameterList typeParameterList, Tree.AnyMethod node, java.util.List<Tree.ParameterList> parameterLists, Tree.Declaration annotated, boolean transformMethod, boolean actual, boolean includeAnnotations, List<JCStatement> body, DaoBody daoTransformation, boolean defaultValuesBody) {
ListBuffer<MethodDefinitionBuilder> lb = ListBuffer.<MethodDefinitionBuilder>lb();
Declaration refinedDeclaration = methodModel.getRefinedDeclaration();
final MethodDefinitionBuilder methodBuilder = MethodDefinitionBuilder.method(this, methodModel);
// do the reified type param arguments
if (gen().supportsReified(methodModel)) {
methodBuilder.reifiedTypeParameters(methodModel.getTypeParameters());
}
if (methodModel.getParameterLists().size() > 1) {
methodBuilder.mpl(methodModel.getParameterLists());
}
boolean hasOverloads = false;
Tree.ParameterList parameterList = parameterLists.get(0);
int flags = 0;
if (rawParameters(methodModel)) {
flags |= JT_RAW;
}
for (final Tree.Parameter parameter : parameterList.getParameters()) {
Parameter parameterModel = parameter.getParameterModel();
List<JCAnnotation> annotations = null;
if (includeAnnotations) {
Tree.TypedDeclaration typedDeclaration = Decl.getMemberDeclaration(annotated, parameter);
// f = function(Integer param) => 2;
if (typedDeclaration != null)
annotations = expressionGen().transformAnnotations(OutputElement.PARAMETER, typedDeclaration);
}
methodBuilder.parameter(parameterModel, annotations, flags, WideningRules.CAN_WIDEN);
if (Strategy.hasDefaultParameterValueMethod(parameterModel) || Strategy.hasDefaultParameterOverload(parameterModel)) {
if (Decl.equal(refinedDeclaration, methodModel) || (!Decl.withinInterface(methodModel) && body != null) || Decl.withinInterface(methodModel) && daoTransformation instanceof DaoCompanion == false) {
if (daoTransformation != null && (daoTransformation instanceof DaoCompanion == false || body != null)) {
DaoBody daoTrans = (body == null) ? daoAbstract : new DaoThis(node, parameterList);
MethodDefinitionBuilder overloadedMethod = new DefaultedArgumentMethod(daoTrans, MethodDefinitionBuilder.method(this, methodModel), methodModel).makeOverload(parameterList.getModel(), parameter.getParameterModel(), methodModel.getTypeParameters());
overloadedMethod.location(null);
lb.append(overloadedMethod);
}
if (Decl.equal(refinedDeclaration, methodModel) && Strategy.hasDefaultParameterValueMethod(parameterModel)) {
lb.append(makeParamDefaultValueMethod(defaultValuesBody, methodModel, parameterList, parameter));
}
}
hasOverloads = true;
}
}
// Determine if we need to generate a "canonical" method
boolean createCanonical = hasOverloads && Decl.withinClassOrInterface(methodModel) && body != null;
if (createCanonical) {
// Creates the private "canonical" method containing the actual body
MethodDefinitionBuilder canonicalMethod = new CanonicalMethod(daoTransformation, methodModel, body).makeOverload(parameterList.getModel(), null, methodModel.getTypeParameters());
lb.append(canonicalMethod);
}
if (transformMethod) {
methodBuilder.modifiers(transformMethodDeclFlags(methodModel));
if (actual) {
methodBuilder.isOverride(methodModel.isActual());
}
if (includeAnnotations) {
methodBuilder.userAnnotations(expressionGen().transformAnnotations(OutputElement.METHOD, annotated));
methodBuilder.modelAnnotations(methodModel.getAnnotations());
} else {
methodBuilder.ignoreModelAnnotations();
}
methodBuilder.resultType(methodModel, 0);
copyTypeParameters(methodModel, methodBuilder);
if (createCanonical) {
// Creates method that redirects to the "canonical" method containing the actual body
MethodDefinitionBuilder overloadedMethod = new CanonicalMethod(new DaoThis(node, parameterList), methodBuilder, methodModel).makeOverload(parameterList.getModel(), null, methodModel.getTypeParameters());
lb.append(overloadedMethod);
} else {
if (body != null) {
// Construct the outermost method using the body we've built so far
methodBuilder.body(body);
} else {
methodBuilder.noBody();
}
lb.append(methodBuilder);
}
}
return lb.toList();
}
use of com.redhat.ceylon.model.typechecker.model.Parameter in project ceylon-compiler by ceylon.
the class ClassTransformer method refineClass.
private Class refineClass(Scope container, Reference pr, ClassOrInterface classModel, Class formalClass, Unit unit) {
Class refined = new Class();
refined.setActual(true);
refined.setShared(formalClass.isShared());
refined.setContainer(container);
refined.setExtendedType(formalClass.getType());
refined.setDeprecated(formalClass.isDeprecated());
refined.setName(formalClass.getName());
refined.setRefinedDeclaration(formalClass.getRefinedDeclaration());
refined.setScope(container);
//refined.setType(pr.getType());
refined.setUnit(unit);
for (ParameterList formalPl : formalClass.getParameterLists()) {
ParameterList refinedPl = new ParameterList();
for (Parameter formalP : formalPl.getParameters()) {
Parameter refinedP = new Parameter();
refinedP.setAtLeastOne(formalP.isAtLeastOne());
refinedP.setDeclaration(refined);
refinedP.setDefaulted(formalP.isDefaulted());
refinedP.setDeclaredAnything(formalP.isDeclaredAnything());
refinedP.setHidden(formalP.isHidden());
refinedP.setSequenced(formalP.isSequenced());
refinedP.setName(formalP.getName());
final TypedReference typedParameter = pr.getTypedParameter(formalP);
FunctionOrValue paramModel;
if (formalP.getModel() instanceof Value) {
Value paramValueModel = refineValue((Value) formalP.getModel(), typedParameter, refined, classModel.getUnit());
paramValueModel.setInitializerParameter(refinedP);
paramModel = paramValueModel;
} else {
Function paramFunctionModel = refineMethod(refined, typedParameter, classModel, (Function) formalP.getModel(), unit);
paramFunctionModel.setInitializerParameter(refinedP);
paramModel = paramFunctionModel;
}
refinedP.setModel(paramModel);
refinedPl.getParameters().add(refinedP);
}
refined.addParameterList(refinedPl);
}
return refined;
}
use of com.redhat.ceylon.model.typechecker.model.Parameter in project ceylon-compiler by ceylon.
the class ClassTransformer method transformMethodBody.
private List<JCStatement> transformMethodBody(Tree.AnyMethod def) {
List<JCStatement> body = null;
final Function model = def.getDeclarationModel();
if (model.isDeferred()) {
// Uninitialized or deferred initialized method => Make a Callable field
String fieldName = naming.selector(model);
final Parameter initializingParameter = CodegenUtil.findParamForDecl(def);
int mods = PRIVATE;
JCExpression initialValue;
if (initializingParameter != null) {
mods |= FINAL;
initialValue = makeUnquotedIdent(Naming.getAliasedParameterName(initializingParameter));
} else {
// The field isn't initialized by a parameter, but later in the block
initialValue = makeNull();
}
Type callableType = model.getReference().getFullType();
current().field(mods, fieldName, makeJavaType(callableType), initialValue, false);
Invocation invocation = new CallableSpecifierInvocation(this, model, makeUnquotedIdent(fieldName), // but with deferred methods we can't define them so that they are erased so we're good
null, def);
invocation.handleBoxing(true);
JCExpression call = expressionGen().transformInvocation(invocation);
JCStatement stmt;
if (!isVoid(def) || !Decl.isUnboxedVoid(model) || Strategy.useBoxedVoid((Function) model)) {
stmt = make().Return(call);
} else {
stmt = make().Exec(call);
}
JCStatement result;
if (initializingParameter == null) {
// If the field isn't initialized by a parameter we have to
// cope with the possibility that it's never initialized
final JCBinary cond = make().Binary(JCTree.EQ, makeUnquotedIdent(fieldName), makeNull());
final JCStatement throw_ = make().Throw(make().NewClass(null, null, makeIdent(syms().ceylonUninitializedMethodErrorType), List.<JCExpression>nil(), null));
result = make().If(cond, throw_, stmt);
} else {
result = stmt;
}
return List.<JCStatement>of(result);
} else if (def instanceof Tree.MethodDefinition) {
body = transformMethodBlock((Tree.MethodDefinition) def);
} else if (def instanceof MethodDeclaration && ((MethodDeclaration) def).getSpecifierExpression() != null) {
body = transformSpecifiedMethodBody((MethodDeclaration) def, ((MethodDeclaration) def).getSpecifierExpression());
}
return body;
}
use of com.redhat.ceylon.model.typechecker.model.Parameter in project ceylon-compiler by ceylon.
the class ClassTransformer method makeParamDefaultValueMethod.
/**
* Creates a (possibly abstract) method for retrieving the value for a
* defaulted parameter
* @param typeParameterList
*/
MethodDefinitionBuilder makeParamDefaultValueMethod(boolean noBody, Declaration container, Tree.ParameterList params, Tree.Parameter currentParam) {
at(currentParam);
Parameter parameter = currentParam.getParameterModel();
if (!Strategy.hasDefaultParameterValueMethod(parameter)) {
throw new BugException();
}
MethodDefinitionBuilder methodBuilder = MethodDefinitionBuilder.systemMethod(this, Naming.getDefaultedParamMethodName(container, parameter));
methodBuilder.ignoreModelAnnotations();
if (container != null && Decl.isAnnotationConstructor(container)) {
AnnotationInvocation ac = (AnnotationInvocation) ((Function) container).getAnnotationConstructor();
for (AnnotationConstructorParameter acp : ac.getConstructorParameters()) {
if (acp.getParameter().equals(parameter) && acp.getDefaultArgument() != null) {
methodBuilder.userAnnotations(acp.getDefaultArgument().makeDpmAnnotations(expressionGen()));
}
}
}
int modifiers = 0;
if (noBody) {
modifiers |= PUBLIC | ABSTRACT;
} else if (container == null || !(container instanceof Class && Strategy.defaultParameterMethodStatic(container))) {
// initializers can override parameter defaults
modifiers |= FINAL;
}
if (container != null && container.isShared()) {
modifiers |= PUBLIC;
} else if (container == null || (!container.isToplevel() && !noBody)) {
modifiers |= PRIVATE;
}
boolean staticMethod = Strategy.defaultParameterMethodStatic(container);
if (staticMethod) {
// static default parameter methods should be consistently public so that if non-shared class Top and
// shared class Bottom which extends Top both have the same default param name, we don't get an error
// if the Bottom class tries to "hide" a static public method with a private one
modifiers &= ~PRIVATE;
modifiers |= STATIC | PUBLIC;
}
methodBuilder.modifiers(modifiers);
if (container instanceof Constructor) {
copyTypeParameters((Class) container.getContainer(), methodBuilder);
methodBuilder.reifiedTypeParameters(((Class) container.getContainer()).getTypeParameters());
} else if (container instanceof Generic) {
// make sure reified type parameters are accepted
copyTypeParameters((Generic) container, methodBuilder);
methodBuilder.reifiedTypeParameters(((Generic) container).getTypeParameters());
}
WideningRules wideningRules = !staticMethod && container instanceof Class ? WideningRules.CAN_WIDEN : WideningRules.NONE;
// Add any of the preceding parameters as parameters to the method
for (Tree.Parameter p : params.getParameters()) {
if (p.equals(currentParam)) {
break;
}
at(p);
methodBuilder.parameter(p.getParameterModel(), null, 0, wideningRules);
}
// The method's return type is the same as the parameter's type
NonWideningParam nonWideningParam = methodBuilder.getNonWideningParam(currentParam.getParameterModel().getModel(), wideningRules);
methodBuilder.resultType(nonWideningParam.nonWideningDecl, nonWideningParam.nonWideningType, nonWideningParam.flags);
// The implementation of the method
if (noBody) {
methodBuilder.noBody();
} else {
HasErrorException error = errors().getFirstExpressionErrorAndMarkBrokenness(Decl.getDefaultArgument(currentParam).getExpression());
if (error != null) {
methodBuilder.body(this.makeThrowUnresolvedCompilationError(error));
} else {
java.util.List<TypeParameter> copiedTypeParameters = null;
if (container instanceof Generic) {
copiedTypeParameters = ((Generic) container).getTypeParameters();
if (copiedTypeParameters != null)
addTypeParameterSubstitution(copiedTypeParameters);
}
try {
JCExpression expr = expressionGen().transform(currentParam);
JCBlock body = at(currentParam).Block(0, List.<JCStatement>of(at(currentParam).Return(expr)));
methodBuilder.block(body);
} finally {
if (copiedTypeParameters != null)
popTypeParameterSubstitution();
}
}
}
return methodBuilder;
}
Aggregations