Search in sources :

Example 86 with TypedDeclaration

use of org.eclipse.ceylon.model.typechecker.model.TypedDeclaration in project ceylon by eclipse.

the class ExpressionTransformer method transformSpreadOperator.

private JCExpression transformSpreadOperator(final Tree.QualifiedMemberOrTypeExpression expr, TermTransformer transformer) {
    at(expr);
    boolean spreadMethodReferenceOuter = !expr.equals(spreading) && !isWithinInvocation() && isCeylonCallableSubtype(expr.getTypeModel());
    boolean spreadMethodReferenceInner = expr.equals(spreading) && isWithinInvocation();
    Tree.QualifiedMemberOrTypeExpression oldSpreading = spreading;
    if (spreadMethodReferenceOuter) {
        spreading = expr;
    }
    try {
        Naming.SyntheticName varBaseName = naming.alias("spread");
        ListBuffer<JCStatement> letStmts = new ListBuffer<JCStatement>();
        final Naming.SyntheticName srcIterableName;
        if (spreadMethodReferenceInner) {
            // use the var we initialized in the outer
            srcIterableName = this.memberPrimary;
        } else {
            srcIterableName = varBaseName.suffixedBy(Suffix.$iterable$);
        }
        if (spreadMethodReferenceOuter) {
            // if we're in the outer, note then name of the var for use in the inner.
            this.memberPrimary = srcIterableName;
        }
        Naming.SyntheticName srcIteratorName = varBaseName.suffixedBy(Suffix.$iterator$);
        Type srcElementType = expr.getTarget().getQualifyingType();
        JCExpression srcIterableExpr;
        boolean isSuperOrSuperOf = false;
        Type srcIterableType;
        if (typeFact().isIterableType(expr.getPrimary().getTypeModel())) {
            srcIterableType = typeFact().getIterableType(srcElementType);
        } else if (typeFact().isJavaIterableType(expr.getPrimary().getTypeModel())) {
            srcIterableType = typeFact().getJavaIterableDeclaration().appliedType(null, Collections.singletonList(srcElementType));
        } else if (typeFact().isJavaArrayType(expr.getPrimary().getTypeModel())) {
            srcIterableType = expr.getPrimary().getTypeModel();
            srcElementType = typeFact().getJavaArrayElementType(srcIterableType);
        } else {
            return makeErroneous(expr, "unhandled iterable type");
        }
        if (spreadMethodReferenceInner) {
            srcIterableExpr = srcIterableName.makeIdent();
        } else {
            boolean isSuper = isSuper(expr.getPrimary());
            isSuperOrSuperOf = isSuper || isSuperOf(expr.getPrimary());
            if (isSuperOrSuperOf) {
                // so we just refer to it later
                if (isSuper) {
                    Declaration member = expr.getPrimary().getTypeModel().getDeclaration().getMember("iterator", null, false);
                    srcIterableExpr = transformSuper(expr, (TypeDeclaration) member.getContainer());
                } else
                    srcIterableExpr = transformSuperOf(expr, expr.getPrimary(), "iterator");
            } else {
                srcIterableExpr = transformExpression(expr.getPrimary(), BoxingStrategy.BOXED, srcIterableType);
            }
        }
        // do not capture the iterable for super invocations: see above
        if (!spreadMethodReferenceInner && !isSuperOrSuperOf) {
            JCVariableDecl srcIterable = null;
            JCExpression srcIterableTypeExpr = makeJavaType(srcIterableType, JT_NO_PRIMITIVES);
            srcIterable = makeVar(Flags.FINAL, srcIterableName, srcIterableTypeExpr, srcIterableExpr);
            letStmts.prepend(srcIterable);
        }
        /* public Object next() {
             *     Object result;
             *     if (!((result = iterator.next()) instanceof Finished)) {
             *         result = transformedMember(result);
             *     }
             *     return result;
             */
        /* Any arguments in the member of the spread would get re-evaluated on each iteration
             * so we need to shift them to the scope of the Let to ensure they're evaluated once. 
             */
        boolean aliasArguments = transformer instanceof InvocationTermTransformer && ((InvocationTermTransformer) transformer).invocation.getNode() instanceof Tree.InvocationExpression && ((Tree.InvocationExpression) ((InvocationTermTransformer) transformer).invocation.getNode()).getPositionalArgumentList() != null;
        if (aliasArguments) {
            ((InvocationTermTransformer) transformer).callBuilder.argumentHandling(CallBuilder.CB_ALIAS_ARGS, varBaseName);
        }
        JCNewClass iterableClass;
        boolean prevSyntheticClassBody = expressionGen().withinSyntheticClassBody(true);
        try {
            Naming.SyntheticName iteratorResultName = varBaseName.suffixedBy(Suffix.$element$);
            JCExpression transformedElement = applyErasureAndBoxing(iteratorResultName.makeIdent(), typeFact().getAnythingType(), CodegenUtil.hasTypeErased(expr.getPrimary()), true, BoxingStrategy.BOXED, srcElementType, 0);
            transformedElement = transformMemberExpression(expr, transformedElement, transformer);
            // be handled by the previous recursion
            if (spreadMethodReferenceOuter) {
                return make().LetExpr(letStmts.toList(), transformedElement);
            }
            Type resultElementType = expr.getTarget().getType();
            final Type resultAbsentType;
            transformedElement = applyErasureAndBoxing(transformedElement, resultElementType, // not necessarily of the applied member
            expr.getTarget().getDeclaration() instanceof TypedDeclaration ? CodegenUtil.hasTypeErased((TypedDeclaration) expr.getTarget().getDeclaration()) : false, !CodegenUtil.isUnBoxed(expr), BoxingStrategy.BOXED, resultElementType, 0);
            MethodDefinitionBuilder nextMdb = MethodDefinitionBuilder.systemMethod(this, "next");
            nextMdb.isOverride(true);
            nextMdb.annotationFlags(Annotations.IGNORE);
            nextMdb.modifiers(Flags.PUBLIC | Flags.FINAL);
            nextMdb.resultType(new TransformedType(make().Type(syms().objectType)));
            final List<JCTree> l;
            if (typeFact().isIterableType(expr.getPrimary().getTypeModel())) {
                // private Iterator<srcElementType> iterator = srcIterableName.iterator();
                JCVariableDecl srcIterator = makeVar(Flags.FINAL, srcIteratorName, makeJavaType(typeFact().getIteratorType(srcElementType)), make().Apply(null, // for super we do not capture it because we can't and it's constant anyways
                naming.makeQualIdent(isSuperOrSuperOf ? srcIterableExpr : srcIterableName.makeIdent(), "iterator"), List.<JCExpression>nil()));
                resultAbsentType = typeFact().getIteratedAbsentType(expr.getPrimary().getTypeModel());
                nextMdb.body(List.of(makeVar(iteratorResultName, make().Type(syms().objectType), null), make().If(make().Unary(JCTree.Tag.NOT, make().TypeTest(make().Assign(iteratorResultName.makeIdent(), make().Apply(null, naming.makeQualIdent(srcIteratorName.makeIdent(), "next"), List.<JCExpression>nil())), make().Type(syms().ceylonFinishedType))), make().Block(0, List.<JCStatement>of(make().Exec(make().Assign(iteratorResultName.makeIdent(), transformedElement)))), null), make().Return(iteratorResultName.makeIdent())));
                l = List.of(srcIterator, nextMdb.build());
            } else if (typeFact().isJavaIterableType(expr.getPrimary().getTypeModel())) {
                // private Iterator<srcElementType> iterator = srcIterableName.iterator();
                JCVariableDecl srcIterator = makeVar(Flags.PRIVATE | Flags.FINAL, srcIteratorName, makeJavaType(typeFact().getJavaIteratorType(srcElementType)), make().Apply(null, // for super we do not capture it because we can't and it's constant anyways
                naming.makeQualIdent(isSuperOrSuperOf ? srcIterableExpr : srcIterableName.makeIdent(), "iterator"), List.<JCExpression>nil()));
                resultAbsentType = typeFact().getNullType();
                nextMdb.body(List.<JCStatement>of(make().If(make().Apply(null, naming.makeQualIdent(srcIteratorName.makeIdent(), "hasNext"), List.<JCExpression>nil()), make().Block(0, List.<JCStatement>of(makeVar(iteratorResultName, make().Type(syms().objectType), make().Apply(null, naming.makeQualIdent(srcIteratorName.makeIdent(), "next"), List.<JCExpression>nil())), make().Return(transformedElement))), make().Return(makeFinished()))));
                l = List.of(srcIterator, nextMdb.build());
            } else if (typeFact().isJavaArrayType(expr.getPrimary().getTypeModel())) {
                resultAbsentType = typeFact().getNullType();
                JCVariableDecl srcIndex = makeVar(Flags.PRIVATE, srcIteratorName, make().Type(syms().intType), make().Literal(0));
                JCExpression indexed = make().Indexed(srcIterableName.makeIdent(), make().Unary(Tag.POSTINC, srcIteratorName.makeIdent()));
                if (typeFact().isJavaPrimitiveArrayType(expr.getPrimary().getTypeModel())) {
                    indexed = applyErasureAndBoxing(indexed, srcElementType, false, BoxingStrategy.BOXED, srcElementType);
                }
                nextMdb.body(List.<JCStatement>of(make().If(make().Binary(Tag.LT, srcIteratorName.makeIdent(), // for super we do not capture it because we can't and it's constant anyways
                naming.makeQualIdent(isSuperOrSuperOf ? srcIterableExpr : srcIterableName.makeIdent(), "length")), make().Block(0, List.<JCStatement>of(makeVar(iteratorResultName, make().Type(syms().objectType), indexed), make().Return(transformedElement))), make().Return(makeFinished()))));
                l = List.of(srcIndex, nextMdb.build());
            } else {
                return makeErroneous(expr, "unhandled iterable type");
            }
            // new AbstractIterator()
            JCNewClass iteratorClass = make().NewClass(null, null, make().TypeApply(make().QualIdent(syms().ceylonAbstractIteratorType.tsym), List.of(makeJavaType(resultElementType, JT_TYPE_ARGUMENT))), List.of(makeReifiedTypeArgument(resultElementType)), make().AnonymousClassDef(make().Modifiers(0), l));
            MethodDefinitionBuilder iteratorMdb = MethodDefinitionBuilder.systemMethod(this, "iterator");
            iteratorMdb.isOverride(true);
            iteratorMdb.annotationFlags(Annotations.IGNORE);
            iteratorMdb.modifiers(Flags.PUBLIC | Flags.FINAL);
            iteratorMdb.resultType(new TransformedType(makeJavaType(typeFact().getIteratorType(resultElementType)), makeAtNonNull()));
            iteratorMdb.body(make().Return(iteratorClass));
            // new AbstractIterable()
            iterableClass = make().NewClass(null, null, make().TypeApply(make().QualIdent(syms().ceylonAbstractIterableType.tsym), List.of(makeJavaType(resultElementType, JT_TYPE_ARGUMENT), makeJavaType(resultAbsentType, JT_TYPE_ARGUMENT))), List.of(makeReifiedTypeArgument(resultElementType), makeReifiedTypeArgument(resultAbsentType)), make().AnonymousClassDef(make().Modifiers(0), List.<JCTree>of(iteratorMdb.build())));
        } finally {
            expressionGen().withinSyntheticClassBody(prevSyntheticClassBody);
        }
        if (aliasArguments) {
            letStmts = letStmts.appendList(((InvocationTermTransformer) transformer).callBuilder.getStatements());
        }
        JCMethodInvocation result = make().Apply(null, naming.makeQualIdent(iterableClass, "sequence"), List.<JCExpression>nil());
        JCExpression spread = letStmts.isEmpty() ? result : make().LetExpr(letStmts.toList(), result);
        // Do we *statically* know the result must be a Sequence
        final boolean primaryIsSequence = typeFact().isNonemptyIterableType(expr.getPrimary().getTypeModel());
        Type returnElementType = expr.getTarget().getType();
        if (primaryIsSequence) {
            int flags = EXPR_DOWN_CAST;
            spread = applyErasureAndBoxing(spread, typeFact().getSequentialType(returnElementType), false, true, BoxingStrategy.BOXED, primaryIsSequence ? typeFact().getSequenceType(returnElementType) : typeFact().getSequentialType(returnElementType), flags);
        }
        return spread;
    } finally {
        spreading = oldSpreading;
    }
}
Also used : TypedDeclaration(org.eclipse.ceylon.model.typechecker.model.TypedDeclaration) ListBuffer(org.eclipse.ceylon.langtools.tools.javac.util.ListBuffer) JCTree(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree) JCStatement(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCStatement) JCVariableDecl(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCVariableDecl) JCMethodInvocation(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCMethodInvocation) UnionType(org.eclipse.ceylon.model.typechecker.model.UnionType) Type(org.eclipse.ceylon.model.typechecker.model.Type) JCExpression(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCExpression) JCTree(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree) Tree(org.eclipse.ceylon.compiler.typechecker.tree.Tree) JCNewClass(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCNewClass) SyntheticName(org.eclipse.ceylon.compiler.java.codegen.Naming.SyntheticName) TypedDeclaration(org.eclipse.ceylon.model.typechecker.model.TypedDeclaration) TypeDeclaration(org.eclipse.ceylon.model.typechecker.model.TypeDeclaration) Declaration(org.eclipse.ceylon.model.typechecker.model.Declaration) TypeDeclaration(org.eclipse.ceylon.model.typechecker.model.TypeDeclaration)

