Search in sources :

Example 51 with TypeParameter

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

the class ExpressionTransformer method needsCast.

boolean needsCast(Type exprType, Type expectedType, boolean expectedTypeNotRaw, boolean expectedTypeHasConstrainedTypeParameters, boolean downCast) {
    // error handling
    if (exprType == null)
        return false;
    // make sure we work on definite types
    exprType = simplifyType(exprType);
    expectedType = simplifyType(expectedType);
    // abort if both types are the same
    if (exprType.isExactly(expectedType)) {
        // really trust the expected type
        if (!expectedTypeHasConstrainedTypeParameters)
            return false;
    }
    // now see about erasure
    boolean eraseExprType = willEraseToObject(exprType);
    boolean eraseExpectedType = willEraseToObject(expectedType);
    // if we erase expected type we need no cast
    if (eraseExpectedType) {
        // unless the expected type is parameterised with bounds that erasure to Object can't possibly satisfy
        if (!expectedTypeHasConstrainedTypeParameters)
            return false;
    }
    // if we erase the expr type we need a cast
    if (eraseExprType)
        return true;
    // find their common type
    Type commonType = exprType.getSupertype(expectedType.getDeclaration());
    if (commonType == null || !(commonType.getDeclaration() instanceof ClassOrInterface)) {
        // we did not find any common type, but we may be downcasting, in which case we need a cast
        return downCast;
    }
    // some times we can lose info due to an erased type parameter somewhere in the inheritance graph
    if (lostTypeParameterInInheritance(exprType, commonType))
        return true;
    if (!expectedTypeNotRaw) {
        // if we know for sure that the expected type is NOT raw. if it's false we've no idea but we can check:
        if (isTurnedToRaw(expectedType)) {
            return false;
        }
        // the common type could be erased
        if (commonType.isExactly(expectedType))
            return false;
    }
    // special case for Callable because only the first type param exists in Java, the rest is completely suppressed
    boolean isCallable = isCeylonCallable(commonType);
    // now see if the type parameters match
    java.util.List<Type> commonTypeArgs = commonType.getTypeArgumentList();
    java.util.List<TypeParameter> commonTps = commonType.getDeclaration().getTypeParameters();
    java.util.List<Type> expectedTypeArgs = expectedType.getTypeArgumentList();
    java.util.List<TypeParameter> expectedTps = expectedType.getDeclaration().getTypeParameters();
    // check that we got them all otherwise we just don't know
    if (commonTypeArgs.size() != expectedTypeArgs.size())
        return false;
    for (int i = 0, n = commonTypeArgs.size(); i < n; i++) {
        // apply the same logic to each type param: see if they would require a raw cast
        Type commonTypeArg = commonTypeArgs.get(i);
        Type expectedTypeArg = expectedTypeArgs.get(i);
        if (hasDependentTypeParameters(commonTps, commonTps.get(i)) || hasDependentTypeParameters(expectedTps, expectedTps.get(i))) {
            // if the type parameters are not identical:
            if (!simplifyType(commonTypeArg).isExactly(simplifyType(expectedTypeArg))) {
                return true;
            }
        }
        if (needsCast(commonTypeArg, expectedTypeArg, expectedTypeNotRaw, expectedTypeHasConstrainedTypeParameters, downCast))
            return true;
        // stop after the first one for Callable
        if (isCallable)
            break;
    }
    if (commonType.getQualifyingType() != null && expectedType.getQualifyingType() != null) {
        return needsCast(commonType.getQualifyingType(), expectedType.getQualifyingType(), expectedTypeNotRaw, expectedTypeHasConstrainedTypeParameters, downCast);
    }
    return false;
}
Also used : ClassOrInterface(org.eclipse.ceylon.model.typechecker.model.ClassOrInterface) UnionType(org.eclipse.ceylon.model.typechecker.model.UnionType) Type(org.eclipse.ceylon.model.typechecker.model.Type) TypeParameter(org.eclipse.ceylon.model.typechecker.model.TypeParameter)

