Search in sources :

Example 11 with TypedReference

use of com.redhat.ceylon.model.typechecker.model.TypedReference in project ceylon-compiler by ceylon.

the class ExpressionTransformer method transformAssignment.

private JCExpression transformAssignment(Node op, Tree.Term leftTerm, Tree.Term rightTerm) {
    // Remember and disable inStatement for RHS
    boolean tmpInStatement = inStatement;
    inStatement = false;
    // FIXME: can this be anything else than a Tree.MemberOrTypeExpression or Tree.ParameterizedExpression?
    final JCExpression rhs;
    BoxingStrategy boxing;
    if (leftTerm instanceof Tree.MemberOrTypeExpression) {
        TypedDeclaration decl = (TypedDeclaration) ((Tree.MemberOrTypeExpression) leftTerm).getDeclaration();
        boxing = CodegenUtil.getBoxingStrategy(decl);
        if (decl instanceof Value) {
            Value val = (Value) decl;
            if (val.getSetter() != null && val.getSetter().getUnboxed() != null) {
                boxing = CodegenUtil.getBoxingStrategy(val.getSetter());
            }
        }
        Type targetType = tmpInStatement ? leftTerm.getTypeModel() : rightTerm.getTypeModel();
        // if we're dealing with widening do not trust the type of the declaration and get the real type
        if (CodegenUtil.hasUntrustedType(decl)) {
            TypedReference typedRef = (TypedReference) ((Tree.MemberOrTypeExpression) leftTerm).getTarget();
            TypedReference nonWideningTypedRef = nonWideningTypeDecl(typedRef);
            targetType = nonWideningType(typedRef, nonWideningTypedRef);
        }
        rhs = transformExpression(rightTerm, boxing, targetType, decl.hasUncheckedNullType() ? EXPR_TARGET_ACCEPTS_NULL : 0);
    } else {
        // instanceof Tree.ParameterizedExpression
        boxing = CodegenUtil.getBoxingStrategy(leftTerm);
        Tree.ParameterizedExpression paramExpr = (Tree.ParameterizedExpression) leftTerm;
        FunctionOrValue decl = (FunctionOrValue) ((Tree.MemberOrTypeExpression) paramExpr.getPrimary()).getDeclaration();
        CallableBuilder callableBuilder = CallableBuilder.anonymous(gen(), paramExpr, decl, (Tree.Expression) rightTerm, paramExpr.getParameterLists(), paramExpr.getPrimary().getTypeModel(), decl instanceof Function ? !((Function) decl).isDeferred() : false);
        rhs = callableBuilder.build();
    }
    if (tmpInStatement) {
        return transformAssignment(op, leftTerm, rhs);
    } else {
        Type valueType = rightTerm.getTypeModel();
        if (isNull(valueType))
            valueType = leftTerm.getTypeModel();
        return transformAssignAndReturnOperation(op, leftTerm, boxing == BoxingStrategy.BOXED, leftTerm.getTypeModel(), valueType, new AssignAndReturnOperationFactory() {

            @Override
            public JCExpression getNewValue(JCExpression previousValue) {
                return rhs;
            }
        });
    }
}
Also used : TypedDeclaration(com.redhat.ceylon.model.typechecker.model.TypedDeclaration) TypedReference(com.redhat.ceylon.model.typechecker.model.TypedReference) Function(com.redhat.ceylon.model.typechecker.model.Function) Type(com.redhat.ceylon.model.typechecker.model.Type) 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) JCTree(com.sun.tools.javac.tree.JCTree) Tree(com.redhat.ceylon.compiler.typechecker.tree.Tree) FunctionOrValue(com.redhat.ceylon.model.typechecker.model.FunctionOrValue)

Example 12 with TypedReference

use of com.redhat.ceylon.model.typechecker.model.TypedReference in project ceylon-compiler by ceylon.

the class AbstractTransformer method getGetterInterfaceType.