Example 87 with TypedDeclaration

use of org.eclipse.ceylon.model.typechecker.model.TypedDeclaration in project ceylon by eclipse.

the class ClassTransformer method concreteMembersFromSuperinterfaces.

/**
 * Generates companion fields ($Foo$impl) and methods
 */
private void concreteMembersFromSuperinterfaces(final Class model, ClassDefinitionBuilder classBuilder, Type satisfiedType, Set<Interface> satisfiedInterfaces) {
    satisfiedType = satisfiedType.resolveAliases();
    Interface iface = (Interface) satisfiedType.getDeclaration();
    if (satisfiedInterfaces.contains(iface) || iface.isIdentifiable()) {
        return;
    }
    // then don't instantiate it...
    if (hasImpl(iface)) {
        // ... otherwise for each satisfied interface,
        // instantiate an instance of the
        // companion class in the constructor and assign it to a
        // $Interface$impl field
        transformInstantiateCompanions(classBuilder, model, iface, satisfiedType);
    }
    if (!ModelUtil.isCeylonDeclaration(iface)) {
        // let's not try to implement CMI for Java interfaces
        return;
    }
    // For each super interface
    for (Declaration member : sortedMembers(iface.getMembers())) {
        if (member instanceof Class) {
            Class klass = (Class) member;
            final Type typedMember = satisfiedType.getTypeMember(klass, Collections.<Type>emptyList());
            if (Strategy.generateInstantiator(member) && !klass.hasConstructors() && !model.isFormal() && needsCompanionDelegate(model, typedMember) && model.getDirectMember(member.getName(), null, false) == null) {
                // instantiator method implementation
                generateInstantiatorDelegate(classBuilder, satisfiedType, iface, klass, null, model.getType(), !member.isFormal());
            }
            if (klass.hasConstructors()) {
                for (Declaration m : klass.getMembers()) {
                    if (m instanceof Constructor && Strategy.generateInstantiator(m)) {
                        Constructor ctor = (Constructor) m;
                        generateInstantiatorDelegate(classBuilder, satisfiedType, iface, klass, ctor, model.getType(), true);
                    }
                }
            }
        }
        // type aliases are on the $impl class
        if (member instanceof TypeAlias)
            continue;
        if (Strategy.onlyOnCompanion(member)) {
            // (they're just private methods on the $impl)
            continue;
        }
        if (member instanceof Function) {
            Function method = (Function) member;
            final TypedReference typedMember = satisfiedType.getTypedMember(method, typesOfTypeParameters(method.getTypeParameters()));
            Declaration sub = (Declaration) model.getMember(method.getName(), getSignatureIfRequired(typedMember), false, true);
            if (sub instanceof Function) /* && !sub.isAbstraction()*/
            {
                Function subMethod = (Function) sub;
                if (subMethod.getParameterLists().isEmpty()) {
                    continue;
                }
                java.util.List<java.util.List<Type>> producedTypeParameterBounds = producedTypeParameterBounds(typedMember, subMethod);
                // final TypedReference refinedTypedMember = model.getType().getTypedMember(subMethod, Collections.<Type>emptyList());
                final java.util.List<TypeParameter> typeParameters = subMethod.getTypeParameters();
                final java.util.List<Parameter> parameters = subMethod.getFirstParameterList().getParameters();
                boolean hasOverloads = false;
                if (!satisfiedInterfaces.contains((Interface) method.getContainer())) {
                    for (Parameter param : parameters) {
                        if (Strategy.hasDefaultParameterValueMethod(param) && CodegenUtil.getTopmostRefinedDeclaration(param.getModel()).getContainer().equals(member)) {
                            final TypedReference typedParameter = typedMember.getTypedParameter(param);
                            // If that method has a defaulted parameter,
                            // we need to generate a default value method
                            // which also delegates to the $impl
                            final MethodDefinitionBuilder defaultValueDelegate = makeDelegateToCompanion(iface, typedMember, model.getType(), modifierTransformation().defaultValueMethodBridge(), typeParameters, producedTypeParameterBounds, typedParameter.getFullType(), Naming.getDefaultedParamMethodName(method, param), parameters.subList(0, parameters.indexOf(param)), param.getModel().getTypeErased(), null, param);
                            classBuilder.method(defaultValueDelegate);
                        }
                        if (Strategy.hasDefaultParameterOverload(param)) {
                            if ((method.isDefault() || method.isShared() && !method.isFormal()) && Decl.equal(method, subMethod)) {
                                MethodDefinitionBuilder overload = new DefaultedArgumentMethodTyped(new DaoThis((Tree.AnyMethod) null, null), MethodDefinitionBuilder.method(this, subMethod), typedMember, true).makeOverload(subMethod.getFirstParameterList(), param, typeParameters);
                                classBuilder.method(overload);
                            }
                            hasOverloads = true;
                        }
                    }
                }
                // delegating to the $impl instance
                if (needsCompanionDelegate(model, typedMember)) {
                    final MethodDefinitionBuilder concreteMemberDelegate = makeDelegateToCompanion(iface, typedMember, model.getType(), modifierTransformation().methodBridge(method), typeParameters, producedTypeParameterBounds, typedMember.getType(), naming.selector(method), method.getFirstParameterList().getParameters(), ((Function) member).getTypeErased(), null, null);
                    classBuilder.method(concreteMemberDelegate);
                }
                if (hasOverloads && (method.isDefault() || method.isShared() && !method.isFormal()) && Decl.equal(method, subMethod)) {
                    final MethodDefinitionBuilder canonicalMethod = makeDelegateToCompanion(iface, typedMember, model.getType(), modifierTransformation().canonicalMethodBridge(), subMethod.getTypeParameters(), producedTypeParameterBounds, typedMember.getType(), Naming.selector(method, Naming.NA_CANONICAL_METHOD), method.getFirstParameterList().getParameters(), ((Function) member).getTypeErased(), naming.selector(method), null);
                    classBuilder.method(canonicalMethod);
                }
            }
        } else if (member instanceof Value || member instanceof Setter) {
            TypedDeclaration attr = (TypedDeclaration) member;
            final TypedReference typedMember = satisfiedType.getTypedMember(attr, null);
            if (needsCompanionDelegate(model, typedMember)) {
                Setter setter = (member instanceof Setter) ? (Setter) member : null;
                if (member instanceof Value) {
                    Value getter = (Value) member;
                    if (member instanceof JavaBeanValue) {
                        setter = ((Value) member).getSetter();
                    }
                    final MethodDefinitionBuilder getterDelegate = makeDelegateToCompanion(iface, typedMember, model.getType(), modifierTransformation().getterBridge(getter), Collections.<TypeParameter>emptyList(), Collections.<java.util.List<Type>>emptyList(), typedMember.getType(), Naming.getGetterName(getter), Collections.<Parameter>emptyList(), getter.getTypeErased(), null, null);
                    classBuilder.method(getterDelegate);
                }
                if (setter != null) {
                    final MethodDefinitionBuilder setterDelegate = makeDelegateToCompanion(iface, satisfiedType.getTypedMember(setter, null), model.getType(), modifierTransformation().setterBridge(setter), Collections.<TypeParameter>emptyList(), Collections.<java.util.List<Type>>emptyList(), typeFact().getAnythingType(), Naming.getSetterName(attr), Collections.<Parameter>singletonList(setter.getParameter()), setter.getTypeErased(), null, null);
                    classBuilder.method(setterDelegate);
                }
                if (Decl.isValue(member) && ((Value) attr).isVariable()) {
                    // $impl to delegate to
                    throw new BugException("assertion failed: " + member.getQualifiedNameString() + " was unexpectedly a variable value");
                }
            }
        } else {
            Reference typedMember = member instanceof TypeDeclaration ? satisfiedType.getTypeMember((TypeDeclaration) member, Collections.<Type>emptyList()) : satisfiedType.getTypedMember((TypedDeclaration) member, Collections.<Type>emptyList());
            if (needsCompanionDelegate(model, typedMember)) {
                throw new BugException("unhandled concrete interface member " + member.getQualifiedNameString() + " " + member.getClass());
            }
        }
    }
    // Add $impl instances for the whole interface hierarchy
    satisfiedInterfaces.add(iface);
    for (Type sat : iface.getSatisfiedTypes()) {
        sat = model.getType().getSupertype(sat.getDeclaration());
        concreteMembersFromSuperinterfaces(model, classBuilder, sat, satisfiedInterfaces);
    }
}
Also used : TypeParameter(org.eclipse.ceylon.model.typechecker.model.TypeParameter) TypedReference(org.eclipse.ceylon.model.typechecker.model.TypedReference) Function(org.eclipse.ceylon.model.typechecker.model.Function) JCPrimitiveTypeTree(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCPrimitiveTypeTree) JCTree(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree) Tree(org.eclipse.ceylon.compiler.typechecker.tree.Tree) ArrayList(java.util.ArrayList) AnnotationList(org.eclipse.ceylon.compiler.typechecker.tree.Tree.AnnotationList) List(org.eclipse.ceylon.langtools.tools.javac.util.List) ParameterList(org.eclipse.ceylon.model.typechecker.model.ParameterList) Declaration(org.eclipse.ceylon.model.typechecker.model.Declaration) TypedDeclaration(org.eclipse.ceylon.model.typechecker.model.TypedDeclaration) TypeDeclaration(org.eclipse.ceylon.model.typechecker.model.TypeDeclaration) MethodDeclaration(org.eclipse.ceylon.compiler.typechecker.tree.Tree.MethodDeclaration) TypedDeclaration(org.eclipse.ceylon.model.typechecker.model.TypedDeclaration) ThrowerCatchallConstructor(org.eclipse.ceylon.compiler.java.codegen.recovery.ThrowerCatchallConstructor) Constructor(org.eclipse.ceylon.model.typechecker.model.Constructor) TypedReference(org.eclipse.ceylon.model.typechecker.model.TypedReference) Reference(org.eclipse.ceylon.model.typechecker.model.Reference) TypeAlias(org.eclipse.ceylon.model.typechecker.model.TypeAlias) Type(org.eclipse.ceylon.model.typechecker.model.Type) Value(org.eclipse.ceylon.model.typechecker.model.Value) FunctionOrValue(org.eclipse.ceylon.model.typechecker.model.FunctionOrValue) JavaBeanValue(org.eclipse.ceylon.model.loader.model.JavaBeanValue) Setter(org.eclipse.ceylon.model.typechecker.model.Setter) Parameter(org.eclipse.ceylon.model.typechecker.model.Parameter) TypeParameter(org.eclipse.ceylon.model.typechecker.model.TypeParameter) Class(org.eclipse.ceylon.model.typechecker.model.Class) JCNewClass(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCNewClass) JavaBeanValue(org.eclipse.ceylon.model.loader.model.JavaBeanValue) TypeDeclaration(org.eclipse.ceylon.model.typechecker.model.TypeDeclaration) Interface(org.eclipse.ceylon.model.typechecker.model.Interface) ClassOrInterface(org.eclipse.ceylon.model.typechecker.model.ClassOrInterface) LazyInterface(org.eclipse.ceylon.model.loader.model.LazyInterface)