Example 52 with TypeParameter

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

the class ExpressionTransformer method transformTypeArguments.

private final void transformTypeArguments(CallBuilder callBuilder, Tree.StaticMemberOrTypeExpression mte) {
    java.util.List<TypeParameter> tps = null;
    Declaration declaration = mte.getDeclaration();
    if (!mte.getTypeModel().isTypeConstructor()) {
        tps = Strategy.getEffectiveTypeParameters(declaration);
    } else {
        for (TypeParameter tp : Strategy.getEffectiveTypeParameters(declaration)) {
            callBuilder.typeArgument(makeJavaType(tp.getType(), JT_TYPE_ARGUMENT));
        }
        return;
    }
    if (tps != null) {
        for (TypeParameter tp : tps) {
            Type ta = mte.getTarget().getTypeArguments().get(tp);
            java.util.List<Type> bounds = null;
            boolean needsCastForBounds = false;
            if (!tp.getSatisfiedTypes().isEmpty()) {
                bounds = new ArrayList<Type>(tp.getSatisfiedTypes().size());
                for (Type bound : tp.getSatisfiedTypes()) {
                    // substitute the right type arguments
                    bound = substituteTypeArgumentsForTypeParameterBound(mte.getTarget(), bound);
                    bounds.add(bound);
                    needsCastForBounds |= needsCast(ta, bound, false, false, false);
                }
            }
            boolean hasMultipleBounds;
            Type firstBound;
            if (bounds != null) {
                hasMultipleBounds = bounds.size() > 1;
                firstBound = bounds.isEmpty() ? null : bounds.get(0);
            } else {
                hasMultipleBounds = false;
                firstBound = null;
            }
            if (willEraseToObject(ta) || needsCastForBounds) {
                boolean boundsSelfDependent = isBoundsSelfDependant(tp);
                if (hasDependentTypeParameters(tps, tp) || // and we cannot represent the intersection type in Java so give up
                hasMultipleBounds || // if we are going to use the first bound and it is self-dependent, we will make it raw
                boundsSelfDependent || (firstBound != null && willEraseToObject(firstBound))) {
                    // so at some point we'll have to introduce an intersection type AST node to satisfy multiple bounds
                    if (hasMultipleBounds) {
                        callBuilder.typeArguments(List.<JCExpression>nil());
                        return;
                    }
                    // if we have a bound
                    if (firstBound != null) {
                        // if it's self-dependent we cannot satisfy it without a raw type
                        if (boundsSelfDependent)
                            callBuilder.typeArgument(makeJavaType(firstBound, JT_TYPE_ARGUMENT | JT_RAW));
                        else
                            callBuilder.typeArgument(makeJavaType(firstBound, JT_TYPE_ARGUMENT));
                    } else {
                        // no bound, let's go with Object then
                        callBuilder.typeArgument(makeJavaType(typeFact().getObjectType(), JT_TYPE_ARGUMENT));
                    }
                } else if (firstBound == null) {
                    callBuilder.typeArgument(makeJavaType(ta, JT_TYPE_ARGUMENT));
                } else {
                    callBuilder.typeArgument(makeJavaType(firstBound, JT_TYPE_ARGUMENT));
                }
            } else {
                callBuilder.typeArgument(makeJavaType(ta, JT_TYPE_ARGUMENT));
            }
        }
    }
}
Also used : TypeParameter(org.eclipse.ceylon.model.typechecker.model.TypeParameter) UnionType(org.eclipse.ceylon.model.typechecker.model.UnionType) Type(org.eclipse.ceylon.model.typechecker.model.Type) TypedDeclaration(org.eclipse.ceylon.model.typechecker.model.TypedDeclaration) TypeDeclaration(org.eclipse.ceylon.model.typechecker.model.TypeDeclaration) Declaration(org.eclipse.ceylon.model.typechecker.model.Declaration)

Example 53 with TypeParameter

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