Type getGetterInterfaceType(TypedDeclaration attrTypedDecl) {
    TypedReference typedRef = getTypedReference(attrTypedDecl);
    TypedReference nonWideningTypedRef = nonWideningTypeDecl(typedRef);
    Type nonWideningType = nonWideningType(typedRef, nonWideningTypedRef);
    Type type;
    boolean unboxed = CodegenUtil.isUnBoxed(attrTypedDecl);
    if (unboxed && isCeylonBoolean(nonWideningType)) {
        type = javacCeylonTypeToProducedType(syms().ceylonGetterBooleanType);
    } else if (unboxed && isCeylonInteger(nonWideningType)) {
        type = javacCeylonTypeToProducedType(syms().ceylonGetterLongType);
    } else if (unboxed && isCeylonFloat(nonWideningType)) {
        type = javacCeylonTypeToProducedType(syms().ceylonGetterDoubleType);
    } else if (unboxed && isCeylonCharacter(nonWideningType)) {
        type = javacCeylonTypeToProducedType(syms().ceylonGetterIntType);
    } else if (unboxed && isCeylonByte(nonWideningType)) {
        type = javacCeylonTypeToProducedType(syms().ceylonGetterByteType);
    } else {
        type = javacCeylonTypeToProducedType(syms().ceylonGetterType);
        Type typeArg = nonWideningType;
        if (unboxed && isCeylonString(typeArg)) {
            typeArg = javacJavaTypeToProducedType(syms().stringType);
        }
        type = appliedType(type.getDeclaration(), typeArg);
    }
    return type;
}
Also used : Type(com.redhat.ceylon.model.typechecker.model.Type) ModelUtil.appliedType(com.redhat.ceylon.model.typechecker.model.ModelUtil.appliedType) TypedReference(com.redhat.ceylon.model.typechecker.model.TypedReference)

Example 13 with TypedReference

use of com.redhat.ceylon.model.typechecker.model.TypedReference in project ceylon-compiler by ceylon.

the class AbstractTransformer method getTypeForParameter.

Type getTypeForParameter(Parameter parameter, Reference producedReference, int flags) {
    /* this method is bogus: It's really trying to answer 
         * "what's the type of the java declaration of the given parameter", 
         * but using the ceylon type system to do so. 
         */
    boolean functional = parameter.getModel() instanceof Function;
    if (producedReference == null) {
        return parameter.getType();
    }
    final TypedReference producedTypedReference = producedReference.getTypedParameter(parameter);
    final Type type = functional ? producedTypedReference.getFullType() : producedTypedReference.getType();
    final TypedDeclaration producedParameterDecl = producedTypedReference.getDeclaration();
    final Type declType = producedParameterDecl.getType();
    // be more resilient to upstream errors
    if (declType == null)
        return typeFact.getUnknownType();
    if (isJavaVariadic(parameter) && (flags & TP_SEQUENCED_TYPE) == 0) {
        // type of param must be Iterable<T>
        Type elementType = typeFact.getIteratedType(type);
        if (elementType == null) {
            log.error("ceylon", "Invalid type for Java variadic parameter: " + type.asQualifiedString());
            return type;
        }
        return elementType;
    }
    if (declType.isClassOrInterface()) {
        return type;
    } else if ((declType.isTypeParameter()) && (flags & TP_TO_BOUND) != 0) {
        if (!declType.getSatisfiedTypes().isEmpty()) {
            // use upper bound
            Type upperBound = declType.getSatisfiedTypes().get(0);
            // make sure we apply the type arguments
            upperBound = substituteTypeArgumentsForTypeParameterBound(producedReference, upperBound);
            Type self = upperBound.getDeclaration().getSelfType();
            if (self != null) {
                // make sure we apply the type arguments
                Type selfUpperBound = self.substitute(upperBound);
                if (!willEraseToObject(selfUpperBound) && (willEraseToObject(type) || expressionGen().needsCast(type, selfUpperBound, false, false, false))) {
                    return selfUpperBound;
                }
            }
            if (!willEraseToObject(upperBound) && (willEraseToObject(type) || expressionGen().needsCast(type, upperBound, false, false, false))) {
                return upperBound;
            }
        }
    }
    return type;
}
Also used : Function(com.redhat.ceylon.model.typechecker.model.Function) TypedDeclaration(com.redhat.ceylon.model.typechecker.model.TypedDeclaration) Type(com.redhat.ceylon.model.typechecker.model.Type) ModelUtil.appliedType(com.redhat.ceylon.model.typechecker.model.ModelUtil.appliedType) TypedReference(com.redhat.ceylon.model.typechecker.model.TypedReference)