Example 88 with TypedDeclaration

use of org.eclipse.ceylon.model.typechecker.model.TypedDeclaration in project ceylon by eclipse.

the class ClassTransformer method transform.

List<MethodDefinitionBuilder> transform(Tree.AnyMethod def, ClassDefinitionBuilder classBuilder, List<JCStatement> body) {
    final Function model = def.getDeclarationModel();
    List<MethodDefinitionBuilder> result = List.<MethodDefinitionBuilder>nil();
    if (!model.isInterfaceMember() || model.isStatic()) {
        // Transform to the class
        TypedDeclaration rd = (TypedDeclaration) model.getRefinedDeclaration();
        boolean refinedResultType = !model.getType().isExactly(rd.getType());
        result = transformMethod(def, true, true, true, transformMplBodyUnlessSpecifier(def, model, body), refinedResultType && !rd.isInterfaceMember() ? new DaoSuper() : new DaoThis(def, def.getParameterLists().get(0)), !Strategy.defaultParameterMethodOnSelf(model) && !Strategy.defaultParameterMethodStatic(model));
    } else {
        // Is within interface
        // Transform the definition to the companion class, how depends
        // on what kind of method it is
        List<MethodDefinitionBuilder> companionDefs;
        if (def instanceof Tree.MethodDeclaration) {
            final SpecifierExpression specifier = ((Tree.MethodDeclaration) def).getSpecifierExpression();
            if (specifier == null) {
                // formal or abstract
                // (still need overloads and DPMs on the companion)
                companionDefs = transformMethod(def, false, true, true, null, new DaoCompanion(def, def.getParameterLists().get(0)), false);
            } else {
                companionDefs = transformMethod(def, true, false, !model.isShared(), transformMplBodyUnlessSpecifier(def, model, body), new DaoCompanion(def, def.getParameterLists().get(0)), false);
            }
        } else if (def instanceof Tree.MethodDefinition) {
            companionDefs = transformMethod(def, true, false, !model.isShared(), transformMplBodyUnlessSpecifier(def, model, body), new DaoCompanion(def, def.getParameterLists().get(0)), false);
        } else {
            throw BugException.unhandledNodeCase(def);
        }
        if (!companionDefs.isEmpty())
            classBuilder.getCompanionBuilder((TypeDeclaration) model.getContainer()).methods(companionDefs);
        // but only if it's shared and not java native
        if (model.isShared() && !model.isJavaNative()) {
            result = transformMethod(def, true, true, true, null, daoAbstract, !Strategy.defaultParameterMethodOnSelf(model));
        }
    }
    return result;
}
Also used : Function(org.eclipse.ceylon.model.typechecker.model.Function) TypedDeclaration(org.eclipse.ceylon.model.typechecker.model.TypedDeclaration) SpecifierExpression(org.eclipse.ceylon.compiler.typechecker.tree.Tree.SpecifierExpression) MethodDeclaration(org.eclipse.ceylon.compiler.typechecker.tree.Tree.MethodDeclaration) JCPrimitiveTypeTree(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCPrimitiveTypeTree) JCTree(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree) Tree(org.eclipse.ceylon.compiler.typechecker.tree.Tree)

