use of org.eclipse.ceylon.model.typechecker.model.ClassOrInterface in project ceylon by eclipse.
the class ExpressionTransformer method transform.
public JCTree transform(Tree.TypeLiteral expr) {
at(expr);
if (!expr.getWantsDeclaration()) {
if (expr.getDeclaration() instanceof Constructor) {
JCExpression classLiteral = makeTypeLiteralCall(expr.getType().getTypeModel().getQualifyingType(), false, expr.getTypeModel());
TypeDeclaration classModelDeclaration = (TypeDeclaration) typeFact().getLanguageModuleModelDeclaration(expr.getType().getTypeModel().getQualifyingType().getDeclaration().isMember() ? "MemberClass" : "Class");
JCTypeCast typeCast = make().TypeCast(makeJavaType(classModelDeclaration.appliedType(null, List.of(expr.getType().getTypeModel().getQualifyingType(), typeFact().getNothingType()))), classLiteral);
Type callableType = expr.getTypeModel().getFullType();
JCExpression reifiedArgumentsExpr = makeReifiedTypeArgument(typeFact().getCallableTuple(callableType));
return make().Apply(null, naming.makeQualIdent(typeCast, "getConstructor"), List.<JCExpression>of(reifiedArgumentsExpr, make().Literal(expr.getDeclaration().getName())));
} else {
if (coerced) {
Type t = expr.getType().getTypeModel();
if (!typeFact().isJavaObjectArrayType(t) || t.getTypeArgumentList().get(0).isClassOrInterface()) {
return makeSelect(makeJavaType(t, JT_NO_PRIMITIVES | JT_RAW), "class");
}
}
return makeTypeLiteralCall(expr.getType().getTypeModel(), true, expr.getTypeModel());
}
} else if (expr.getDeclaration() instanceof TypeParameter) {
// we must get it from its container
TypeParameter declaration = (TypeParameter) expr.getDeclaration();
Node node = expr;
return makeTypeParameterDeclaration(node, declaration);
} else if (expr.getDeclaration() instanceof Constructor || expr instanceof Tree.NewLiteral) {
Constructor ctor;
if (expr.getDeclaration() instanceof Constructor) {
ctor = (Constructor) expr.getDeclaration();
} else {
ctor = ((Class) expr.getDeclaration()).getDefaultConstructor();
}
JCExpression metamodelCall = makeTypeDeclarationLiteral(ModelUtil.getConstructedClass(ctor));
metamodelCall = make().TypeCast(makeJavaType(typeFact().getClassDeclarationType(), JT_RAW), metamodelCall);
metamodelCall = make().Apply(null, naming.makeQualIdent(metamodelCall, "getConstructorDeclaration"), List.<JCExpression>of(make().Literal(ctor.getName() == null ? "" : ctor.getName())));
if (ModelUtil.isEnumeratedConstructor(ctor)) {
metamodelCall = make().TypeCast(makeJavaType(typeFact().getValueConstructorDeclarationType(), JT_RAW), metamodelCall);
} else /*else if (Decl.isDefaultConstructor(ctor)){
metamodelCall = make().TypeCast(
makeJavaType(typeFact().getDefaultConstructorDeclarationType(), JT_RAW), metamodelCall);
} */
{
metamodelCall = make().TypeCast(makeJavaType(typeFact().getCallableConstructorDeclarationType(), JT_RAW), metamodelCall);
}
return metamodelCall;
} else if (expr.getDeclaration() instanceof ClassOrInterface || expr.getDeclaration() instanceof TypeAlias) {
// use the generated class to get to the declaration literal
JCExpression metamodelCall = makeTypeDeclarationLiteral((TypeDeclaration) expr.getDeclaration());
Type exprType = expr.getTypeModel().resolveAliases();
// now cast if required
if (!exprType.isExactly(((TypeDeclaration) typeFact().getLanguageModuleDeclarationDeclaration("NestableDeclaration")).getType())) {
JCExpression type = makeJavaType(exprType, JT_NO_PRIMITIVES);
return make().TypeCast(type, metamodelCall);
}
return metamodelCall;
} else {
return makeErroneous(expr, "compiler bug: " + expr.getDeclaration() + " is an unsupported declaration type");
}
}
use of org.eclipse.ceylon.model.typechecker.model.ClassOrInterface 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.ClassOrInterface in project ceylon by eclipse.
the class ExpressionTransformer method transform.
public JCExpression transform(Tree.Parameter param) {
// Transform the expression marking that we're inside a defaulted parameter for $this-handling
// needDollarThis = true;
JCExpression expr;
at(param);
if (Strategy.hasDefaultParameterValueMethod(param.getParameterModel())) {
Tree.SpecifierOrInitializerExpression spec = Decl.getDefaultArgument(param);
Scope container = param.getParameterModel().getModel().getContainer();
boolean classParameter = container instanceof ClassOrInterface;
ClassOrInterface oldWithinDefaultParameterExpression = withinDefaultParameterExpression;
if (classParameter)
withinDefaultParameterExpression((ClassOrInterface) container);
if (param instanceof Tree.FunctionalParameterDeclaration) {
Tree.FunctionalParameterDeclaration fpTree = (Tree.FunctionalParameterDeclaration) param;
Tree.SpecifierExpression lazy = (Tree.SpecifierExpression) spec;
Function fp = (Function) fpTree.getParameterModel().getModel();
expr = CallableBuilder.anonymous(gen(), param, (Function) fpTree.getTypedDeclaration().getDeclarationModel(), lazy.getExpression(), ((Tree.MethodDeclaration) fpTree.getTypedDeclaration()).getParameterLists(), getTypeForFunctionalParameter(fp), true).build();
} else {
expr = transformExpression(spec.getExpression(), CodegenUtil.getBoxingStrategy(param.getParameterModel().getModel()), param.getParameterModel().getModel().getTypedReference().getFullType());
}
if (classParameter)
withinDefaultParameterExpression(oldWithinDefaultParameterExpression);
} else {
expr = makeErroneous(param, "compiler bug: no default parameter value method");
}
// needDollarThis = false;
return expr;
}
use of org.eclipse.ceylon.model.typechecker.model.ClassOrInterface in project ceylon by eclipse.
the class ExpressionTransformer method addThisOrObjectQualifierIfRequired.
/**
* We may need to force a qualified this prefix (direct or outer) in the following cases:
*
* - Required because of mixin inheritance with different type arguments (the same is already
* done for qualified references, but not for direct references)
* - The compiler generates anonymous local classes for things like
* Callables and Comprehensions. When referring to a member foo
* within one of those things we need a qualified {@code this}
* to ensure we're accessing the outer instances member, not
* a member of the anonymous local class that happens to have the same name.
*/
private JCExpression addThisOrObjectQualifierIfRequired(JCExpression qualExpr, Tree.StaticMemberOrTypeExpression expr, Declaration decl) {
// find out the real target
Declaration typeDecl;
if (Decl.isConstructor(decl))
typeDecl = ModelUtil.getConstructedClass(decl);
else
typeDecl = decl;
if (qualExpr == null && // statics are not members that can be inherited
!decl.isStatic() && (!Decl.isConstructor(decl) || !Decl.isConstructor(typeDecl)) && typeDecl.isMember() && // and have a name mapping)
expr.getTarget().getDeclaration() == decl && !ModelUtil.isLocalToInitializer(typeDecl) && !isWithinSuperInvocation()) {
// First check whether the expression is captured from an enclosing scope
TypeDeclaration outer = Decl.getOuterScopeOfMemberInvocation(expr, typeDecl);
if (outer != null) {
Type targetType = expr.getTarget().getQualifyingType();
Type declarationContainerType = ((TypeDeclaration) outer).getType();
// check if we need a variance cast
VarianceCastResult varianceCastResult = getVarianceCastResult(targetType, declarationContainerType);
// if we are within a comprehension body, or if we need a variance cast
if (isWithinSyntheticClassBody() || varianceCastResult != null) {
if (decl.isShared() && outer instanceof Interface) {
// always prefer qualified
qualExpr = makeQualifiedDollarThis(declarationContainerType);
} else {
// Class or companion class,
qualExpr = naming.makeQualifiedThis(makeJavaType(((TypeDeclaration) outer).getType(), JT_RAW | (outer instanceof Interface ? JT_COMPANION : 0)));
}
// add the variance cast if required
if (varianceCastResult != null) {
qualExpr = applyVarianceCasts(qualExpr, targetType, varianceCastResult, 0);
}
}
} else if (typeDecl.isClassOrInterfaceMember()) {
ClassOrInterface container;
if (((ClassOrInterface) typeDecl.getContainer()).isAnonymous() && ((ClassOrInterface) typeDecl.getContainer()).isToplevel()) {
// easy
container = (Class) typeDecl.getContainer();
} else {
// find the import
Import foundImport = statementGen().findImport(expr, decl);
container = (Class) foundImport.getTypeDeclaration();
}
Value value = (Value) ((Package) container.getContainer()).getMember(container.getName(), null, false);
qualExpr = make().Apply(null, naming.makeName(value, Naming.NA_FQ | Naming.NA_WRAPPER | Naming.NA_MEMBER), List.<JCExpression>nil());
} else if (decl.isMember() && !expr.getStaticMethodReference()) {
throw new BugException(expr, decl.getQualifiedNameString() + " was unexpectedly a member");
}
}
return qualExpr;
}
use of org.eclipse.ceylon.model.typechecker.model.ClassOrInterface in project ceylon by eclipse.
the class ExpressionTransformer method lostTypeParameterInInheritance.
private boolean lostTypeParameterInInheritance(Type exprType, Type commonType) {
if (exprType.getDeclaration() instanceof ClassOrInterface == false || commonType.getDeclaration() instanceof ClassOrInterface == false)
return false;
ClassOrInterface exprDecl = (ClassOrInterface) exprType.getDeclaration();
ClassOrInterface commonDecl = (ClassOrInterface) commonType.getDeclaration();
// do not search interfaces if the common declaration is a class, because interfaces cannot be subtypes of a class
boolean searchInterfaces = commonDecl instanceof Interface;
return lostTypeParameterInInheritance(exprDecl, commonDecl, searchInterfaces, false);
}
Aggregations