the class CeylonVisitor method transformConstructor.

private void transformConstructor(Tree.Declaration ctor, Tree.ParameterList parameterList, Tree.DelegatedConstructor delegatedCtor, Tree.Block block, Constructor ctorModel, Map<Constructor, CtorDelegation> delegates) {
    TransformationPlan plan = gen.errors().hasDeclarationAndMarkBrokenness(ctor);
    if (plan instanceof Drop) {
        return;
    }
    if (parameterList != null) {
        for (Parameter param : parameterList.getModel().getParameters()) {
            FunctionOrValue model = param.getModel();
            if (Naming.aliasConstructorParameterName(model)) {
                gen.naming.addVariableSubst(model, Naming.suffixName(Suffix.$param$, param.getName()));
            }
        }
    }
    final CtorDelegation delegation = delegates.get(ctorModel);
    ListBuffer<JCStatement> stmts = new ListBuffer<JCStatement>();
    boolean delegatedTo = CtorDelegation.isDelegatedTo(delegates, ctorModel);
    if (delegatedTo && !ctorModel.isAbstract()) {
        Tree.InvocationExpression chainedCtorInvocation;
        if (delegatedCtor != null) {
            chainedCtorInvocation = delegatedCtor.getInvocationExpression();
        } else {
            chainedCtorInvocation = null;
        }
        // We need to generate $delegation$ delegation constructor
        makeDelegationConstructor(ctor, parameterList, delegatedCtor, block, ctorModel, delegation, chainedCtorInvocation);
        JCStatement delegateExpr;
        if (chainedCtorInvocation != null) {
            delegateExpr = gen.expressionGen().transformConstructorDelegation(chainedCtorInvocation, delegation.isSelfDelegation() ? delegation : new CtorDelegation(ctorModel, ctorModel), chainedCtorInvocation, classBuilder, !delegation.isSelfDelegation());
        } else {
            // In this case there is no extends clause in the source code
            // so we have to construct the argument list "by hand".
            ListBuffer<JCExpression> arguments = new ListBuffer<JCExpression>();
            for (TypeParameter tp : ((Class) delegation.getConstructor().getContainer()).getTypeParameters()) {
                arguments.add(gen.makeReifiedTypeArgument(tp.getType()));
            }
            arguments.add(gen.naming.makeNamedConstructorName(delegation.getConstructor(), true));
            for (Parameter p : delegation.getConstructor().getFirstParameterList().getParameters()) {
                arguments.add(gen.naming.makeName(p.getModel(), Naming.NA_IDENT));
            }
            delegateExpr = gen.make().Exec(gen.make().Apply(null, gen.naming.makeThis(), arguments.toList()));
        }
        stmts.add(delegateExpr);
    } else if (delegatedCtor != null) {
        stmts.add(gen.expressionGen().transformConstructorDelegation(delegatedCtor, delegation, delegatedCtor.getInvocationExpression(), classBuilder, false));
    } else {
    // no explicit extends clause
    }
    final boolean addBody;
    if (delegatedTo && (delegation.isAbstractSelfOrSuperDelegation())) {
        if (delegation.getConstructor().isAbstract()) {
            stmts.addAll(classBuilder.getInitBuilder().copyStatementsBetween(null, ctorModel));
            addBody = true;
        } else if (delegation.getExtendingConstructor() != null && delegation.getExtendingConstructor().isAbstract()) {
            stmts.addAll(classBuilder.getInitBuilder().copyStatementsBetween(delegation.getExtendingConstructor(), ctorModel));
            addBody = true;
        } else {
            addBody = false;
        }
    } else if (delegation.isAbstractSelfDelegation()) {
        // delegating to abstract
        stmts.addAll(classBuilder.getInitBuilder().copyStatementsBetween(delegation.getExtendingConstructor(), ctorModel));
        addBody = true;
    } else if (delegation.isConcreteSelfDelegation()) {
        stmts.addAll(classBuilder.getInitBuilder().copyStatementsBetween(delegation.getExtendingConstructor(), ctorModel));
        addBody = true;
    } else {
        // super delegation
        stmts.addAll(classBuilder.getInitBuilder().copyStatementsBetween(null, ctorModel));
        addBody = true;
    }
    if (ctorModel.isAbstract() && !delegatedTo) {
        stmts.add(gen.make().Throw(gen.make().NewClass(null, List.<JCExpression>nil(), gen.make().QualIdent(gen.syms().ceylonUninvokableErrorType.tsym), List.<JCExpression>nil(), null)));
    }
    List<JCStatement> following = ctorModel.isAbstract() ? List.<JCStatement>nil() : classBuilder.getInitBuilder().copyStatementsBetween(ctorModel, null);
    if (addBody) {
        if (following.isEmpty()) {
            stmts.addAll(gen.statementGen().transformBlock(block));
        } else {
            Name label = gen.naming.aliasName(Naming.Unfix.$return$.toString());
            Transformer<JCStatement, Return> prev = gen.statementGen().returnTransformer(gen.statementGen().new ConstructorReturnTransformer(label));
            try {
                stmts.add(gen.make().Labelled(label, gen.make().DoLoop(gen.make().Block(0, gen.statementGen().transformBlock(block, true)), gen.make().Literal(false))));
            } finally {
                gen.statementGen().returnTransformer(prev);
            }
        }
    }
    ThrowVisitor visitor = new ThrowVisitor();
    block.visit(visitor);
    if (!visitor.getDefinitelyReturnsViaThrow()) {
        stmts.addAll(following);
    }
    String ctorName = !Decl.isDefaultConstructor(ctorModel) ? gen.naming.makeTypeDeclarationName(ctorModel) : null;
    classBuilder.defs(gen.classGen().makeNamedConstructor(ctor, parameterList, ctorModel, classBuilder, Strategy.generateInstantiator(ctorModel), gen.classGen().modifierTransformation().constructor(ctorModel), false, ctorName, stmts.toList(), DeclNameFlag.QUALIFIED));
}
Also used : TypeParameter(org.eclipse.ceylon.model.typechecker.model.TypeParameter) Return(org.eclipse.ceylon.compiler.typechecker.tree.Tree.Return) ListBuffer(org.eclipse.ceylon.langtools.tools.javac.util.ListBuffer) JCStatement(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCStatement) Drop(org.eclipse.ceylon.compiler.java.codegen.recovery.Drop) Name(org.eclipse.ceylon.langtools.tools.javac.util.Name) SyntheticName(org.eclipse.ceylon.compiler.java.codegen.Naming.SyntheticName) JCExpression(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCExpression) Parameter(org.eclipse.ceylon.model.typechecker.model.Parameter) TypeParameter(org.eclipse.ceylon.model.typechecker.model.TypeParameter) Tree(org.eclipse.ceylon.compiler.typechecker.tree.Tree) CustomTree(org.eclipse.ceylon.compiler.typechecker.tree.CustomTree) JCTree(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree) Class(org.eclipse.ceylon.model.typechecker.model.Class) JCNewClass(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCNewClass) TransformationPlan(org.eclipse.ceylon.compiler.java.codegen.recovery.TransformationPlan) FunctionOrValue(org.eclipse.ceylon.model.typechecker.model.FunctionOrValue)

