use of org.eclipse.ceylon.model.typechecker.model.TypeParameter in project ceylon by eclipse.
the class AbstractTransformer method canOptimiseReifiedTypeTest.
/**
* Determine whether we can use a plain {@code instanceof} instead of
* a full {@code Util.isReified()} for a {@code is} test
*/
private boolean canOptimiseReifiedTypeTest(Type type) {
if (isJavaArray(type)) {
if (isJavaObjectArray(type)) {
MultidimensionalArray multiArray = getMultiDimensionalArrayInfo(type);
// we can test, even if not fully reified in Java
return multiArray.type.getDeclaration() instanceof ClassOrInterface;
} else {
// primitive array we can test
return true;
}
}
// we can optimise it if we've got a ClassOrInterface with only Anything type parameters
TypeDeclaration typeDeclaration = type.getDeclaration();
if (typeDeclaration instanceof ClassOrInterface == false)
return false;
for (Entry<TypeParameter, Type> entry : type.getTypeArguments().entrySet()) {
TypeParameter tp = entry.getKey();
// skip type params for qualifying types
if (!tp.getDeclaration().equals(typeDeclaration))
continue;
if (!type.isCovariant(tp)) {
return false;
}
java.util.List<Type> bounds = tp.getSatisfiedTypes();
Type ta = entry.getValue();
if ((bounds == null || bounds.isEmpty()) && !isAnything(ta)) {
return false;
}
for (Type bound : bounds) {
if (!ta.isSupertypeOf(bound)) {
return false;
}
}
}
// they're all Anything (or supertypes of their upper bound) we can optimise, unless we have a container with type arguments
Type qualifyingType = type.getQualifyingType();
if (qualifyingType == null && // ignore qualifying types of static java declarations
(ModelUtil.isCeylonDeclaration(type.getDeclaration()) || !type.getDeclaration().isStatic())) {
Declaration declaration = type.getDeclaration();
do {
// it may be contained in a function or value, and we want its type
Declaration enclosingDeclaration = getDeclarationContainer(declaration);
if (enclosingDeclaration instanceof TypedDeclaration) {
// must be in scope
if (enclosingDeclaration.isParameterized())
return false;
// look up the containers
declaration = enclosingDeclaration;
} else if (enclosingDeclaration instanceof TypeDeclaration) {
// we can't optimise if that container has type arguments as they are not provided
if (enclosingDeclaration.isParameterized())
return false;
// look up the containers
declaration = enclosingDeclaration;
} else {
// that's fucked up
break;
}
// go up every containing typed declaration
} while (declaration != null);
// we can optimise!
return true;
} else if (qualifyingType != null) {
// we can only optimise if the qualifying type can also be optimised
return canOptimiseReifiedTypeTest(qualifyingType);
} else {
// we can optimise!
return true;
}
}
use of org.eclipse.ceylon.model.typechecker.model.TypeParameter in project ceylon by eclipse.
the class AbstractTransformer method makeTypeArgs.
private ListBuffer<JCExpression> makeTypeArgs(boolean isCeylonCallable, int flags, Map<TypeParameter, Type> tas, java.util.List<TypeParameter> tps, Type simpleType) {
ListBuffer<JCExpression> typeArgs = new ListBuffer<JCExpression>();
for (TypeParameter tp : tps) {
Type ta = tas.get(tp);
// error handling
if (ta == null)
continue;
boolean isDependedOn = hasDependentTypeParameters(tps, tp);
// record whether we were initially working with Anything, because getNonNullType turns it into Object
// and we need to treat "in Anything" specially below
boolean isAnything = isAnything(ta);
// we want, so we make sure it's not Null
if (isOptional(ta) && !isNull(ta)) {
// For an optional type T?:
// - The Ceylon type Foo<T?> results in the Java type Foo<T>.
ta = getNonNullType(ta);
}
// In a type argument Foo<X&Object> or Foo<X?> transform to just Foo<X>
ta = simplifyType(ta);
if (typeFact().isUnion(ta) || typeFact().isIntersection(ta)) {
// conform with where raw types would be used between expressions and constructors
if (((flags & (JT_EXTENDS | JT_SATISFIES)) != 0 && tp.getSelfTypedDeclaration() != null)) {
// A bit ugly, but we need to escape from the loop and create a raw type, no generics
if ((flags & (JT_EXTENDS | JT_SATISFIES)) != 0)
throw new BugException("rawSupertype() should prevent this method going raw when JT_EXTENDS | JT_SATISFIES");
typeArgs = null;
break;
} else if ((flags & (__JT_FULL_TYPE | JT_EXTENDS | JT_SATISFIES)) == 0) {
if ((flags & (JT_EXTENDS | JT_SATISFIES)) != 0)
throw new BugException("rawSupertype() should prevent this method going raw when JT_EXTENDS | JT_SATISFIES");
typeArgs = null;
break;
}
// otherwise just go on
}
if (isCeylonBoolean(ta) && !isTypeParameter(ta)) {
ta = typeFact.getBooleanType();
}
JCExpression jta;
if (!tp.getSatisfiedTypes().isEmpty()) {
boolean needsCastForBounds = false;
for (Type bound : tp.getSatisfiedTypes()) {
bound = bound.substitute(tas, null);
needsCastForBounds |= expressionGen().needsCast(ta, bound, false, false, false);
}
if (needsCastForBounds) {
// replace with the first bound
ta = tp.getSatisfiedTypes().get(0).substitute(tas, null);
if (tp.getSatisfiedTypes().size() > 1 || isBoundsSelfDependant(tp) || isBoundsRecursive(simpleType, tp) || willEraseToObject(ta) || // we should reject it for all non-covariant types, unless we're in satisfies/extends
((flags & (JT_SATISFIES | JT_EXTENDS)) == 0 && !simpleType.isCovariant(tp))) {
if ((flags & (JT_EXTENDS | JT_SATISFIES)) != 0)
throw new BugException("rawSupertype() should prevent this method going raw when JT_EXTENDS | JT_SATISFIES");
// A bit ugly, but we need to escape from the loop and create a raw type, no generics
typeArgs = null;
break;
}
}
}
if (ta.isExactlyNothing() || // use the same erasure rules as bottom: prefer wildcards
((flags & (__JT_FULL_TYPE | JT_EXTENDS | JT_SATISFIES)) != 0 && (typeFact().isUnion(ta) || typeFact().isIntersection(ta)))) {
// For the bottom type Bottom:
if ((flags & (JT_CLASS_NEW)) != 0) {
// A bit ugly, but we need to escape from the loop and create a raw type, no generics
if ((flags & (JT_EXTENDS | JT_SATISFIES)) != 0)
throw new BugException("rawSupertype() should prevent this method going raw when JT_EXTENDS | JT_SATISFIES");
typeArgs = null;
break;
} else {
// Foo<Object> (see https://github.com/ceylon/ceylon-compiler/issues/633 for why)
if ((flags & (JT_SATISFIES | JT_EXTENDS)) != 0) {
if (ta.isExactlyNothing()) {
jta = make().Type(syms().objectType);
} else {
if (!tp.getSatisfiedTypes().isEmpty()) {
// union or intersection: Use the common upper bound of the types
jta = makeJavaType(tp.getSatisfiedTypes().get(0), JT_TYPE_ARGUMENT);
} else {
jta = make().Type(syms().objectType);
}
}
} else if (ta.isExactlyNothing()) {
// see https://github.com/ceylon/ceylon-compiler/issues/1003
if (simpleType.isContravariant(tp)) {
typeArgs = null;
break;
} else if (tp.isCovariant() && !isDependedOn) {
// DO NOT trust use-site covariance for Nothing, because we consider "out Nothing" to be the same
// as "Nothing". Only look at declaration-site covariance
jta = make().Wildcard(make().TypeBoundKind(BoundKind.EXTENDS), make().Type(syms().objectType));
} else {
jta = make().Type(syms().objectType);
}
} else {
// see https://github.com/ceylon/ceylon/issues/6365
if (((flags & JT_CLASS_NEW) == 0) && simpleType.isContravariant(tp)) /* && !isDependedOn*/
{
jta = make().Wildcard(make().TypeBoundKind(BoundKind.SUPER), makeJavaType(ta, JT_TYPE_ARGUMENT));
} else if (((flags & JT_CLASS_NEW) == 0) && simpleType.isCovariant(tp) && !isDependedOn) {
jta = make().Wildcard(make().TypeBoundKind(BoundKind.EXTENDS), makeJavaType(ta, JT_TYPE_ARGUMENT));
} else {
jta = makeJavaType(ta, JT_TYPE_ARGUMENT);
}
}
}
} else {
// For an ordinary class or interface type T:
if ((flags & (JT_SATISFIES | JT_EXTENDS)) != 0) {
// - The Ceylon type Foo<T> appearing in an extends or satisfies clause
// results in the Java type Foo<T>
jta = makeJavaType(ta, JT_TYPE_ARGUMENT);
} else {
// - Foo<? super T> if Foo is contravariant in T
if (((flags & JT_CLASS_NEW) == 0) && simpleType.isContravariant(tp) && (!isAnything || tp.isContravariant())) // FIXME: it may be necessary to uncomment this in the future,
// see https://github.com/ceylon/ceylon/issues/6365
/*&& !isDependedOn*/
{
// DO NOT trust use-site contravariance for Anything, because we consider "in Anything" to be the same
// as "Anything". Only look at declaration-site contravariance
jta = make().Wildcard(make().TypeBoundKind(BoundKind.SUPER), makeJavaType(ta, JT_TYPE_ARGUMENT));
} else if (((flags & JT_CLASS_NEW) == 0) && simpleType.isCovariant(tp) && !isDependedOn) {
jta = make().Wildcard(make().TypeBoundKind(BoundKind.EXTENDS), makeJavaType(ta, JT_TYPE_ARGUMENT));
} else {
jta = makeJavaType(ta, JT_TYPE_ARGUMENT);
}
}
}
typeArgs.add(jta);
if (isCeylonCallable) {
// In the runtime Callable only has a single type param
break;
}
}
return typeArgs;
}
use of org.eclipse.ceylon.model.typechecker.model.TypeParameter in project ceylon by eclipse.
the class AbstractTransformer method getTypeArguments.
private java.util.List<Type> getTypeArguments(Reference producedReference) {
java.util.List<TypeParameter> typeParameters = getTypeParameters(producedReference);
java.util.List<Type> typeArguments = new ArrayList<Type>(typeParameters.size());
for (TypeParameter tp : typeParameters) {
Type ta;
Reference ref = producedReference;
do {
ta = ref.getTypeArguments().get(tp);
ref = ref.getQualifyingType();
} while (ta == null && ref != null);
typeArguments.add(ta);
}
return typeArguments;
}
use of org.eclipse.ceylon.model.typechecker.model.TypeParameter in project ceylon by eclipse.
the class AbstractTransformer method makeTypeParameter.
JCTypeParameter makeTypeParameter(TypeParameter declarationModel, java.util.List<Type> satisfiedTypesForBounds) {
TypeParameter typeParameterForBounds = declarationModel;
if (satisfiedTypesForBounds == null) {
satisfiedTypesForBounds = declarationModel.getSatisfiedTypes();
}
// special case for method refinenement where Java doesn't let us refine the parameter bounds
if (declarationModel.getContainer() instanceof Function) {
Function method = (Function) declarationModel.getContainer();
Function refinedMethod = (Function) method.getRefinedDeclaration();
if (!Decl.equal(method, refinedMethod)) {
// find the param index
int index = method.getTypeParameters().indexOf(declarationModel);
if (index == -1) {
log.error("Failed to find type parameter index: " + declarationModel.getName());
} else if (refinedMethod.getTypeParameters().size() > index) {
// ignore smaller index than size since the typechecker would have found the error
TypeParameter refinedTP = refinedMethod.getTypeParameters().get(index);
if (!haveSameBounds(declarationModel, refinedTP)) {
// find the right instantiation of that type parameter
TypeDeclaration methodContainer = (TypeDeclaration) method.getContainer();
TypeDeclaration refinedMethodContainer = (TypeDeclaration) refinedMethod.getContainer();
// find the supertype that gave us that method and its type arguments
Type supertype = methodContainer.getType().getSupertype(refinedMethodContainer);
satisfiedTypesForBounds = new ArrayList<Type>(refinedTP.getSatisfiedTypes().size());
for (Type satisfiedType : refinedTP.getSatisfiedTypes()) {
// substitute the refined type parameter bounds with the right type arguments
satisfiedTypesForBounds.add(satisfiedType.substitute(supertype));
}
typeParameterForBounds = refinedTP;
}
}
}
}
return makeTypeParameter(declarationModel.getName(), satisfiedTypesForBounds, typeParameterForBounds.isCovariant(), typeParameterForBounds.isContravariant());
}
use of org.eclipse.ceylon.model.typechecker.model.TypeParameter in project ceylon by eclipse.
the class AbstractTransformer method getRefinedTypedReference.
private TypedReference getRefinedTypedReference(TypedReference typedReference, TypedDeclaration refinedDeclaration) {
TypeDeclaration refinedContainer = (TypeDeclaration) refinedDeclaration.getContainer();
Type refinedContainerType = typedReference.getQualifyingType().getSupertype(refinedContainer);
ArrayList<Type> typeArgs = new ArrayList<Type>();
for (TypeParameter tp : typedReference.getDeclaration().getTypeParameters()) {
typeArgs.add(typedReference.getTypeArguments().get(tp));
}
return refinedDeclaration.appliedTypedReference(refinedContainerType, typeArgs);
}
Aggregations