Example 14 with TypedReference

use of com.redhat.ceylon.model.typechecker.model.TypedReference in project ceylon-compiler by ceylon.

the class NamedArgumentInvocation method bindAttributeArgument.

private void bindAttributeArgument(Tree.AttributeArgument attrArg, Parameter declaredParam, Naming.SyntheticName argName) {
    ListBuffer<JCStatement> statements;
    final Value model = attrArg.getDeclarationModel();
    final String name = model.getName();
    String className = Naming.getAttrClassName(model, 0);
    final List<JCTree> attrClass = gen.gen().transformAttribute(model, name, className, null, attrArg.getBlock(), attrArg.getSpecifierExpression(), null, null);
    TypedReference typedRef = gen.getTypedReference(model);
    TypedReference nonWideningTypedRef = gen.nonWideningTypeDecl(typedRef);
    Type nonWideningType = gen.nonWideningType(typedRef, nonWideningTypedRef);
    Type type = parameterType(declaredParam, model.getType(), 0);
    final BoxingStrategy boxType = getNamedParameterBoxingStrategy(declaredParam);
    JCExpression initValue = gen.make().Apply(null, gen.makeSelect(gen.makeUnquotedIdent(className), Naming.getGetterName(model)), List.<JCExpression>nil());
    initValue = gen.expressionGen().applyErasureAndBoxing(initValue, nonWideningType, !CodegenUtil.isUnBoxed(nonWideningTypedRef.getDeclaration()), boxType, type);
    JCTree.JCVariableDecl var = gen.make().VarDef(gen.make().Modifiers(FINAL, List.<JCAnnotation>nil()), argName.asName(), gen.makeJavaType(type, boxType == BoxingStrategy.BOXED ? JT_NO_PRIMITIVES : 0), initValue);
    statements = toStmts(attrArg, attrClass).append(var);
    bind(declaredParam, argName, gen.makeJavaType(type, boxType == BoxingStrategy.BOXED ? JT_NO_PRIMITIVES : 0), statements.toList());
}
Also used : Type(com.redhat.ceylon.model.typechecker.model.Type) JCExpression(com.sun.tools.javac.tree.JCTree.JCExpression) TypedReference(com.redhat.ceylon.model.typechecker.model.TypedReference) JCVariableDecl(com.sun.tools.javac.tree.JCTree.JCVariableDecl) FunctionOrValue(com.redhat.ceylon.model.typechecker.model.FunctionOrValue) Value(com.redhat.ceylon.model.typechecker.model.Value) JCTree(com.sun.tools.javac.tree.JCTree) JCStatement(com.sun.tools.javac.tree.JCTree.JCStatement) BoxingStrategy(com.redhat.ceylon.compiler.java.codegen.AbstractTransformer.BoxingStrategy) JCAnnotation(com.sun.tools.javac.tree.JCTree.JCAnnotation)

Example 15 with TypedReference

use of com.redhat.ceylon.model.typechecker.model.TypedReference in project ceylon-compiler by ceylon.

the class AbstractTransformer method getRefinedDeclaration.

/*
     * We have several special cases here to find the best non-widening refinement in case of multiple inheritace:
     * 
     * - The first special case is for some decls like None.first, which inherits from ContainerWithFirstElement
     * twice: once with Nothing (erased to j.l.Object) and once with Element (a type param). Now, in order to not widen the
     * return type it can't be Nothing (j.l.Object), it must be Element (a type param that is not instantiated), because in Java
     * a type param refines j.l.Object but not the other way around.
     * - The second special case is when implementing an interface first with a non-erased type, then with an erased type. In this
     * case we want the refined decl to be the one with the non-erased type.
     * - The third special case is when we implement a declaration via multiple super types, without having any refining
     * declarations in those supertypes, simply by instantiating a common super type with different type parameters
     */