Example 89 with TypedDeclaration

use of org.eclipse.ceylon.model.typechecker.model.TypedDeclaration in project ceylon by eclipse.

the class ClassTransformer method transformMethod.

private List<MethodDefinitionBuilder> transformMethod(final Function methodModel, Tree.TypeParameterList typeParameterList, Tree.AnyMethod node, java.util.List<Tree.ParameterList> parameterLists, Tree.Declaration annotated, boolean transformMethod, boolean actual, boolean includeAnnotations, List<JCStatement> body, DaoBody daoTransformation, boolean defaultValuesBody) {
    ListBuffer<MethodDefinitionBuilder> lb = new ListBuffer<MethodDefinitionBuilder>();
    Declaration refinedDeclaration = methodModel.getRefinedDeclaration();
    final MethodDefinitionBuilder methodBuilder = MethodDefinitionBuilder.method(this, methodModel);
    // do the reified type param arguments
    if (AbstractTransformer.supportsReified(methodModel)) {
        methodBuilder.reifiedTypeParameters(Strategy.getEffectiveTypeParameters(methodModel));
    }
    if (methodModel.getParameterLists().size() > 1) {
        methodBuilder.mpl(methodModel.getParameterLists());
    }
    boolean hasOverloads = false;
    Tree.ParameterList parameterList = parameterLists.get(0);
    int flags = 0;
    if (rawParameters(methodModel)) {
        flags |= JT_RAW;
    }
    for (final Tree.Parameter parameter : parameterList.getParameters()) {
        Parameter parameterModel = parameter.getParameterModel();
        List<JCAnnotation> annotations = null;
        if (includeAnnotations) {
            Tree.TypedDeclaration typedDeclaration = Decl.getMemberDeclaration(annotated, parameter);
            // f = function(Integer param) => 2;
            if (typedDeclaration != null)
                annotations = expressionGen().transformAnnotations(OutputElement.PARAMETER, typedDeclaration);
        }
        // methodModel.getTypedReference().getTypedParameter(parameterModel).getType()
        // parameterModel.getModel().getTypedReference().getType()
        methodBuilder.parameter(parameter, parameterModel, annotations, flags, WideningRules.CAN_WIDEN);
        if (Strategy.hasDefaultParameterValueMethod(parameterModel) || Strategy.hasDefaultParameterOverload(parameterModel)) {
            if (Decl.equal(refinedDeclaration, methodModel) || (!methodModel.isInterfaceMember() && body != null) || methodModel.isInterfaceMember() && daoTransformation instanceof DaoCompanion == false) {
                if (daoTransformation != null && (daoTransformation instanceof DaoCompanion == false || body != null)) {
                    DaoBody daoTrans = (body == null && !methodModel.isJavaNative()) ? daoAbstract : new DaoThis(node, parameterList);
                    MethodDefinitionBuilder overloadedMethod = new DefaultedArgumentMethod(daoTrans, MethodDefinitionBuilder.method(this, methodModel), methodModel).makeOverload(parameterList.getModel(), parameter.getParameterModel(), Strategy.getEffectiveTypeParameters(methodModel));
                    overloadedMethod.location(null);
                    lb.append(overloadedMethod);
                }
                if (Decl.equal(refinedDeclaration, methodModel) && Strategy.hasDefaultParameterValueMethod(parameterModel)) {
                    lb.append(makeParamDefaultValueMethod(defaultValuesBody, methodModel, parameterList, parameter));
                }
            }
            hasOverloads = true;
        }
    }
    // Determine if we need to generate a "canonical" method
    boolean createCanonical = hasOverloads && methodModel.isClassOrInterfaceMember() && (body != null || methodModel.isJavaNative());
    if (createCanonical) {
        // Creates the private "canonical" method containing the actual body
        MethodDefinitionBuilder canonicalMethod = new CanonicalMethod(daoTransformation, methodModel, body).makeOverload(parameterList.getModel(), null, Strategy.getEffectiveTypeParameters(methodModel));
        lb.append(canonicalMethod);
    }
    if (transformMethod) {
        methodBuilder.modifiers(modifierTransformation().method(methodModel) | (methodModel.isJavaNative() && !createCanonical ? Flags.NATIVE : 0));
        if (actual) {
            methodBuilder.isOverride(methodModel.isActual());
        }
        if (includeAnnotations) {
            methodBuilder.userAnnotations(expressionGen().transformAnnotations(OutputElement.METHOD, annotated));
            methodBuilder.modelAnnotations(methodModel.getAnnotations());
            if (!methodModel.isDefault() && isEe(methodModel)) {
                methodBuilder.modelAnnotations(makeAtFinal());
            }
        } else {
            methodBuilder.ignoreModelAnnotations();
        }
        methodBuilder.resultType(methodModel, 0);
        copyTypeParameters(methodModel, methodBuilder);
        if (createCanonical) {
            // Creates method that redirects to the "canonical" method containing the actual body
            MethodDefinitionBuilder overloadedMethod = new CanonicalMethod(new DaoThis(node, parameterList), methodBuilder, methodModel).makeOverload(parameterList.getModel(), null, Strategy.getEffectiveTypeParameters(methodModel));
            lb.append(overloadedMethod);
        } else {
            if (body != null) {
                // Construct the outermost method using the body we've built so far
                methodBuilder.body(body);
            } else {
                methodBuilder.noBody();
            }
            lb.append(methodBuilder);
        }
    }
    return lb.toList();
}
Also used : ListBuffer(org.eclipse.ceylon.langtools.tools.javac.util.ListBuffer) JCPrimitiveTypeTree(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCPrimitiveTypeTree) JCTree(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree) Tree(org.eclipse.ceylon.compiler.typechecker.tree.Tree) Parameter(org.eclipse.ceylon.model.typechecker.model.Parameter) TypeParameter(org.eclipse.ceylon.model.typechecker.model.TypeParameter) Declaration(org.eclipse.ceylon.model.typechecker.model.Declaration) TypedDeclaration(org.eclipse.ceylon.model.typechecker.model.TypedDeclaration) TypeDeclaration(org.eclipse.ceylon.model.typechecker.model.TypeDeclaration) MethodDeclaration(org.eclipse.ceylon.compiler.typechecker.tree.Tree.MethodDeclaration) JCAnnotation(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCAnnotation)

