use of com.redhat.ceylon.model.typechecker.model.TypeParameter 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.TypeParameter in project ceylon-compiler by ceylon.
the class ExpressionTransformer method transform.
public JCTree transform(Tree.TypeLiteral expr) {
at(expr);
if (!expr.getWantsDeclaration()) {
if (expr.getDeclaration() instanceof Constructor) {
JCExpression classLiteral = makeTypeLiteralCall(expr.getType().getTypeModel().getQualifyingType(), false, expr.getTypeModel());
TypeDeclaration classModelDeclaration = (TypeDeclaration) typeFact().getLanguageModuleModelDeclaration(expr.getType().getTypeModel().getQualifyingType().getDeclaration().isMember() ? "MemberClass" : "Class");
JCTypeCast typeCast = make().TypeCast(makeJavaType(classModelDeclaration.appliedType(null, List.of(expr.getType().getTypeModel().getQualifyingType(), typeFact().getNothingType()))), classLiteral);
Type callableType = expr.getTypeModel().getFullType();
JCExpression reifiedArgumentsExpr = makeReifiedTypeArgument(typeFact().getCallableTuple(callableType));
return make().Apply(null, naming.makeQualIdent(typeCast, "getConstructor"), List.<JCExpression>of(reifiedArgumentsExpr, make().Literal(expr.getDeclaration().getName())));
} else {
return makeTypeLiteralCall(expr.getType().getTypeModel(), true, expr.getTypeModel());
}
} else if (expr.getDeclaration() instanceof TypeParameter) {
// we must get it from its container
TypeParameter declaration = (TypeParameter) expr.getDeclaration();
Node node = expr;
return makeTypeParameterDeclaration(node, declaration);
} else if (expr.getDeclaration() instanceof Constructor || expr instanceof Tree.NewLiteral) {
Constructor ctor;
if (expr.getDeclaration() instanceof Constructor) {
ctor = (Constructor) expr.getDeclaration();
} else {
ctor = Decl.getDefaultConstructor((Class) expr.getDeclaration());
}
JCExpression metamodelCall = makeTypeDeclarationLiteral(Decl.getConstructedClass(ctor));
metamodelCall = make().TypeCast(makeJavaType(typeFact().getClassDeclarationType(), JT_RAW), metamodelCall);
metamodelCall = make().Apply(null, naming.makeQualIdent(metamodelCall, "getConstructorDeclaration"), List.<JCExpression>of(make().Literal(ctor.getName() == null ? "" : ctor.getName())));
if (Decl.isEnumeratedConstructor(ctor)) {
metamodelCall = make().TypeCast(makeJavaType(typeFact().getValueConstructorDeclarationType(), JT_RAW), metamodelCall);
} else /*else if (Decl.isDefaultConstructor(ctor)){
metamodelCall = make().TypeCast(
makeJavaType(typeFact().getDefaultConstructorDeclarationType(), JT_RAW), metamodelCall);
} */
{
metamodelCall = make().TypeCast(makeJavaType(typeFact().getCallableConstructorDeclarationType(), JT_RAW), metamodelCall);
}
return metamodelCall;
} else if (expr.getDeclaration() instanceof ClassOrInterface || expr.getDeclaration() instanceof TypeAlias) {
// use the generated class to get to the declaration literal
JCExpression metamodelCall = makeTypeDeclarationLiteral((TypeDeclaration) expr.getDeclaration());
Type exprType = expr.getTypeModel().resolveAliases();
// now cast if required
if (!exprType.isExactly(((TypeDeclaration) typeFact().getLanguageModuleDeclarationDeclaration("NestableDeclaration")).getType())) {
JCExpression type = makeJavaType(exprType, JT_NO_PRIMITIVES);
return make().TypeCast(type, metamodelCall);
}
return metamodelCall;
} else {
return makeErroneous(expr, "compiler bug: " + expr.getDeclaration() + " is an unsupported declaration type");
}
}
use of com.redhat.ceylon.model.typechecker.model.TypeParameter 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.TypeParameter in project ceylon-compiler by ceylon.
the class ExpressionTransformer method needsCast.
boolean needsCast(Type exprType, Type expectedType, boolean expectedTypeNotRaw, boolean expectedTypeHasConstrainedTypeParameters, boolean downCast) {
// error handling
if (exprType == null)
return false;
// make sure we work on definite types
exprType = simplifyType(exprType);
expectedType = simplifyType(expectedType);
// abort if both types are the same
if (exprType.isExactly(expectedType)) {
// really trust the expected type
if (!expectedTypeHasConstrainedTypeParameters)
return false;
}
// now see about erasure
boolean eraseExprType = willEraseToObject(exprType);
boolean eraseExpectedType = willEraseToObject(expectedType);
// if we erase expected type we need no cast
if (eraseExpectedType) {
// unless the expected type is parameterised with bounds that erasure to Object can't possibly satisfy
if (!expectedTypeHasConstrainedTypeParameters)
return false;
}
// if we erase the expr type we need a cast
if (eraseExprType)
return true;
// find their common type
Type commonType = exprType.getSupertype(expectedType.getDeclaration());
if (commonType == null || !(commonType.getDeclaration() instanceof ClassOrInterface)) {
// we did not find any common type, but we may be downcasting, in which case we need a cast
return downCast;
}
// some times we can lose info due to an erased type parameter somewhere in the inheritance graph
if (lostTypeParameterInInheritance(exprType, commonType))
return true;
if (!expectedTypeNotRaw) {
// if we know for sure that the expected type is NOT raw. if it's false we've no idea but we can check:
if (isTurnedToRaw(expectedType)) {
return false;
}
// the common type could be erased
if (commonType.isExactly(expectedType))
return false;
}
// special case for Callable because only the first type param exists in Java, the rest is completely suppressed
boolean isCallable = isCeylonCallable(commonType);
// now see if the type parameters match
java.util.List<Type> commonTypeArgs = commonType.getTypeArgumentList();
java.util.List<TypeParameter> commonTps = commonType.getDeclaration().getTypeParameters();
java.util.List<Type> expectedTypeArgs = expectedType.getTypeArgumentList();
java.util.List<TypeParameter> expectedTps = expectedType.getDeclaration().getTypeParameters();
// check that we got them all otherwise we just don't know
if (commonTypeArgs.size() != expectedTypeArgs.size())
return false;
for (int i = 0, n = commonTypeArgs.size(); i < n; i++) {
// apply the same logic to each type param: see if they would require a raw cast
Type commonTypeArg = commonTypeArgs.get(i);
Type expectedTypeArg = expectedTypeArgs.get(i);
if (hasDependentTypeParameters(commonTps, commonTps.get(i)) || hasDependentTypeParameters(expectedTps, expectedTps.get(i))) {
// if the type parameters are not identical:
if (!simplifyType(commonTypeArg).isExactly(simplifyType(expectedTypeArg))) {
return true;
}
}
if (needsCast(commonTypeArg, expectedTypeArg, expectedTypeNotRaw, expectedTypeHasConstrainedTypeParameters, downCast))
return true;
// stop after the first one for Callable
if (isCallable)
break;
}
return false;
}
use of com.redhat.ceylon.model.typechecker.model.TypeParameter in project ceylon-compiler by ceylon.
the class TypeParserTests method testParamsVariance2.
@Test
public void testParamsVariance2() {
Type type = new TypeParser(MockLoader.instance).decodeType("t2<b,out c>", null, mockDefaultModule, mockPkgUnit);
assertTypeWithParameters(type);
Map<TypeParameter, SiteVariance> varianceOverrides = type.getVarianceOverrides();
Assert.assertNotNull(varianceOverrides);
Assert.assertEquals(1, varianceOverrides.size());
List<TypeParameter> tps = type.getDeclaration().getTypeParameters();
Assert.assertEquals(null, varianceOverrides.get(tps.get(0)));
Assert.assertEquals(SiteVariance.OUT, varianceOverrides.get(tps.get(1)));
}
Aggregations