Search in sources :

Example 1 with Interface

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;
}
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 Interface

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;
}
Also used : ClassOrInterface(com.redhat.ceylon.model.typechecker.model.ClassOrInterface) Function(com.redhat.ceylon.model.typechecker.model.Function) JCExpression(com.sun.tools.javac.tree.JCTree.JCExpression) 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) TypeDeclaration(com.redhat.ceylon.model.typechecker.model.TypeDeclaration) Interface(com.redhat.ceylon.model.typechecker.model.Interface) ClassOrInterface(com.redhat.ceylon.model.typechecker.model.ClassOrInterface)

Example 3 with Interface

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);
}
Also used : Term(com.redhat.ceylon.compiler.typechecker.tree.Tree.Term) JCStatement(com.sun.tools.javac.tree.JCTree.JCStatement) JCVariableDecl(com.sun.tools.javac.tree.JCTree.JCVariableDecl) AssignmentOperatorTranslation(com.redhat.ceylon.compiler.java.codegen.Operators.AssignmentOperatorTranslation) OperatorTranslation(com.redhat.ceylon.compiler.java.codegen.Operators.OperatorTranslation) SyntheticName(com.redhat.ceylon.compiler.java.codegen.Naming.SyntheticName) Name(com.sun.tools.javac.util.Name) Type(com.redhat.ceylon.model.typechecker.model.Type) JCExpression(com.sun.tools.javac.tree.JCTree.JCExpression) JCTree(com.sun.tools.javac.tree.JCTree) Tree(com.redhat.ceylon.compiler.typechecker.tree.Tree) OptimisationStrategy(com.redhat.ceylon.compiler.java.codegen.Operators.OptimisationStrategy) Interface(com.redhat.ceylon.model.typechecker.model.Interface) ClassOrInterface(com.redhat.ceylon.model.typechecker.model.ClassOrInterface)

Example 4 with Interface

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);
    }
}
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 5 with Interface

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;
}
Also used : Scope(com.redhat.ceylon.model.typechecker.model.Scope) TypedDeclaration(com.redhat.ceylon.model.typechecker.model.TypedDeclaration) Declaration(com.redhat.ceylon.model.typechecker.model.Declaration) TypeDeclaration(com.redhat.ceylon.model.typechecker.model.TypeDeclaration) Interface(com.redhat.ceylon.model.typechecker.model.Interface) ClassOrInterface(com.redhat.ceylon.model.typechecker.model.ClassOrInterface)

Aggregations

Interface (com.redhat.ceylon.model.typechecker.model.Interface)56 ClassOrInterface (com.redhat.ceylon.model.typechecker.model.ClassOrInterface)53 TypeDeclaration (com.redhat.ceylon.model.typechecker.model.TypeDeclaration)35 Type (com.redhat.ceylon.model.typechecker.model.Type)30 TypedDeclaration (com.redhat.ceylon.model.typechecker.model.TypedDeclaration)21 Declaration (com.redhat.ceylon.model.typechecker.model.Declaration)20 Tree (com.redhat.ceylon.compiler.typechecker.tree.Tree)18 JCTree (com.sun.tools.javac.tree.JCTree)18 Class (com.redhat.ceylon.model.typechecker.model.Class)17 JCExpression (com.sun.tools.javac.tree.JCTree.JCExpression)17 LazyInterface (com.redhat.ceylon.model.loader.model.LazyInterface)14 JCNewClass (com.sun.tools.javac.tree.JCTree.JCNewClass)12 Scope (com.redhat.ceylon.model.typechecker.model.Scope)10 TypeParameter (com.redhat.ceylon.model.typechecker.model.TypeParameter)10 Function (com.redhat.ceylon.model.typechecker.model.Function)9 Value (com.redhat.ceylon.model.typechecker.model.Value)9 TypeParser (com.redhat.ceylon.model.loader.TypeParser)8 Constructor (com.redhat.ceylon.model.typechecker.model.Constructor)8 FunctionOrValue (com.redhat.ceylon.model.typechecker.model.FunctionOrValue)8 IntersectionType (com.redhat.ceylon.model.typechecker.model.IntersectionType)8