use of com.redhat.ceylon.model.typechecker.model.Interface in project ceylon-compiler by ceylon.
the class ExpressionTransformer method getVarianceCastResult.
private VarianceCastResult getVarianceCastResult(Type expectedType, Type exprType) {
// exactly the same type, doesn't need casting
if (expectedType == null || exprType.isExactly(expectedType))
return null;
// if we're not trying to put it into an interface, there's no need
if (!(expectedType.getDeclaration() instanceof Interface))
return null;
// the interface must have type arguments, otherwise we can't use raw types
if (expectedType.getTypeArguments().isEmpty())
return null;
// see if any of those type arguments has variance
boolean hasVariance = false;
for (TypeParameter t : expectedType.getTypeArguments().keySet()) {
if (expectedType.isContravariant(t) || expectedType.isCovariant(t)) {
hasVariance = true;
break;
}
}
if (!hasVariance)
return null;
// see if we're inheriting the interface twice with different type parameters
java.util.List<Type> satisfiedTypes = new LinkedList<Type>();
for (Type superType : simplifyType(exprType).getSupertypes()) {
if (Decl.equal(superType.getDeclaration(), expectedType.getDeclaration()))
satisfiedTypes.add(superType);
}
// discard the supertypes that have the same erasure
for (int i = 0; i < satisfiedTypes.size(); i++) {
Type pt = satisfiedTypes.get(i);
for (int j = i + 1; j < satisfiedTypes.size(); j++) {
Type other = satisfiedTypes.get(j);
if (pt.isExactly(other) || haveSameErasure(pt, other)) {
satisfiedTypes.remove(j);
break;
}
}
}
// we need at least two instantiations
if (satisfiedTypes.size() <= 1)
return null;
boolean needsCast = false;
// we need at least one that differs
for (Type superType : satisfiedTypes) {
if (!exprType.isExactly(superType)) {
needsCast = true;
break;
}
}
// no cast needed if they are all the same type
if (!needsCast)
return null;
// find the better cast match
for (Type superType : satisfiedTypes) {
if (expectedType.isExactly(superType))
return new VarianceCastResult(superType);
}
// nothing better than a raw cast (Stef: not sure that can happen)
return RawCastVarianceResult;
}
use of com.redhat.ceylon.model.typechecker.model.Interface in project ceylon-compiler by ceylon.
the class ExpressionTransformer method makeMemberValueOrFunctionDeclarationLiteral.
JCExpression makeMemberValueOrFunctionDeclarationLiteral(Node node, Declaration declaration, boolean f) {
// it's a member we get from its container declaration
if (declaration.getContainer() instanceof ClassOrInterface == false)
return makeErroneous(node, "compiler bug: " + declaration.getContainer() + " is not a supported type parameter container");
ClassOrInterface container = (ClassOrInterface) declaration.getContainer();
// use the generated class to get to the declaration literal
JCExpression metamodelCall = makeTypeDeclarationLiteral(container);
JCExpression metamodelCast = makeJavaType(typeFact().getLanguageModuleDeclarationTypeDeclaration(Decl.isConstructor(declaration) ? "ClassDeclaration" : "ClassOrInterfaceDeclaration").getType(), JT_NO_PRIMITIVES);
metamodelCall = make().TypeCast(metamodelCast, metamodelCall);
String memberClassName;
String memberAccessor;
if (declaration instanceof Class)
memberClassName = "ClassDeclaration";
else if (Decl.isConstructor(declaration))
memberClassName = "ConstructorDeclaration";
else if (declaration instanceof Interface)
memberClassName = "InterfaceDeclaration";
else if (declaration instanceof Function)
memberClassName = "FunctionDeclaration";
else if (declaration instanceof Value) {
memberClassName = "ValueDeclaration";
} else {
return makeErroneous(node, "compiler bug: " + declaration + " is not a supported declaration literal");
}
if (Decl.isConstructor(declaration))
memberAccessor = "getConstructorDeclaration";
else
memberAccessor = f ? "getMemberDeclaration" : "getDeclaredMemberDeclaration";
TypeDeclaration metamodelDecl = (TypeDeclaration) typeFact().getLanguageModuleDeclarationDeclaration(memberClassName);
JCExpression memberType = makeJavaType(metamodelDecl.getType());
JCExpression reifiedMemberType = makeReifiedTypeArgument(metamodelDecl.getType());
JCExpression memberCall = make().Apply(List.of(memberType), makeSelect(metamodelCall, memberAccessor), List.of(reifiedMemberType, ceylonLiteral(declaration.getName())));
return memberCall;
}
use of com.redhat.ceylon.model.typechecker.model.Interface in project ceylon-compiler by ceylon.
the class ExpressionTransformer method transform.
// Postfix operator
public JCExpression transform(Tree.PostfixOperatorExpression expr) {
OperatorTranslation operator = Operators.getOperator(expr.getClass());
if (operator == null) {
return makeErroneous(expr, "compiler bug " + expr.getNodeType() + " is not yet supported");
}
OptimisationStrategy optimisationStrategy = operator.getUnOpOptimisationStrategy(expr, expr.getTerm(), this);
boolean canOptimise = optimisationStrategy.useJavaOperator();
// only fully optimise if we don't have to access the getter/setter
if (canOptimise && CodegenUtil.isDirectAccessVariable(expr.getTerm())) {
JCExpression term = transformExpression(expr.getTerm(), BoxingStrategy.UNBOXED, expr.getTypeModel(), EXPR_WIDEN_PRIM);
return at(expr).Unary(operator.javacOperator, term);
}
Tree.Term term = unwrapExpressionUntilTerm(expr.getTerm());
Interface compoundType = expr.getUnit().getOrdinalDeclaration();
Type valueType = getSupertype(expr.getTerm(), compoundType);
Type returnType = getMostPreciseType(term, getTypeArgument(valueType, 0));
List<JCVariableDecl> decls = List.nil();
List<JCStatement> stats = List.nil();
JCExpression result = null;
// we can optimise that case a bit sometimes
boolean boxResult = !canOptimise;
// (let $tmp = attr; attr = $tmp.getSuccessor(); $tmp;)
if (term instanceof Tree.BaseMemberExpression || // special case for java statics Foo.attr where Foo does not need to be evaluated
(term instanceof Tree.QualifiedMemberExpression && ((Tree.QualifiedMemberExpression) term).getStaticMethodReference())) {
JCExpression getter;
if (term instanceof Tree.BaseMemberExpression)
getter = transform((Tree.BaseMemberExpression) term, null);
else
getter = transformMemberExpression((Tree.QualifiedMemberExpression) term, null, null);
at(expr);
// Type $tmp = attr
JCExpression exprType = makeJavaType(returnType, boxResult ? JT_NO_PRIMITIVES : 0);
Name varName = naming.tempName("op");
// make sure we box the results if necessary
getter = applyErasureAndBoxing(getter, term, boxResult ? BoxingStrategy.BOXED : BoxingStrategy.UNBOXED, returnType);
JCVariableDecl tmpVar = make().VarDef(make().Modifiers(0), varName, exprType, getter);
decls = decls.prepend(tmpVar);
// attr = $tmp.getSuccessor()
JCExpression successor;
if (canOptimise) {
// use +1/-1 if we can optimise a bit
successor = make().Binary(operator == OperatorTranslation.UNARY_POSTFIX_INCREMENT ? JCTree.PLUS : JCTree.MINUS, make().Ident(varName), makeInteger(1));
successor = unAutoPromote(successor, returnType);
} else {
successor = make().Apply(null, makeSelect(make().Ident(varName), operator.ceylonMethod), List.<JCExpression>nil());
// make sure the result is boxed if necessary, the result of successor/predecessor is always boxed
successor = boxUnboxIfNecessary(successor, true, term.getTypeModel(), CodegenUtil.getBoxingStrategy(term));
}
JCExpression assignment = transformAssignment(expr, term, successor);
stats = stats.prepend(at(expr).Exec(assignment));
// $tmp
result = make().Ident(varName);
} else if (term instanceof Tree.QualifiedMemberExpression) {
// e.attr++
// (let $tmpE = e, $tmpV = $tmpE.attr; $tmpE.attr = $tmpV.getSuccessor(); $tmpV;)
Tree.QualifiedMemberExpression qualified = (Tree.QualifiedMemberExpression) term;
boolean isSuper = isSuperOrSuperOf(qualified.getPrimary());
boolean isPackage = isPackageQualified(qualified);
// transform the primary, this will get us a boxed primary
JCExpression e = transformQualifiedMemberPrimary(qualified);
at(expr);
// Type $tmpE = e
JCExpression exprType = makeJavaType(qualified.getTarget().getQualifyingType(), JT_NO_PRIMITIVES);
Name varEName = naming.tempName("opE");
JCVariableDecl tmpEVar = make().VarDef(make().Modifiers(0), varEName, exprType, e);
// Type $tmpV = $tmpE.attr
JCExpression attrType = makeJavaType(returnType, boxResult ? JT_NO_PRIMITIVES : 0);
Name varVName = naming.tempName("opV");
JCExpression getter;
if (isSuper) {
getter = transformMemberExpression(qualified, transformSuper(qualified), null);
} else if (isPackage) {
getter = transformMemberExpression(qualified, null, null);
} else {
getter = transformMemberExpression(qualified, make().Ident(varEName), null);
}
// make sure we box the results if necessary
getter = applyErasureAndBoxing(getter, term, boxResult ? BoxingStrategy.BOXED : BoxingStrategy.UNBOXED, returnType);
JCVariableDecl tmpVVar = make().VarDef(make().Modifiers(0), varVName, attrType, getter);
decls = decls.prepend(tmpVVar);
if (!isSuper && !isPackage) {
// define all the variables
decls = decls.prepend(tmpEVar);
}
// $tmpE.attr = $tmpV.getSuccessor()
JCExpression successor;
if (canOptimise) {
// use +1/-1 if we can optimise a bit
successor = make().Binary(operator == OperatorTranslation.UNARY_POSTFIX_INCREMENT ? JCTree.PLUS : JCTree.MINUS, make().Ident(varVName), makeInteger(1));
successor = unAutoPromote(successor, returnType);
} else {
successor = make().Apply(null, makeSelect(make().Ident(varVName), operator.ceylonMethod), List.<JCExpression>nil());
// make sure the result is boxed if necessary, the result of successor/predecessor is always boxed
successor = boxUnboxIfNecessary(successor, true, term.getTypeModel(), CodegenUtil.getBoxingStrategy(term));
}
JCExpression assignment = transformAssignment(expr, term, isSuper ? transformSuper(qualified) : make().Ident(varEName), successor);
stats = stats.prepend(at(expr).Exec(assignment));
// $tmpV
result = make().Ident(varVName);
} else {
return makeErroneous(term, "compiler bug: " + term.getNodeType() + " is not supported yet");
}
return make().LetExpr(decls, stats, result);
}
use of com.redhat.ceylon.model.typechecker.model.Interface in project ceylon-compiler by ceylon.
the class ExpressionTransformer method appendDeclarationLiteralForAnnotation.
/**
* Appends into the given builder a String representation of the given
* declaration, suitable for parsing my the DeclarationParser.
*/
private static void appendDeclarationLiteralForAnnotation(Declaration decl, StringBuilder sb) {
Scope container = decl.getContainer();
while (true) {
if (container instanceof Declaration) {
appendDeclarationLiteralForAnnotation((Declaration) container, sb);
sb.append(".");
break;
} else if (container instanceof Package) {
appendDeclarationLiteralForAnnotation((Package) container, sb);
sb.append(":");
break;
}
container = container.getContainer();
}
if (decl instanceof Class) {
sb.append("C").append(decl.getName());
} else if (decl instanceof Interface) {
sb.append("I").append(decl.getName());
} else if (decl instanceof TypeAlias) {
sb.append("A").append(decl.getName());
} else if (decl instanceof Value) {
sb.append("V").append(decl.getName());
} else if (decl instanceof Function) {
sb.append("F").append(decl.getName());
} else if (decl instanceof TypeParameter) {
sb.append("P").append(decl.getName());
} else if (decl instanceof Constructor) {
sb.append("c").append(decl.getName());
} else {
throw BugException.unhandledDeclarationCase(decl);
}
}
use of com.redhat.ceylon.model.typechecker.model.Interface in project ceylon-compiler by ceylon.
the class ExpressionTransformer method needDollarThis.
private boolean needDollarThis(Tree.StaticMemberOrTypeExpression expr) {
if (expr instanceof Tree.BaseMemberExpression) {
// We need to add a `$this` prefix to the member expression if:
// * The member was declared on an interface I and
// * The member is being used in the companion class of I or
// // REMOVED: some subinterface of I, and
// some member type of I, and
// * The member is shared (non-shared means its only on the companion class)
// FIXME: https://github.com/ceylon/ceylon-compiler/issues/1019
final Declaration decl = expr.getDeclaration();
if (!Decl.withinInterface(decl))
return false;
// Find the method/getter/setter where the expr is being used
Scope scope = expr.getScope();
while (scope != null) {
// Is it being used in an interface (=> impl)
if (scope instanceof Interface && ((Interface) scope).getType().isSubtypeOf(scope.getDeclaringType(decl))) {
return decl.isShared();
}
scope = scope.getContainer();
}
}
return false;
}
Aggregations