use of org.eclipse.ceylon.model.typechecker.model.Declaration in project ceylon by eclipse.
the class ExpressionTransformer method transform.
public JCTree transform(Tree.MemberLiteral expr) {
at(expr);
Declaration declaration = expr.getDeclaration();
if (declaration == null)
return makeErroneous(expr, "compiler bug: missing declaration");
if (declaration.isToplevel()) {
return makeTopLevelValueOrFunctionLiteral(expr);
} else if (expr.getWantsDeclaration()) {
return makeMemberValueOrFunctionDeclarationLiteral(expr, declaration);
} else {
// get its produced ref
Reference producedReference = expr.getTarget();
// it's a member we get from its container type
Type containerType = producedReference.getQualifyingType();
// if we have no container type it means we have an object member
boolean objectMember = containerType.getDeclaration().isAnonymous();
JCExpression memberCall;
if (objectMember) {
// We don't care about the type args for the cast, nor for the reified container expr, because
// we take the real reified container type from the container instance, and that one has the type
// arguments
containerType = ((Class) declaration.getContainer()).getType();
}
JCExpression typeCall = makeTypeLiteralCall(containerType, false, expr.getTypeModel());
// make sure we cast it to ClassOrInterface
String metatypeName;
if (Decl.isConstructor(declaration)) {
Class constructedClass = ModelUtil.getConstructedClass(declaration);
Declaration container = getDeclarationContainer(constructedClass);
if (constructedClass.isToplevel() || container instanceof TypeDeclaration == false) {
metatypeName = "Class";
} else {
metatypeName = "MemberClass";
}
} else {
metatypeName = "ClassOrInterface";
}
TypeDeclaration classOrInterfaceDeclaration = (TypeDeclaration) typeFact().getLanguageModuleModelDeclaration(metatypeName);
JCExpression classOrInterfaceTypeExpr = makeJavaType(classOrInterfaceDeclaration.appliedReference(null, Arrays.asList(containerType)).getType());
typeCall = make().TypeCast(classOrInterfaceTypeExpr, typeCall);
// we will need a TD for the container
// Note that we don't use Basic for the container for object members, because that's not how we represent
// anonymous types.
JCExpression reifiedContainerExpr = makeReifiedTypeArgument(containerType);
// make a raw call and cast
if (Decl.isConstructor(declaration)) {
Type callableType = producedReference.getFullType();
/*JCExpression reifiedArgumentsExpr;
if (Decl.isEnumeratedConstructor(Decl.getConstructor(declaration))) {
reifiedArgumentsExpr = makeReifiedTypeArgument(typeFact().getCallableTuple(callableType.getQualifyingType()));
} else {
reifiedArgumentsExpr = makeReifiedTypeArgument(typeFact().getCallableTuple(callableType));
}*/
JCExpression reifiedArguments;
if (ModelUtil.isEnumeratedConstructor(ModelUtil.getConstructor(declaration))) {
reifiedArguments = makeReifiedTypeArgument(typeFact().getNothingType());
} else {
reifiedArguments = makeReifiedTypeArgument(typeFact().getCallableTuple(callableType));
}
List<JCExpression> arguments = List.of(reifiedArguments, ceylonLiteral(declaration.getName()));
JCExpression classModel = makeSelect(typeCall, "getDeclaredConstructor");
memberCall = make().Apply(null, classModel, arguments);
} else if (declaration instanceof Function) {
// we need to get types for each type argument
JCExpression closedTypesExpr = null;
if (expr.getTypeArgumentList() != null) {
java.util.List<Type> typeModels = expr.getTypeArgumentList().getTypeModels();
if (typeModels != null) {
closedTypesExpr = getClosedTypesSequential(typeModels);
}
}
// we also need type descriptors for ret and args
Type callableType = producedReference.getFullType();
JCExpression reifiedReturnTypeExpr = makeReifiedTypeArgument(typeFact().getCallableReturnType(callableType));
JCExpression reifiedArgumentsExpr = makeReifiedTypeArgument(typeFact().getCallableTuple(callableType));
List<JCExpression> arguments;
if (closedTypesExpr != null)
arguments = List.of(reifiedContainerExpr, reifiedReturnTypeExpr, reifiedArgumentsExpr, ceylonLiteral(declaration.getName()), closedTypesExpr);
else
arguments = List.of(reifiedContainerExpr, reifiedReturnTypeExpr, reifiedArgumentsExpr, ceylonLiteral(declaration.getName()));
memberCall = make().Apply(null, makeSelect(typeCall, "getMethod"), arguments);
} else if (declaration instanceof Value) {
JCExpression reifiedGetExpr = makeReifiedTypeArgument(producedReference.getType());
String getterName = "getAttribute";
Type ptype;
if (!((Value) declaration).isVariable())
ptype = typeFact().getNothingType();
else
ptype = producedReference.getType();
JCExpression reifiedSetExpr = makeReifiedTypeArgument(ptype);
memberCall = make().Apply(null, makeSelect(typeCall, getterName), List.of(reifiedContainerExpr, reifiedGetExpr, reifiedSetExpr, ceylonLiteral(declaration.getName())));
} else {
return makeErroneous(expr, "Unsupported member type: " + declaration);
}
// if(objectMember){
// // now get the instance and bind it
// // I don't think we need any expected type since objects can't be erased
// JCExpression object = transformExpression(expr.getObjectExpression());
// // reset the location after we transformed the expression
// memberCall = at(expr).Apply(null, makeSelect(memberCall, "bind"), List.of(object));
// }
// cast the member call because we invoke it with no Java generics
memberCall = make().TypeCast(makeJavaType(expr.getTypeModel(), JT_RAW | JT_NO_PRIMITIVES), memberCall);
memberCall = make().TypeCast(makeJavaType(expr.getTypeModel(), JT_NO_PRIMITIVES), memberCall);
return memberCall;
}
}
use of org.eclipse.ceylon.model.typechecker.model.Declaration in project ceylon by eclipse.
the class ExpressionTransformer method addThisOrObjectQualifierIfRequired.
/**
* We may need to force a qualified this prefix (direct or outer) in the following cases:
*
* - Required because of mixin inheritance with different type arguments (the same is already
* done for qualified references, but not for direct references)
* - The compiler generates anonymous local classes for things like
* Callables and Comprehensions. When referring to a member foo
* within one of those things we need a qualified {@code this}
* to ensure we're accessing the outer instances member, not
* a member of the anonymous local class that happens to have the same name.
*/
private JCExpression addThisOrObjectQualifierIfRequired(JCExpression qualExpr, Tree.StaticMemberOrTypeExpression expr, Declaration decl) {
// find out the real target
Declaration typeDecl;
if (Decl.isConstructor(decl))
typeDecl = ModelUtil.getConstructedClass(decl);
else
typeDecl = decl;
if (qualExpr == null && // statics are not members that can be inherited
!decl.isStatic() && (!Decl.isConstructor(decl) || !Decl.isConstructor(typeDecl)) && typeDecl.isMember() && // and have a name mapping)
expr.getTarget().getDeclaration() == decl && !ModelUtil.isLocalToInitializer(typeDecl) && !isWithinSuperInvocation()) {
// First check whether the expression is captured from an enclosing scope
TypeDeclaration outer = Decl.getOuterScopeOfMemberInvocation(expr, typeDecl);
if (outer != null) {
Type targetType = expr.getTarget().getQualifyingType();
Type declarationContainerType = ((TypeDeclaration) outer).getType();
// check if we need a variance cast
VarianceCastResult varianceCastResult = getVarianceCastResult(targetType, declarationContainerType);
// if we are within a comprehension body, or if we need a variance cast
if (isWithinSyntheticClassBody() || varianceCastResult != null) {
if (decl.isShared() && outer instanceof Interface) {
// always prefer qualified
qualExpr = makeQualifiedDollarThis(declarationContainerType);
} else {
// Class or companion class,
qualExpr = naming.makeQualifiedThis(makeJavaType(((TypeDeclaration) outer).getType(), JT_RAW | (outer instanceof Interface ? JT_COMPANION : 0)));
}
// add the variance cast if required
if (varianceCastResult != null) {
qualExpr = applyVarianceCasts(qualExpr, targetType, varianceCastResult, 0);
}
}
} else if (typeDecl.isClassOrInterfaceMember()) {
ClassOrInterface container;
if (((ClassOrInterface) typeDecl.getContainer()).isAnonymous() && ((ClassOrInterface) typeDecl.getContainer()).isToplevel()) {
// easy
container = (Class) typeDecl.getContainer();
} else {
// find the import
Import foundImport = statementGen().findImport(expr, decl);
container = (Class) foundImport.getTypeDeclaration();
}
Value value = (Value) ((Package) container.getContainer()).getMember(container.getName(), null, false);
qualExpr = make().Apply(null, naming.makeName(value, Naming.NA_FQ | Naming.NA_WRAPPER | Naming.NA_MEMBER), List.<JCExpression>nil());
} else if (decl.isMember() && !expr.getStaticMethodReference()) {
throw new BugException(expr, decl.getQualifiedNameString() + " was unexpectedly a member");
}
}
return qualExpr;
}
use of org.eclipse.ceylon.model.typechecker.model.Declaration in project ceylon by eclipse.
the class ExpressionTransformer method transformTypeArguments.
private final void transformTypeArguments(CallBuilder callBuilder, Tree.StaticMemberOrTypeExpression mte) {
java.util.List<TypeParameter> tps = null;
Declaration declaration = mte.getDeclaration();
if (!mte.getTypeModel().isTypeConstructor()) {
tps = Strategy.getEffectiveTypeParameters(declaration);
} else {
for (TypeParameter tp : Strategy.getEffectiveTypeParameters(declaration)) {
callBuilder.typeArgument(makeJavaType(tp.getType(), JT_TYPE_ARGUMENT));
}
return;
}
if (tps != null) {
for (TypeParameter tp : tps) {
Type ta = mte.getTarget().getTypeArguments().get(tp);
java.util.List<Type> bounds = null;
boolean needsCastForBounds = false;
if (!tp.getSatisfiedTypes().isEmpty()) {
bounds = new ArrayList<Type>(tp.getSatisfiedTypes().size());
for (Type bound : tp.getSatisfiedTypes()) {
// substitute the right type arguments
bound = substituteTypeArgumentsForTypeParameterBound(mte.getTarget(), bound);
bounds.add(bound);
needsCastForBounds |= needsCast(ta, bound, false, false, false);
}
}
boolean hasMultipleBounds;
Type firstBound;
if (bounds != null) {
hasMultipleBounds = bounds.size() > 1;
firstBound = bounds.isEmpty() ? null : bounds.get(0);
} else {
hasMultipleBounds = false;
firstBound = null;
}
if (willEraseToObject(ta) || needsCastForBounds) {
boolean boundsSelfDependent = isBoundsSelfDependant(tp);
if (hasDependentTypeParameters(tps, tp) || // and we cannot represent the intersection type in Java so give up
hasMultipleBounds || // if we are going to use the first bound and it is self-dependent, we will make it raw
boundsSelfDependent || (firstBound != null && willEraseToObject(firstBound))) {
// so at some point we'll have to introduce an intersection type AST node to satisfy multiple bounds
if (hasMultipleBounds) {
callBuilder.typeArguments(List.<JCExpression>nil());
return;
}
// if we have a bound
if (firstBound != null) {
// if it's self-dependent we cannot satisfy it without a raw type
if (boundsSelfDependent)
callBuilder.typeArgument(makeJavaType(firstBound, JT_TYPE_ARGUMENT | JT_RAW));
else
callBuilder.typeArgument(makeJavaType(firstBound, JT_TYPE_ARGUMENT));
} else {
// no bound, let's go with Object then
callBuilder.typeArgument(makeJavaType(typeFact().getObjectType(), JT_TYPE_ARGUMENT));
}
} else if (firstBound == null) {
callBuilder.typeArgument(makeJavaType(ta, JT_TYPE_ARGUMENT));
} else {
callBuilder.typeArgument(makeJavaType(firstBound, JT_TYPE_ARGUMENT));
}
} else {
callBuilder.typeArgument(makeJavaType(ta, JT_TYPE_ARGUMENT));
}
}
}
}
use of org.eclipse.ceylon.model.typechecker.model.Declaration in project ceylon by eclipse.
the class ExpressionTransformer method transformConstructorDelegation.
/**
* Transform a delegated constructor call ({@code extends XXX()})
* which may be either a superclass initializer/constructor or a
* same-class constructor.
* @param extendedType
* @param delegation The kind of delegation
* @param invocation
* @param classBuilder
* @return
*/
JCStatement transformConstructorDelegation(Node extendedType, CtorDelegation delegation, Tree.InvocationExpression invocation, ClassDefinitionBuilder classBuilder, boolean forDelegationConstructor) {
if (delegation != null && delegation.isError()) {
return delegation.makeThrow(this);
}
Declaration primaryDeclaration = ((Tree.MemberOrTypeExpression) invocation.getPrimary()).getDeclaration();
java.util.List<ParameterList> paramLists = ((Functional) primaryDeclaration).getParameterLists();
if (paramLists.isEmpty()) {
classBuilder.getInitBuilder().delegateCall(at(extendedType).Exec(makeErroneous(extendedType, "compiler bug: super class " + primaryDeclaration.getName() + " is missing parameter list")));
return null;
}
SuperInvocation builder = new SuperInvocation(this, classBuilder.getForDefinition(), delegation, invocation, paramLists.get(0), forDelegationConstructor);
CallBuilder callBuilder = CallBuilder.instance(this);
boolean prevFnCall = withinInvocation(true);
try {
if (invocation.getPrimary() instanceof Tree.StaticMemberOrTypeExpression) {
transformTypeArguments(callBuilder, (Tree.StaticMemberOrTypeExpression) invocation.getPrimary());
}
at(builder.getNode());
JCExpression expr = null;
Scope outerDeclaration;
if (Decl.isConstructor(primaryDeclaration)) {
outerDeclaration = builder.getPrimaryDeclaration().getContainer().getContainer();
} else {
outerDeclaration = builder.getPrimaryDeclaration().getContainer();
}
if ((Strategy.generateInstantiator(builder.getPrimaryDeclaration()) || builder.getPrimaryDeclaration() instanceof Class) && outerDeclaration instanceof Interface && !((Interface) outerDeclaration).isJava()) {
// If the subclass is inner to an interface then it will be
// generated inner to the companion and we need to qualify the
// super(), *unless* the subclass is nested within the same
// interface as it's superclass.
Scope outer = builder.getSub().getContainer();
while (!(outer instanceof Package)) {
if (outer == outerDeclaration) {
expr = naming.makeSuper();
break;
}
outer = outer.getContainer();
}
if (expr == null) {
if (delegation.isSelfDelegation()) {
throw new BugException();
}
Interface iface = (Interface) outerDeclaration;
JCExpression superQual;
if (ModelUtil.getClassOrInterfaceContainer(classBuilder.getForDefinition(), false) instanceof Interface) {
superQual = naming.makeCompanionAccessorCall(naming.makeQuotedThis(), iface);
} else {
superQual = naming.makeCompanionFieldName(iface);
}
expr = naming.makeQualifiedSuper(superQual);
}
} else {
expr = delegation.isSelfDelegation() ? naming.makeThis() : naming.makeSuper();
}
final List<JCExpression> superArguments = transformSuperInvocationArguments(classBuilder, builder, callBuilder);
JCExpression superExpr = callBuilder.invoke(expr).arguments(superArguments).build();
return at(extendedType).Exec(superExpr);
// classBuilder.getInitBuilder().superCall(at(extendedType).Exec(superExpr));
} finally {
withinInvocation(prevFnCall);
}
}
use of org.eclipse.ceylon.model.typechecker.model.Declaration in project ceylon by eclipse.
the class EeVisitor method visit.
@Override
public void visit(Tree.Declaration that) {
super.visit(that);
Declaration a = that.getDeclarationModel();
if (that.getAnnotationList() != null && that.getAnnotationList().getAnnotations() != null) {
for (Tree.Annotation an : that.getAnnotationList().getAnnotations()) {
Declaration ad = ((Tree.BaseMemberOrTypeExpression) an.getPrimary()).getDeclaration();
if (ad != null) {
String qualifiedName = ad.getQualifiedNameString();
if ("java.lang::transient".equals(qualifiedName)) {
setModifier(a, TRANSIENT);
}
if ("java.lang::volatile".equals(qualifiedName)) {
setModifier(a, VOLATILE);
}
if ("java.lang::synchronized".equals(qualifiedName)) {
setModifier(a, SYNCHRONIZED);
}
if ("java.lang::strictfp".equals(qualifiedName)) {
setModifier(a, STRICTFP);
}
// note: native is handledby the typechecker
}
}
}
}
Aggregations