Example 54 with TypeParameter

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

the class ClassDefinitionBuilder method addRefineReifiedTypeParametersMethod.

public ClassDefinitionBuilder addRefineReifiedTypeParametersMethod(java.util.List<TypeParameter> typeParameterList) {
    MethodDefinitionBuilder method = MethodDefinitionBuilder.systemMethod(gen, gen.naming.getRefineTypeParametersMethodName());
    method.modifiers(PUBLIC);
    method.ignoreModelAnnotations();
    List<JCStatement> body = List.nil();
    for (TypeParameter tp : typeParameterList) {
        String descriptorName = gen.naming.getTypeArgumentDescriptorName(tp);
        method.parameter(makeReifiedParameter(descriptorName));
        body = body.prepend(gen.makeReifiedTypeParameterAssignment(tp));
    }
    method.body(body);
    defs(method.build());
    return this;
}
Also used : TypeParameter(org.eclipse.ceylon.model.typechecker.model.TypeParameter) JCTypeParameter(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCTypeParameter) JCStatement(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCStatement)

Example 55 with TypeParameter

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

the class MethodDefinitionBuilder method isParamTypeLocalToMethod.

private boolean isParamTypeLocalToMethod(Parameter parameter, Type nonWideningType) {
    // error recovery
    if (nonWideningType == null)
        return false;
    if (parameter.getModel().getTypeErased()) {
        return false;
    }
    // make sure we resolve aliases
    nonWideningType = nonWideningType.resolveAliases();
    Declaration method = parameter.getDeclaration();
    TypeDeclaration paramTypeDecl = nonWideningType.getDeclaration();
    if (paramTypeDecl instanceof TypeParameter && Decl.equalScopeDecl(paramTypeDecl.getContainer(), method)) {
        return false;
    }
    Scope scope = paramTypeDecl.getContainer();
    while (scope != null && !(scope instanceof Package)) {
        if (Decl.equalScopeDecl(scope, method)) {
            return true;
        }
        scope = scope.getContainer();
    }
    return false;
}
Also used : TypeParameter(org.eclipse.ceylon.model.typechecker.model.TypeParameter) JCTypeParameter(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCTypeParameter) Scope(org.eclipse.ceylon.model.typechecker.model.Scope) TypedDeclaration(org.eclipse.ceylon.model.typechecker.model.TypedDeclaration) TypeDeclaration(org.eclipse.ceylon.model.typechecker.model.TypeDeclaration) Declaration(org.eclipse.ceylon.model.typechecker.model.Declaration) Package(org.eclipse.ceylon.model.typechecker.model.Package) TypeDeclaration(org.eclipse.ceylon.model.typechecker.model.TypeDeclaration)

