Search in sources :

Example 36 with TypedDeclaration

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

the class AbstractTransformer method makeTypedDeclarationTypeDescriptorResolved.

private JCExpression makeTypedDeclarationTypeDescriptorResolved(TypedDeclaration declaration) {
    // figure out the method name
    String methodName = declaration.getPrefixedName();
    List<JCExpression> arguments;
    if (declaration instanceof Function)
        arguments = makeReifiedTypeArgumentsResolved(getTypeArguments((Function) declaration), true);
    else
        arguments = List.nil();
    if (declaration.isToplevel()) {
        JCExpression getterClassNameExpr;
        if (declaration instanceof Function) {
            getterClassNameExpr = naming.makeName(declaration, Naming.NA_FQ | Naming.NA_WRAPPER);
        } else {
            String getterClassName = Naming.getAttrClassName(declaration, 0);
            getterClassNameExpr = naming.makeUnquotedIdent(getterClassName);
        }
        arguments = arguments.prepend(makeSelect(getterClassNameExpr, "class"));
    } else
        arguments = arguments.prepend(make().Literal(methodName));
    JCMethodInvocation typedDeclarationDescriptor = make().Apply(null, makeSelect(makeTypeDescriptorType(), "functionOrValue"), arguments);
    // see if the declaration has a container too
    Declaration enclosingDeclaration = getDeclarationContainer(declaration);
    JCExpression containerType = null;
    if (enclosingDeclaration instanceof TypedDeclaration)
        containerType = makeTypedDeclarationTypeDescriptorResolved((TypedDeclaration) enclosingDeclaration);
    else if (enclosingDeclaration instanceof TypeDeclaration) {
        Type qualifyingType = ((TypeDeclaration) enclosingDeclaration).getType();
        containerType = makeReifiedTypeArgumentResolved(qualifyingType, true);
    }
    if (containerType == null) {
        return typedDeclarationDescriptor;
    } else {
        return make().Apply(null, makeSelect(makeTypeDescriptorType(), "member"), List.of(containerType, typedDeclarationDescriptor));
    }
}
Also used : Function(com.redhat.ceylon.model.typechecker.model.Function) JCMethodInvocation(com.sun.tools.javac.tree.JCTree.JCMethodInvocation) 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) JCExpression(com.sun.tools.javac.tree.JCTree.JCExpression) TypedDeclaration(com.redhat.ceylon.model.typechecker.model.TypedDeclaration) Declaration(com.redhat.ceylon.model.typechecker.model.Declaration) TypeDeclaration(com.redhat.ceylon.model.typechecker.model.TypeDeclaration) TypeDeclaration(com.redhat.ceylon.model.typechecker.model.TypeDeclaration)

Example 37 with TypedDeclaration

use of com.redhat.ceylon.model.typechecker.model.TypedDeclaration 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)

Example 38 with TypedDeclaration

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

the class AbstractTransformer method getFirstRefinedDeclaration.

private TypedDeclaration getFirstRefinedDeclaration(TypedDeclaration decl) {
    if (decl.getContainer() instanceof ClassOrInterface == false)
        return decl;
    java.util.List<Type> signature = com.redhat.ceylon.model.typechecker.model.ModelUtil.getSignature(decl);
    boolean overloaded = decl.isOverloaded() || decl.isAbstraction();
    Declaration refinedDeclaration = decl.getRefinedDeclaration();
    if (refinedDeclaration != null) {
        overloaded |= refinedDeclaration.isOverloaded() || refinedDeclaration.isAbstraction();
    }
    ClassOrInterface container = (ClassOrInterface) decl.getContainer();
    HashSet<TypeDeclaration> visited = new HashSet<TypeDeclaration>();
    // start looking for it, but skip this type, only lookup upwards of it
    TypedDeclaration firstRefinedDeclaration = getFirstRefinedDeclaration(container, decl, signature, visited, true, overloaded);
    // only keep the first refined decl if its type can be trusted: if it is not itself widening
    if (firstRefinedDeclaration != null) {
        if (CodegenUtil.hasUntrustedType(firstRefinedDeclaration))
            firstRefinedDeclaration = getFirstRefinedDeclaration(firstRefinedDeclaration);
    }
    return firstRefinedDeclaration != null ? firstRefinedDeclaration : decl;
}
Also used : ClassOrInterface(com.redhat.ceylon.model.typechecker.model.ClassOrInterface) 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) TypedDeclaration(com.redhat.ceylon.model.typechecker.model.TypedDeclaration) Declaration(com.redhat.ceylon.model.typechecker.model.Declaration) TypeDeclaration(com.redhat.ceylon.model.typechecker.model.TypeDeclaration) TypeDeclaration(com.redhat.ceylon.model.typechecker.model.TypeDeclaration) HashSet(java.util.HashSet)

