Search in sources :

Example 1 with TypeParameter

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;
}
Also used : TypeParameter(com.redhat.ceylon.model.typechecker.model.TypeParameter) Type(com.redhat.ceylon.model.typechecker.model.Type) Interface(com.redhat.ceylon.model.typechecker.model.Interface) ClassOrInterface(com.redhat.ceylon.model.typechecker.model.ClassOrInterface) LinkedList(java.util.LinkedList)

Example 2 with TypeParameter

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");
    }
}
Also used : ClassOrInterface(com.redhat.ceylon.model.typechecker.model.ClassOrInterface) Type(com.redhat.ceylon.model.typechecker.model.Type) TypeParameter(com.redhat.ceylon.model.typechecker.model.TypeParameter) JCExpression(com.sun.tools.javac.tree.JCTree.JCExpression) JCTypeCast(com.sun.tools.javac.tree.JCTree.JCTypeCast) Constructor(com.redhat.ceylon.model.typechecker.model.Constructor) Node(com.redhat.ceylon.compiler.typechecker.tree.Node) JCTree(com.sun.tools.javac.tree.JCTree) Tree(com.redhat.ceylon.compiler.typechecker.tree.Tree) Class(com.redhat.ceylon.model.typechecker.model.Class) JCNewClass(com.sun.tools.javac.tree.JCTree.JCNewClass) TypeAlias(com.redhat.ceylon.model.typechecker.model.TypeAlias) TypeDeclaration(com.redhat.ceylon.model.typechecker.model.TypeDeclaration)

Example 3 with TypeParameter

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);
    }
}
Also used : Function(com.redhat.ceylon.model.typechecker.model.Function) TypeParameter(com.redhat.ceylon.model.typechecker.model.TypeParameter) Scope(com.redhat.ceylon.model.typechecker.model.Scope) Constructor(com.redhat.ceylon.model.typechecker.model.Constructor) FunctionOrValue(com.redhat.ceylon.model.typechecker.model.FunctionOrValue) FieldValue(com.redhat.ceylon.model.loader.model.FieldValue) Value(com.redhat.ceylon.model.typechecker.model.Value) Class(com.redhat.ceylon.model.typechecker.model.Class) JCNewClass(com.sun.tools.javac.tree.JCTree.JCNewClass) TypeAlias(com.redhat.ceylon.model.typechecker.model.TypeAlias) TypedDeclaration(com.redhat.ceylon.model.typechecker.model.TypedDeclaration) Declaration(com.redhat.ceylon.model.typechecker.model.Declaration) TypeDeclaration(com.redhat.ceylon.model.typechecker.model.TypeDeclaration) Package(com.redhat.ceylon.model.typechecker.model.Package) Interface(com.redhat.ceylon.model.typechecker.model.Interface) ClassOrInterface(com.redhat.ceylon.model.typechecker.model.ClassOrInterface)

Example 4 with TypeParameter

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;
}
Also used : ClassOrInterface(com.redhat.ceylon.model.typechecker.model.ClassOrInterface) Type(com.redhat.ceylon.model.typechecker.model.Type) TypeParameter(com.redhat.ceylon.model.typechecker.model.TypeParameter)

Example 5 with TypeParameter

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)));
}
Also used : IntersectionType(com.redhat.ceylon.model.typechecker.model.IntersectionType) Type(com.redhat.ceylon.model.typechecker.model.Type) UnionType(com.redhat.ceylon.model.typechecker.model.UnionType) TypeParameter(com.redhat.ceylon.model.typechecker.model.TypeParameter) TypeParser(com.redhat.ceylon.model.loader.TypeParser) SiteVariance(com.redhat.ceylon.model.typechecker.model.SiteVariance) Test(org.junit.Test)

Aggregations

TypeParameter (com.redhat.ceylon.model.typechecker.model.TypeParameter)59 Type (com.redhat.ceylon.model.typechecker.model.Type)40 JCTypeParameter (com.sun.tools.javac.tree.JCTree.JCTypeParameter)24 TypeDeclaration (com.redhat.ceylon.model.typechecker.model.TypeDeclaration)23 ModelUtil.appliedType (com.redhat.ceylon.model.typechecker.model.ModelUtil.appliedType)21 ArrayList (java.util.ArrayList)15 Function (com.redhat.ceylon.model.typechecker.model.Function)14 Class (com.redhat.ceylon.model.typechecker.model.Class)13 ClassOrInterface (com.redhat.ceylon.model.typechecker.model.ClassOrInterface)13 Declaration (com.redhat.ceylon.model.typechecker.model.Declaration)13 TypedDeclaration (com.redhat.ceylon.model.typechecker.model.TypedDeclaration)13 Parameter (com.redhat.ceylon.model.typechecker.model.Parameter)12 TypedReference (com.redhat.ceylon.model.typechecker.model.TypedReference)12 JCExpression (com.sun.tools.javac.tree.JCTree.JCExpression)12 JCNewClass (com.sun.tools.javac.tree.JCTree.JCNewClass)10 Generic (com.redhat.ceylon.model.typechecker.model.Generic)9 Constructor (com.redhat.ceylon.model.typechecker.model.Constructor)8 Interface (com.redhat.ceylon.model.typechecker.model.Interface)8 ParameterList (com.redhat.ceylon.model.typechecker.model.ParameterList)8 FunctionOrValue (com.redhat.ceylon.model.typechecker.model.FunctionOrValue)7