Example 90 with TypedDeclaration

use of org.eclipse.ceylon.model.typechecker.model.TypedDeclaration in project ceylon by eclipse.

the class ClassTransformer method makeAttributeForValueParameter.

private void makeAttributeForValueParameter(ClassDefinitionBuilder classBuilder, Tree.Parameter parameterTree, Tree.TypedDeclaration memberTree) {
    Parameter decl = parameterTree.getParameterModel();
    if (!(decl.getModel() instanceof Value)) {
        return;
    }
    final Value value = (Value) decl.getModel();
    if (decl.getDeclaration() instanceof Constructor) {
        classBuilder.field(PUBLIC | FINAL, decl.getName(), makeJavaType(decl.getType()), null, false, expressionGen().transformAnnotations(OutputElement.FIELD, memberTree));
        classBuilder.getInitBuilder().init(make().Exec(make().Assign(naming.makeQualIdent(naming.makeThis(), decl.getName()), naming.makeName(value, Naming.NA_IDENT))));
    } else if (parameterTree instanceof Tree.ValueParameterDeclaration && ModelUtil.isCaptured(value)) {
        makeFieldForParameter(classBuilder, decl, memberTree);
        AttributeDefinitionBuilder adb = AttributeDefinitionBuilder.getter(this, decl.getName(), decl.getModel());
        adb.modifiers(classGen().modifierTransformation().getterSetter(decl.getModel(), false));
        adb.userAnnotations(expressionGen().transformAnnotations(OutputElement.GETTER, memberTree));
        classBuilder.attribute(adb);
        if (value.isVariable()) {
            AttributeDefinitionBuilder setter = AttributeDefinitionBuilder.setter(this, parameterTree, decl.getName(), decl.getModel());
            setter.modifiers(classGen().modifierTransformation().getterSetter(decl.getModel(), false));
            // setter.userAnnotations(expressionGen().transform(AnnotationTarget.SETTER, memberTree.getAnnotationList()));
            classBuilder.attribute(setter);
        }
    } else if (decl.isHidden() && // TODO Isn't this always true here? We know this is a parameter to a Class
    (decl.getDeclaration() instanceof TypeDeclaration)) {
        Declaration member = CodegenUtil.findMethodOrValueForParam(decl);
        if (Strategy.createField(decl, (Value) member)) {
            // The field itself is created by when we transform the AttributeDeclaration
            // but it has to be initialized here so all the fields are initialized in parameter order
            at(parameterTree);
            JCExpression parameterExpr = makeUnquotedIdent(Naming.getAliasedParameterName(decl));
            TypedReference typedRef = getTypedReference(value);
            TypedReference nonWideningTypedRef = nonWideningTypeDecl(typedRef);
            Type paramType = nonWideningType(typedRef, nonWideningTypedRef);
            AttributeDefinitionBuilder adb = AttributeDefinitionBuilder.field(this, memberTree, value.getName(), value, false);
            if (!paramType.isExactly(decl.getType())) {
                // The parameter type follows normal erasure rules, not affected by inheritance
                // but the attribute respects non-widening rules, so we may need to cast
                // the parameter to the field type (see #1728)
                parameterExpr = make().TypeCast(adb.valueFieldType(), parameterExpr);
            }
            at(parameterTree);
            BoxingStrategy exprBoxed = CodegenUtil.isUnBoxed((TypedDeclaration) member) ? BoxingStrategy.UNBOXED : BoxingStrategy.BOXED;
            adb.initialValue(parameterExpr, exprBoxed);
            classBuilder.getInitBuilder().init(adb.buildInit(true));
        }
    }
}
Also used : TypedDeclaration(org.eclipse.ceylon.model.typechecker.model.TypedDeclaration) Type(org.eclipse.ceylon.model.typechecker.model.Type) JCExpression(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCExpression) TypedReference(org.eclipse.ceylon.model.typechecker.model.TypedReference) ThrowerCatchallConstructor(org.eclipse.ceylon.compiler.java.codegen.recovery.ThrowerCatchallConstructor) Constructor(org.eclipse.ceylon.model.typechecker.model.Constructor) Value(org.eclipse.ceylon.model.typechecker.model.Value) FunctionOrValue(org.eclipse.ceylon.model.typechecker.model.FunctionOrValue) JavaBeanValue(org.eclipse.ceylon.model.loader.model.JavaBeanValue) Parameter(org.eclipse.ceylon.model.typechecker.model.Parameter) TypeParameter(org.eclipse.ceylon.model.typechecker.model.TypeParameter) Declaration(org.eclipse.ceylon.model.typechecker.model.Declaration) TypedDeclaration(org.eclipse.ceylon.model.typechecker.model.TypedDeclaration) TypeDeclaration(org.eclipse.ceylon.model.typechecker.model.TypeDeclaration) MethodDeclaration(org.eclipse.ceylon.compiler.typechecker.tree.Tree.MethodDeclaration) TypeDeclaration(org.eclipse.ceylon.model.typechecker.model.TypeDeclaration)