private TypedReference getRefinedDeclaration(TypedReference typedReference, Type currentType) {
    TypedDeclaration decl = typedReference.getDeclaration();
    TypedDeclaration modelRefinedDecl = (TypedDeclaration) decl.getRefinedDeclaration();
    Type referenceQualifyingType = typedReference.getQualifyingType();
    boolean forMixinMethod = currentType != null && decl.getContainer() instanceof ClassOrInterface && referenceQualifyingType != null && !Decl.equal(referenceQualifyingType.getDeclaration(), currentType.getDeclaration());
    // quick exit
    if (Decl.equal(decl, modelRefinedDecl) && !forMixinMethod)
        return null;
    // modelRefinedDecl exists, but perhaps it's the toplevel refinement and not the one Java will look at
    if (!forMixinMethod)
        modelRefinedDecl = getFirstRefinedDeclaration(decl);
    TypeDeclaration qualifyingDeclaration = currentType.getDeclaration();
    if (qualifyingDeclaration instanceof ClassOrInterface) {
        // if both are returning unboxed void we're good
        if (Decl.isUnboxedVoid(decl) && Decl.isUnboxedVoid(modelRefinedDecl))
            return null;
        // only try to find better if we're erasing to Object and we're not returning a type param
        if (willEraseToObject(typedReference.getType()) || isWideningTypeArguments(decl.getType(), modelRefinedDecl.getType(), true) && !isTypeParameter(typedReference.getType())) {
            ClassOrInterface declaringType = (ClassOrInterface) qualifyingDeclaration;
            Set<TypedDeclaration> refinedMembers = getRefinedMembers(declaringType, decl.getName(), com.redhat.ceylon.model.typechecker.model.ModelUtil.getSignature(decl), false);
            // now we must select a different refined declaration if we refine it more than once
            if (refinedMembers.size() > (forMixinMethod ? 0 : 1)) {
                // first case
                for (TypedDeclaration refinedDecl : refinedMembers) {
                    // get the type reference to see if any eventual type param is instantiated in our inheritance of this type/method
                    TypedReference refinedTypedReference = getRefinedTypedReference(typedReference, refinedDecl);
                    // if it is not instantiated, that's the one we're looking for
                    if (isTypeParameter(refinedTypedReference.getType()))
                        return refinedTypedReference;
                }
                // second case
                for (TypedDeclaration refinedDecl : refinedMembers) {
                    // get the type reference to see if any eventual type param is instantiated in our inheritance of this type/method
                    TypedReference refinedTypedReference = getRefinedTypedReference(typedReference, refinedDecl);
                    // if we're not erasing this one to Object let's select it
                    if (!willEraseToObject(refinedTypedReference.getType()) && !isWideningTypeArguments(refinedDecl.getType(), modelRefinedDecl.getType(), true))
                        return refinedTypedReference;
                }
                // third case
                if (isTypeParameter(modelRefinedDecl.getType())) {
                    // it can happen that we have inherited a method twice from a single refined declaration 
                    // via different supertype instantiations, without having ever refined them in supertypes
                    // so we try each super type to see if we already have a matching typed reference
                    // first super type
                    Type extendedType = declaringType.getExtendedType();
                    if (extendedType != null) {
                        TypedReference refinedTypedReference = getRefinedTypedReference(extendedType, modelRefinedDecl);
                        Type refinedType = refinedTypedReference.getType();
                        if (!isTypeParameter(refinedType) && !willEraseToObject(refinedType))
                            return refinedTypedReference;
                    }
                    // then satisfied interfaces
                    for (Type satisfiedType : declaringType.getSatisfiedTypes()) {
                        TypedReference refinedTypedReference = getRefinedTypedReference(satisfiedType, modelRefinedDecl);
                        Type refinedType = refinedTypedReference.getType();
                        if (!isTypeParameter(refinedType) && !willEraseToObject(refinedType))
                            return refinedTypedReference;
                    }
                }
            }
        }
        /*
             * Now there's another crazy case:
             * 
             * interface Top<out Element> {
             *  Top<Element> ret => nothing;
             * }
             * interface Left satisfies Top<Integer> {}
             * interface Right satisfies Top<String> {}
             * class Bottom() satisfies Left&Right {}
             * 
             * Where Bottom.ret does not exist and is typed as returning Integer&String which is Nothing, erased to Object,
             * and we look at what it refines and find only a single definition Top.ret typed as returning Integer&String (Nothing),
             * so we think there's no widening, but Java will only see Top<Integer>.ret from Left, and that's the one we want
             * to use for determining widening.
             * See https://github.com/ceylon/ceylon-compiler/issues/1765
             */
        Type firstInstantiation = isInheritedWithDifferentTypeArguments(modelRefinedDecl.getContainer(), currentType);
        if (firstInstantiation != null) {
            TypedReference firstInstantiationTypedReference = getRefinedTypedReference(firstInstantiation, modelRefinedDecl);
            Type firstInstantiationType = firstInstantiationTypedReference.getType();
            if (isWidening(decl.getType(), firstInstantiationType) || isWideningTypeArguments(decl.getType(), firstInstantiationType, true))
                return firstInstantiationTypedReference;
        }
    }
    return getRefinedTypedReference(typedReference, modelRefinedDecl);
}
Also used : TypedDeclaration(com.redhat.ceylon.model.typechecker.model.TypedDeclaration) ClassOrInterface(com.redhat.ceylon.model.typechecker.model.ClassOrInterface) Type(com.redhat.ceylon.model.typechecker.model.Type) ModelUtil.appliedType(com.redhat.ceylon.model.typechecker.model.ModelUtil.appliedType) TypedReference(com.redhat.ceylon.model.typechecker.model.TypedReference) TypeDeclaration(com.redhat.ceylon.model.typechecker.model.TypeDeclaration)

