use of com.redhat.ceylon.model.typechecker.model.Type in project ceylon-compiler by ceylon.
the class ExpressionTransformer method transform.
public JCExpression transform(Tree.WithinOp op) {
Tree.Term middleTerm = op.getTerm();
Tree.Bound lowerBound = op.getLowerBound();
OperatorTranslation lowerOp = Operators.getOperator(lowerBound instanceof Tree.OpenBound ? Tree.SmallerOp.class : Tree.SmallAsOp.class);
Tree.Term lowerTerm = lowerBound.getTerm();
Tree.Bound upperBound = op.getUpperBound();
OperatorTranslation upperOp = Operators.getOperator(upperBound instanceof Tree.OpenBound ? Tree.SmallerOp.class : Tree.SmallAsOp.class);
Tree.Term upperTerm = upperBound.getTerm();
Type middleType = getComparableType(middleTerm);
Type lowerType = getComparableType(lowerTerm);
Type upperType = getComparableType(upperTerm);
// If any of the terms is optimizable, then use optimized
OptimisationStrategy opt;
boolean optimizeLower = lowerOp.isTermOptimisable(lowerTerm, lowerType, this) == OptimisationStrategy.OPTIMISE || lowerOp.isTermOptimisable(middleTerm, middleType, this) == OptimisationStrategy.OPTIMISE;
boolean optimizeUpper = upperOp.isTermOptimisable(middleTerm, middleType, this) == OptimisationStrategy.OPTIMISE || upperOp.isTermOptimisable(upperTerm, upperType, this) == OptimisationStrategy.OPTIMISE;
if ((lowerType.isExactly(middleType) && middleType.isExactly(upperType) && (optimizeLower || // if all same type and any optimizable
optimizeUpper)) || (// otherwise onle if all optimizable
optimizeLower && optimizeUpper)) {
opt = OptimisationStrategy.OPTIMISE;
} else {
opt = OptimisationStrategy.NONE;
}
SyntheticName middleName = naming.alias("middle");
List<JCStatement> vars = List.<JCStatement>of(makeVar(middleName, makeJavaType(middleType, opt.getBoxingStrategy() == BoxingStrategy.UNBOXED ? 0 : JT_NO_PRIMITIVES), transformExpression(middleTerm, opt.getBoxingStrategy(), middleType)));
JCExpression lower = transformBound(middleName, middleType, lowerType, lowerOp, opt, middleTerm, lowerBound, false);
JCExpression upper = transformBound(middleName, middleType, upperType, upperOp, opt, middleTerm, upperBound, true);
at(op);
OperatorTranslation andOp = Operators.getOperator(Tree.AndOp.class);
OptimisationStrategy optimisationStrategy = OptimisationStrategy.OPTIMISE;
return make().LetExpr(vars, transformOverridableBinaryOperator(andOp, optimisationStrategy, lower, upper, null, null, op.getTypeModel()));
}
use of com.redhat.ceylon.model.typechecker.model.Type in project ceylon-compiler by ceylon.
the class ExpressionTransformer method applyErasureAndBoxing.
JCExpression applyErasureAndBoxing(JCExpression result, Type exprType, boolean exprErased, boolean exprBoxed, boolean exprUntrustedType, BoxingStrategy boxingStrategy, Type expectedType, int flags) {
if (exprType != null)
exprType = exprType.resolveAliases();
if (expectedType != null)
expectedType = expectedType.resolveAliases();
boolean canCast = false;
if (expectedType != null && // don't add cast to an erased type
!willEraseToObject(expectedType)) {
// only try to cast boxed types, no point otherwise
if (exprBoxed) {
boolean expectedTypeIsNotRaw = (flags & EXPR_EXPECTED_TYPE_NOT_RAW) != 0;
boolean expectedTypeHasConstrainedTypeParameters = (flags & EXPR_EXPECTED_TYPE_HAS_CONSTRAINED_TYPE_PARAMETERS) != 0;
boolean expectedTypeHasDependentCovariantTypeParameters = (flags & EXPR_EXPECTED_TYPE_HAS_DEPENDENT_COVARIANT_TYPE_PARAMETERS) != 0;
boolean downCast = (flags & EXPR_DOWN_CAST) != 0;
int companionFlags = (flags & EXPR_WANTS_COMPANION) != 0 ? AbstractTransformer.JT_COMPANION : 0;
// special case for returning Null expressions
if (isNull(exprType)) {
// don't add cast for null
if (!isNullValue(exprType) || // of different types using the "of" operator
downCast) {
// in some cases we may have an instance of Null, which is of type java.lang.Object, being
// returned in a context where we expect a String? (aka ceylon.language.String) so even though
// the instance at hand will really be null, we need a up-cast to it
JCExpression targetType = makeJavaType(expectedType, AbstractTransformer.JT_RAW | companionFlags);
result = make().TypeCast(targetType, result);
}
} else if (exprType.isExactlyNothing()) {
// type param erasure
JCExpression targetType = makeJavaType(expectedType, AbstractTransformer.JT_NO_PRIMITIVES | companionFlags);
result = make().TypeCast(targetType, result);
} else if (// expression was forcibly erased
exprErased || // bounds that are different from what we think the expression type should be
exprUntrustedType || // see https://github.com/ceylon/ceylon-compiler/issues/1557
expectedTypeHasDependentCovariantTypeParameters || // some type parameter somewhere needs a cast
needsCast(exprType, expectedType, expectedTypeIsNotRaw, expectedTypeHasConstrainedTypeParameters, downCast) || // if the exprType is raw and the expected type isn't
(exprType.isRaw() && (expectedTypeIsNotRaw || !isTurnedToRaw(expectedType)))) {
// save this before we simplify it because we lose that flag doing so
boolean exprIsRaw = exprType.isRaw();
boolean expectedTypeIsRaw = isTurnedToRaw(expectedType) && !expectedTypeIsNotRaw;
// (unless the other type is already raw)
if ((!exprIsRaw && hasTypeParameters(expectedType)) || (downCast && !expectedTypeIsRaw && hasTypeParameters(exprType))) {
Type rawType = hasTypeParameters(expectedType) ? expectedType : exprType;
JCExpression rawTypeExpr = makeJavaType(rawType, AbstractTransformer.JT_TYPE_ARGUMENT | AbstractTransformer.JT_RAW | companionFlags);
result = make().TypeCast(rawTypeExpr, result);
// expr is now raw
exprIsRaw = true;
// let's not add another downcast if we got a cast: one is enough
downCast = false;
// same for forced erasure
exprErased = false;
exprUntrustedType = false;
}
// simplify the type
// (without the underlying type, because the cast is always to a non-primitive)
exprType = simplifyType(expectedType).withoutUnderlyingType();
// if the expr is not raw, we need a cast
// if the expr is raw:
// don't even try making an actual cast if there are bounded type parameters in play, because going raw is much safer
// also don't try making the cast if the expected type is raw because anything goes
boolean needsTypedCast = !exprIsRaw || (!expectedTypeHasConstrainedTypeParameters && !expectedTypeHasDependentCovariantTypeParameters && !expectedTypeIsRaw);
if (needsTypedCast || // make sure that downcasts get at least one cast
downCast || // same for forced erasure
exprUntrustedType) {
// it figures out that there's no intersection between the two types, but we know better
if (exprUntrustedType && !exprIsRaw) {
result = make().TypeCast(syms().objectType, result);
}
// Do the actual cast
JCExpression targetType = makeJavaType(expectedType, AbstractTransformer.JT_TYPE_ARGUMENT | companionFlags);
result = make().TypeCast(targetType, result);
}
} else
canCast = true;
} else
canCast = true;
}
// If expr type if Self<T> and expected type is T we need to cast before any unboxing
if (exprType.getDeclaration().getSelfType() != null && expectedType != null && expectedType.isExactly(exprType.getTypeArguments().get(exprType.getDeclaration().getSelfType().getDeclaration()))) {
result = applySelfTypeCasts(result, exprType, exprBoxed, BoxingStrategy.BOXED, expectedType);
exprType = expectedType;
}
// we must do the boxing after the cast to the proper type
JCExpression ret = boxUnboxIfNecessary(result, exprBoxed, exprType, boxingStrategy, expectedType);
// very special case for nothing that we need to "unbox" to a primitive type
if (exprType != null && exprType.isExactlyNothing() && boxingStrategy == BoxingStrategy.UNBOXED) {
// in this case we have to use the expected type
ret = unboxType(ret, expectedType);
}
// now check if we need variance casts
if (canCast) {
ret = applyVarianceCasts(ret, exprType, exprBoxed, boxingStrategy, expectedType, flags);
}
ret = applySelfTypeCasts(ret, exprType, exprBoxed, boxingStrategy, expectedType);
ret = applyJavaTypeConversions(ret, exprType, expectedType, boxingStrategy, exprBoxed, flags);
return ret;
}
use of com.redhat.ceylon.model.typechecker.model.Type in project ceylon-compiler by ceylon.
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());
return transformExpression(expr, boxing, nonWideningType);
}
use of com.redhat.ceylon.model.typechecker.model.Type in project ceylon-compiler by ceylon.
the class ExpressionTransformer method lostTypeParameterInInheritance.
private boolean lostTypeParameterInInheritance(ClassOrInterface exprDecl, ClassOrInterface commonDecl, boolean searchInterfaces, boolean lostTypeParameter) {
// stop if we found the common decl
if (Decl.equal(exprDecl, commonDecl))
return lostTypeParameter;
if (searchInterfaces) {
// find a match in interfaces
for (Type pt : exprDecl.getSatisfiedTypes()) {
// FIXME: this is very heavy-handed because we consider that once we've lost a type parameter we've lost them all
// but we could optimise this by checking:
// 1/ which type parameter we've really lost
// 2/ if the type parameters we're passing to our super type actually depend in any way from type parameters we've lost
boolean lostTypeParameter2 = lostTypeParameter || isTurnedToRaw(pt);
pt = simplifyType(pt);
// it has to be an interface
Interface interf = (Interface) pt.getDeclaration();
if (lostTypeParameterInInheritance(interf, commonDecl, searchInterfaces, lostTypeParameter2))
return true;
}
}
// search for super classes
Type extendedType = exprDecl.getExtendedType();
if (extendedType != null) {
// FIXME: see above
boolean lostTypeParameter2 = lostTypeParameter || isTurnedToRaw(extendedType);
extendedType = simplifyType(extendedType);
// it has to be a Class
Class extendedTypeDeclaration = (Class) extendedType.getDeclaration();
// looks like Object's superclass is Object, so stop right there
if (extendedTypeDeclaration != typeFact().getObjectDeclaration())
return lostTypeParameterInInheritance(extendedTypeDeclaration, commonDecl, searchInterfaces, lostTypeParameter2);
}
// didn't find it
return false;
}
use of com.redhat.ceylon.model.typechecker.model.Type in project ceylon-compiler by ceylon.
the class ClassTransformer method addMissingUnrefinedMembers.
/**
* Recover from members not being refined in the class hierarchy
* by generating a stub method that throws.
*/
private void addMissingUnrefinedMembers(Node def, Class classModel, ClassDefinitionBuilder classBuilder) {
for (Reference unrefined : classModel.getUnimplementedFormals()) {
//classModel.getMember(memberName, null, false);
Declaration formalMember = unrefined.getDeclaration();
String errorMessage = "formal member '" + formalMember.getName() + "' of '" + ((TypeDeclaration) formalMember.getContainer()).getName() + "' not implemented in class hierarchy";
java.util.List<Type> params = new java.util.ArrayList<Type>();
if (formalMember instanceof Generic) {
for (TypeParameter tp : ((Generic) formalMember).getTypeParameters()) {
params.add(tp.getType());
}
}
if (formalMember instanceof Value) {
addRefinedThrowerAttribute(classBuilder, errorMessage, classModel, (Value) formalMember);
} else if (formalMember instanceof Function) {
addRefinedThrowerMethod(classBuilder, errorMessage, classModel, (Function) formalMember);
} else if (formalMember instanceof Class && formalMember.isClassMember()) {
addRefinedThrowerInstantiatorMethod(classBuilder, errorMessage, classModel, (Class) formalMember, unrefined);
}
// formal member class of interface handled in
// makeDelegateToCompanion()
}
}
Aggregations