Aggregations

TypeParameter (org.eclipse.ceylon.model.typechecker.model.TypeParameter)181 Type (org.eclipse.ceylon.model.typechecker.model.Type)138 TypeDeclaration (org.eclipse.ceylon.model.typechecker.model.TypeDeclaration)82 ArrayList (java.util.ArrayList)57 ModelUtil.appliedType (org.eclipse.ceylon.model.typechecker.model.ModelUtil.appliedType)57 Tree (org.eclipse.ceylon.compiler.typechecker.tree.Tree)54 UnknownType (org.eclipse.ceylon.model.typechecker.model.UnknownType)46 Declaration (org.eclipse.ceylon.model.typechecker.model.Declaration)45 ModelUtil.intersectionType (org.eclipse.ceylon.model.typechecker.model.ModelUtil.intersectionType)35 TypedDeclaration (org.eclipse.ceylon.model.typechecker.model.TypedDeclaration)32 ClassOrInterface (org.eclipse.ceylon.model.typechecker.model.ClassOrInterface)30 Function (org.eclipse.ceylon.model.typechecker.model.Function)29 AnalyzerUtil.getTupleType (org.eclipse.ceylon.compiler.typechecker.analyzer.AnalyzerUtil.getTupleType)28 AnalyzerUtil.spreadType (org.eclipse.ceylon.compiler.typechecker.analyzer.AnalyzerUtil.spreadType)28 Parameter (org.eclipse.ceylon.model.typechecker.model.Parameter)28 IntersectionType (org.eclipse.ceylon.model.typechecker.model.IntersectionType)27 JCTypeParameter (org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCTypeParameter)26 Class (org.eclipse.ceylon.model.typechecker.model.Class)26 UnionType (org.eclipse.ceylon.model.typechecker.model.UnionType)25 HashMap (java.util.HashMap)24