Aggregations

TypedReference (com.redhat.ceylon.model.typechecker.model.TypedReference)24 Type (com.redhat.ceylon.model.typechecker.model.Type)21 TypeParameter (com.redhat.ceylon.model.typechecker.model.TypeParameter)14 FunctionOrValue (com.redhat.ceylon.model.typechecker.model.FunctionOrValue)12 Value (com.redhat.ceylon.model.typechecker.model.Value)11 Function (com.redhat.ceylon.model.typechecker.model.Function)10 Parameter (com.redhat.ceylon.model.typechecker.model.Parameter)10 JavaBeanValue (com.redhat.ceylon.model.loader.model.JavaBeanValue)8 TypedDeclaration (com.redhat.ceylon.model.typechecker.model.TypedDeclaration)8 ModelUtil.appliedType (com.redhat.ceylon.model.typechecker.model.ModelUtil.appliedType)7 ParameterList (com.redhat.ceylon.model.typechecker.model.ParameterList)7 TypeDeclaration (com.redhat.ceylon.model.typechecker.model.TypeDeclaration)7 JCExpression (com.sun.tools.javac.tree.JCTree.JCExpression)7 ArrayList (java.util.ArrayList)6 Class (com.redhat.ceylon.model.typechecker.model.Class)5 Declaration (com.redhat.ceylon.model.typechecker.model.Declaration)5 JCNewClass (com.sun.tools.javac.tree.JCTree.JCNewClass)5 JCTypeParameter (com.sun.tools.javac.tree.JCTree.JCTypeParameter)5 ThrowerCatchallConstructor (com.redhat.ceylon.compiler.java.codegen.recovery.ThrowerCatchallConstructor)4 AnnotationList (com.redhat.ceylon.compiler.typechecker.tree.Tree.AnnotationList)4