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;
}
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));
}
}
}
}
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));
}
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;
}
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;
}
Aggregations