Aggregations

TypedDeclaration (org.eclipse.ceylon.model.typechecker.model.TypedDeclaration)110 Type (org.eclipse.ceylon.model.typechecker.model.Type)58 TypeDeclaration (org.eclipse.ceylon.model.typechecker.model.TypeDeclaration)51 Declaration (org.eclipse.ceylon.model.typechecker.model.Declaration)50 Tree (org.eclipse.ceylon.compiler.typechecker.tree.Tree)47 Function (org.eclipse.ceylon.model.typechecker.model.Function)34 Value (org.eclipse.ceylon.model.typechecker.model.Value)28 Class (org.eclipse.ceylon.model.typechecker.model.Class)26 FunctionOrValue (org.eclipse.ceylon.model.typechecker.model.FunctionOrValue)26 AnalyzerUtil.getTypedDeclaration (org.eclipse.ceylon.compiler.typechecker.analyzer.AnalyzerUtil.getTypedDeclaration)25 ClassOrInterface (org.eclipse.ceylon.model.typechecker.model.ClassOrInterface)22 ModelUtil.appliedType (org.eclipse.ceylon.model.typechecker.model.ModelUtil.appliedType)21 TypeParameter (org.eclipse.ceylon.model.typechecker.model.TypeParameter)21 AnalyzerUtil.getPackageTypedDeclaration (org.eclipse.ceylon.compiler.typechecker.analyzer.AnalyzerUtil.getPackageTypedDeclaration)20 Scope (org.eclipse.ceylon.model.typechecker.model.Scope)19 JCExpression (org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCExpression)18 JCTree (org.eclipse.ceylon.langtools.tools.javac.tree.JCTree)17 Parameter (org.eclipse.ceylon.model.typechecker.model.Parameter)17 Constructor (org.eclipse.ceylon.model.typechecker.model.Constructor)16 CustomTree (org.eclipse.ceylon.compiler.typechecker.tree.CustomTree)15