use of org.eclipse.ceylon.model.typechecker.model.Declaration in project ceylon by eclipse.
the class ClassTransformer method needsCompanionDelegate.
private boolean needsCompanionDelegate(final Class model, Reference ref) {
final boolean mostRefined;
Declaration member = ref.getDeclaration();
java.util.List<Type> sig = getSignatureIfRequired(ref);
Declaration m = model.getMember(member.getName(), sig, false, true);
if (member instanceof Setter && Decl.isGetter(m)) {
mostRefined = member.equals(((Value) m).getSetter());
} else {
mostRefined = member.equals(m);
}
return mostRefined && (member.isDefault() || !member.isFormal());
}
use of org.eclipse.ceylon.model.typechecker.model.Declaration in project ceylon by eclipse.
the class ClassTransformer method addAmbiguousMembers.
private void addAmbiguousMembers(ClassDefinitionBuilder classBuilder, Interface model) {
// only if we refine more than one interface
java.util.List<Type> satisfiedTypes = model.getSatisfiedTypes();
if (satisfiedTypes.size() <= 1)
return;
Set<Interface> satisfiedInterfaces = new HashSet<Interface>();
for (Type interfaceDecl : model.getSatisfiedTypes()) {
collectInterfaces((Interface) interfaceDecl.getDeclaration(), satisfiedInterfaces);
}
Set<Interface> ambiguousInterfaces = new HashSet<Interface>();
for (Interface satisfiedInterface : satisfiedInterfaces) {
if (isInheritedWithDifferentTypeArguments(satisfiedInterface, model.getType()) != null) {
ambiguousInterfaces.add(satisfiedInterface);
}
}
Set<String> treated = new HashSet<String>();
for (Interface ambiguousInterface : ambiguousInterfaces) {
for (Declaration member : ambiguousInterface.getMembers()) {
String name = member.getName();
// skip if already handled
if (treated.contains(name))
continue;
// skip if it's implemented directly
if (model.getDirectMember(name, null, false) != null) {
treated.add(name);
continue;
}
// find if we have different implementations in two direct interfaces
LOOKUP: for (int i = 0; i < satisfiedTypes.size(); i++) {
Type firstInterface = satisfiedTypes.get(i);
Declaration member1 = firstInterface.getDeclaration().getMember(name, null, false);
// if we can't find it in this interface, move to the next
if (member1 == null)
continue;
// try to find member in other interfaces
for (int j = i + 1; j < satisfiedTypes.size(); j++) {
Type secondInterface = satisfiedTypes.get(j);
Declaration member2 = secondInterface.getDeclaration().getMember(name, null, false);
// if we can't find it in this interface, move to the next
if (member2 == null)
continue;
// we have it in two separate interfaces
Reference typedMember1 = firstInterface.getTypedReference(member1, Collections.<Type>emptyList());
Reference typedMember2 = secondInterface.getTypedReference(member2, Collections.<Type>emptyList());
Type type1 = simplifyType(typedMember1.getType());
Type type2 = simplifyType(typedMember2.getType());
if (!type1.isExactly(type2)) {
// treat it and stop looking for other interfaces
addAmbiguousMember(classBuilder, model, name);
break LOOKUP;
}
}
}
// that member has no conflict
treated.add(name);
}
}
}
use of org.eclipse.ceylon.model.typechecker.model.Declaration 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.Declaration in project ceylon by eclipse.
the class ClassTransformer method serializationReferences.
/**
* <p>Generates the {@code $deserialize$()} method to deserialize
* the classes state, which:</p>
* <ul>
* <li>invokes {@code super.$deserialize$()}, if the super class is also
* serializable,</li>
* <li>assigns each reified type argument in the
* class by invoking {@code dted.getTypeArgument()},</li>
* <li>assigns each field in the
* class by invoking {@code dted.getValue()}.</li>
* </ul>
*/
private void serializationReferences(Class model, ClassDefinitionBuilder classBuilder) {
MethodDefinitionBuilder mdb = MethodDefinitionBuilder.systemMethod(this, Unfix.$references$.toString());
mdb.isOverride(true);
mdb.ignoreModelAnnotations();
mdb.modifiers(PUBLIC);
mdb.resultType(new TransformedType(make().TypeApply(naming.makeQuotedFQIdent("java.util.Collection"), List.<JCExpression>of(make().Type(syms().ceylonReachableReferenceType))), null, makeAtNonNull()));
ListBuffer<JCStatement> stmts = new ListBuffer<JCStatement>();
// TODO this is all static information, but the method itself needs to be
// callable virtually, so we should cache it somehow.
SyntheticName r = naming.synthetic(Unfix.reference);
if (extendsSerializable(model)) {
// prepend the invocation of super.$serialize$()
stmts.add(makeVar(r, make().TypeApply(naming.makeQuotedFQIdent("java.util.Collection"), List.<JCExpression>of(make().Type(syms().ceylonReachableReferenceType))), make().Apply(null, naming.makeQualIdent(naming.makeSuper(), Unfix.$references$.toString()), List.<JCExpression>nil())));
} else {
stmts.add(makeVar(r, make().TypeApply(naming.makeQuotedFQIdent("java.util.Collection"), List.<JCExpression>of(make().Type(syms().ceylonReachableReferenceType))), make().NewClass(null, null, make().TypeApply(naming.makeQuotedFQIdent("java.util.ArrayList"), List.<JCExpression>of(make().Type(syms().ceylonReachableReferenceType))), List.<JCExpression>nil(), null)));
}
if (model.isMember()) {
JCExpressionStatement outer = make().Exec(make().Apply(null, naming.makeQualIdent(r.makeIdent(), "add"), List.<JCExpression>of(make().Apply(null, naming.makeQualIdent(make().Type(syms().ceylonOuterImplType), "get_"), List.<JCExpression>nil()))));
stmts.add(outer);
}
for (Declaration member : model.getMembers()) {
if (hasField(member)) {
// Obtain a ValueDeclaration
JCExpression valueDeclaration = expressionGen().makeMemberValueOrFunctionDeclarationLiteral(null, member, false);
// Create a MemberImpl
JCExpression mi = make().NewClass(null, null, make().QualIdent(syms().ceylonMemberImplType.tsym), List.of(valueDeclaration), null);
JCExpressionStatement attribute = make().Exec(make().Apply(null, naming.makeQualIdent(r.makeIdent(), "add"), List.of(mi)));
stmts.add(attribute);
}
}
stmts.add(make().Return(r.makeIdent()));
mdb.body(stmts.toList());
classBuilder.method(mdb);
}
use of org.eclipse.ceylon.model.typechecker.model.Declaration in project ceylon by eclipse.
the class ClassTransformer method transformRefinementSpecifierStatement.
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()) {
Tree.Term baseMemberTerm = op.getBaseMemberExpression();
if (baseMemberTerm instanceof Tree.ParameterizedExpression)
baseMemberTerm = ((Tree.ParameterizedExpression) baseMemberTerm).getPrimary();
Tree.BaseMemberExpression expr = (BaseMemberExpression) baseMemberTerm;
Declaration decl = expr.getDeclaration();
if (Decl.isValue(decl) || Decl.isGetter(decl)) {
// 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());
attrDecl.setSpecifierOrInitializerExpression(op.getSpecifierExpression());
attrDecl.setAnnotationList(makeShortcutRefinementAnnotationTrees());
// Make sure the boxing information is set correctly
BoxingDeclarationVisitor v = new CompilerBoxingDeclarationVisitor(this);
v.visit(attrDecl);
// Generate the attribute
transform(attrDecl, classBuilder);
} else if (decl instanceof Function) {
// Now build a "fake" declaration for the method
Tree.MethodDeclaration methDecl = new Tree.MethodDeclaration(null);
Function m = (Function) decl;
methDecl.setDeclarationModel(m);
methDecl.setIdentifier(expr.getIdentifier());
methDecl.setScope(op.getScope());
methDecl.setAnnotationList(makeShortcutRefinementAnnotationTrees());
Tree.SpecifierExpression specifierExpression = op.getSpecifierExpression();
methDecl.setSpecifierExpression(specifierExpression);
if (specifierExpression instanceof Tree.LazySpecifierExpression == false) {
Tree.Expression expression = specifierExpression.getExpression();
Tree.Term expressionTerm = Decl.unwrapExpressionsUntilTerm(expression);
// we can optimise lambdas and static method calls
if (!CodegenUtil.canOptimiseMethodSpecifier(expressionTerm, m)) {
// we need a field to save the callable value
String name = naming.getMethodSpecifierAttributeName(m);
JCExpression specifierType = makeJavaType(expression.getTypeModel());
JCExpression specifier = expressionGen().transformExpression(expression);
classBuilder.field(PRIVATE | FINAL, name, specifierType, specifier, false);
}
}
java.util.List<Tree.ParameterList> parameterListTrees = null;
if (op.getBaseMemberExpression() instanceof Tree.ParameterizedExpression) {
parameterListTrees = new ArrayList<>(m.getParameterLists().size());
parameterListTrees.addAll(((Tree.ParameterizedExpression) op.getBaseMemberExpression()).getParameterLists());
Tree.Term term = specifierExpression.getExpression().getTerm();
// and give it the given block of expr as it's specifier
while (term instanceof Tree.FunctionArgument && m.getParameterLists().size() > 1) {
FunctionArgument functionArgument = (Tree.FunctionArgument) term;
specifierExpression.setExpression(functionArgument.getExpression());
parameterListTrees.addAll(functionArgument.getParameterLists());
term = functionArgument.getExpression().getTerm();
}
}
int plIndex = 0;
// copy from formal declaration
for (ParameterList pl : m.getParameterLists()) {
Tree.ParameterList parameterListTree = null;
if (parameterListTrees != null)
parameterListTree = parameterListTrees.get(plIndex++);
Tree.ParameterList tpl = new Tree.ParameterList(null);
tpl.setModel(pl);
int pIndex = 0;
for (Parameter p : pl.getParameters()) {
Tree.Parameter parameterTree = null;
if (parameterListTree != null)
parameterTree = parameterListTree.getParameters().get(pIndex++);
Tree.Parameter tp = null;
if (p.getModel() instanceof Value) {
Tree.ValueParameterDeclaration tvpd = new Tree.ValueParameterDeclaration(null);
if (parameterTree != null)
tvpd.setTypedDeclaration(((Tree.ParameterDeclaration) parameterTree).getTypedDeclaration());
tvpd.setParameterModel(p);
tp = tvpd;
} else if (p.getModel() instanceof Function) {
Tree.FunctionalParameterDeclaration tfpd = new Tree.FunctionalParameterDeclaration(null);
if (parameterTree != null)
tfpd.setTypedDeclaration(((Tree.ParameterDeclaration) parameterTree).getTypedDeclaration());
tfpd.setParameterModel(p);
tp = tfpd;
} else {
throw BugException.unhandledDeclarationCase(p.getModel());
}
tp.setScope(p.getDeclaration().getContainer());
// tp.setIdentifier(makeIdentifier(p.getName()));
tpl.addParameter(tp);
}
methDecl.addParameterList(tpl);
}
// Make sure the boxing information is set correctly
BoxingDeclarationVisitor v = new CompilerBoxingDeclarationVisitor(this);
v.visit(methDecl);
// Generate the method
classBuilder.method(methDecl, Errors.GENERATE);
}
} else {
// Normal case, just generate the specifier statement
result = result.append(expressionGen().transform(op));
}
Tree.Term term = op.getBaseMemberExpression();
if (term instanceof Tree.BaseMemberExpression) {
Tree.BaseMemberExpression bme = (Tree.BaseMemberExpression) term;
DeferredSpecification ds = statementGen().getDeferredSpecification(bme.getDeclaration());
if (ds != null && needsInnerSubstitution(term.getScope(), bme.getDeclaration())) {
result = result.append(ds.openInnerSubstitution());
}
}
return result;
}
Aggregations