Example 39 with TypedDeclaration

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

the class BoxingVisitor method visit.

@Override
public void visit(IndexExpression that) {
    super.visit(that);
    // we need to propagate from the underlying method call (item/span)
    if (that.getPrimary() == null || that.getPrimary().getTypeModel() == null)
        return;
    Type lhsModel = that.getPrimary().getTypeModel();
    if (lhsModel.getDeclaration() == null)
        return;
    String methodName = that.getElementOrRange() instanceof Tree.Element ? "get" : "span";
    // find the method from its declaration
    TypedDeclaration member = (TypedDeclaration) lhsModel.getDeclaration().getMember(methodName, null, false);
    if (member == null)
        return;
    propagateFromDeclaration(that, member);
}
Also used : TypedDeclaration(com.redhat.ceylon.model.typechecker.model.TypedDeclaration) Type(com.redhat.ceylon.model.typechecker.model.Type) Tree(com.redhat.ceylon.compiler.typechecker.tree.Tree)

Example 40 with TypedDeclaration

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

the class BoxingDeclarationVisitor method boxAttribute.

private void boxAttribute(TypedDeclaration declaration, Node that) {
    // deal with invalid input
    if (declaration == null)
        return;
    TypedDeclaration refinedDeclaration = null;
    refinedDeclaration = (TypedDeclaration) CodegenUtil.getTopmostRefinedDeclaration(declaration, optimisedMethodSpecifiersToMethods);
    // deal with invalid input
    if (refinedDeclaration == null)
        return;
    setBoxingState(declaration, refinedDeclaration, that);
}
Also used : TypedDeclaration(com.redhat.ceylon.model.typechecker.model.TypedDeclaration)

Aggregations

TypedDeclaration (com.redhat.ceylon.model.typechecker.model.TypedDeclaration)52 TypeDeclaration (com.redhat.ceylon.model.typechecker.model.TypeDeclaration)28 Declaration (com.redhat.ceylon.model.typechecker.model.Declaration)26 Type (com.redhat.ceylon.model.typechecker.model.Type)26 Function (com.redhat.ceylon.model.typechecker.model.Function)23 Tree (com.redhat.ceylon.compiler.typechecker.tree.Tree)17 JCExpression (com.sun.tools.javac.tree.JCTree.JCExpression)17 Class (com.redhat.ceylon.model.typechecker.model.Class)15 Value (com.redhat.ceylon.model.typechecker.model.Value)14 JCTree (com.sun.tools.javac.tree.JCTree)14 FunctionOrValue (com.redhat.ceylon.model.typechecker.model.FunctionOrValue)13 ClassOrInterface (com.redhat.ceylon.model.typechecker.model.ClassOrInterface)12 TypeParameter (com.redhat.ceylon.model.typechecker.model.TypeParameter)11 Constructor (com.redhat.ceylon.model.typechecker.model.Constructor)10 TypedReference (com.redhat.ceylon.model.typechecker.model.TypedReference)10 Parameter (com.redhat.ceylon.model.typechecker.model.Parameter)9 JCNewClass (com.sun.tools.javac.tree.JCTree.JCNewClass)9 Interface (com.redhat.ceylon.model.typechecker.model.Interface)8 ModelUtil.appliedType (com.redhat.ceylon.model.typechecker.model.ModelUtil.appliedType)8 AttributeDeclaration (com.redhat.ceylon.compiler.typechecker.tree.Tree.AttributeDeclaration)7