use of org.eclipse.ceylon.model.typechecker.model.ClassOrInterface in project ceylon by eclipse.
the class AbstractModelLoader method completeActual.
@Override
public void completeActual(Declaration decl) {
Scope container = decl.getContainer();
if (container instanceof ClassOrInterface) {
ClassOrInterface klass = (ClassOrInterface) container;
decl.setRefinedDeclaration(decl);
// we never consider Interface and other stuff, since we never register the actualCompleter for them
if (decl instanceof Class) {
// Java member classes are never actual
if (!ModelUtil.isCeylonDeclaration((Class) decl))
return;
// we already set the actual bit for member classes, we just need the refined decl
if (decl.isActual()) {
Declaration refined = klass.getRefinedMember(decl.getName(), getSignature(decl), klass.isVariadic());
decl.setRefinedDeclaration(refined);
}
} else {
// Function or Value
MethodMirror methodMirror;
if (decl instanceof JavaBeanValue)
methodMirror = ((JavaBeanValue) decl).mirror;
else if (decl instanceof JavaMethod)
methodMirror = ((JavaMethod) decl).mirror;
else
throw new ModelResolutionException("Unknown type of declaration: " + decl + ": " + decl.getClass().getName());
decl.setRefinedDeclaration(decl);
// For Ceylon interfaces we rely on annotation
if (klass instanceof LazyInterface && ((LazyInterface) klass).isCeylon()) {
boolean actual = methodMirror.getAnnotation(CEYLON_LANGUAGE_ACTUAL_ANNOTATION) != null;
decl.setActual(actual);
if (actual) {
Declaration refined = klass.getRefinedMember(decl.getName(), getSignature(decl), decl.isVariadic());
decl.setRefinedDeclaration(refined);
}
} else {
if (isOverridingMethod(methodMirror)) {
Declaration refined = klass.getRefinedMember(decl.getName(), getSignature(decl), decl.isVariadic());
if (refined instanceof FieldValue == false) {
decl.setActual(true);
decl.setRefinedDeclaration(refined);
}
}
}
// for Ceylon methods
if (decl instanceof JavaMethod && ModelUtil.isCeylonDeclaration(klass)) {
if (!methodMirror.getTypeParameters().isEmpty() && // lazy loading just to check.
JvmBackendUtil.supportsReified(decl)) {
checkReifiedTypeDescriptors(methodMirror.getTypeParameters().size(), container.getQualifiedNameString(), methodMirror, false);
}
}
}
}
completeVariable(decl);
}
use of org.eclipse.ceylon.model.typechecker.model.ClassOrInterface in project ceylon by eclipse.
the class AbstractModelLoader method complete.
private void complete(ClassOrInterface klass, ClassMirror classMirror) {
boolean isFromJDK = isFromJDK(classMirror);
boolean isCeylon = (classMirror.getAnnotation(CEYLON_CEYLON_ANNOTATION) != null);
boolean isNativeHeaderMember = klass.isNativeHeader();
// now that everything has containers, do the inner classes
if (klass instanceof Class == false || !klass.isOverloaded()) {
// this will not load inner classes of overloads, but that's fine since we want them in the
// abstracted super class (the real one)
addInnerClasses(klass, classMirror);
}
// Java classes with multiple constructors get turned into multiple Ceylon classes
// Here we get the specific constructor that was assigned to us (if any)
MethodMirror constructor = null;
if (klass instanceof LazyClass) {
constructor = ((LazyClass) klass).getConstructor();
setHasJpaConstructor((LazyClass) klass, classMirror);
}
// Set up enumerated constructors before looking at getters,
// because the type of the getter is the constructor's type
Boolean hasConstructors = hasConstructors(classMirror);
// only add constructors to the abstraction class
if (hasConstructors != null && hasConstructors && !klass.isOverloaded()) {
HashMap<String, MethodMirror> m = new HashMap<>();
MethodMirrorFilter methodFilter;
// collect
if (klass.isAbstraction()) {
methodFilter = namedConstructorOnly;
} else {
methodFilter = constructorOnly;
}
// Get all the java constructors...
for (MethodMirror ctorMirror : getClassConstructors(classMirror, classMirror, methodFilter)) {
m.put(getCtorName(ctorMirror), ctorMirror);
}
for (MethodMirror ctor : getClassConstructors(classMirror, classMirror.getEnclosingClass() != null ? classMirror.getEnclosingClass() : classMirror, new ValueConstructorGetter(classMirror))) {
Object name = getAnnotationValue(ctor, CEYLON_NAME_ANNOTATION);
MethodMirror ctorMirror = m.remove(name);
Constructor c;
// When for each value constructor getter we can add a Value+Constructor
if (ctorMirror == null) {
// Only add a Constructor using the getter if we couldn't find a matching java constructor
c = addConstructor((Class) klass, classMirror, ctor, isNativeHeaderMember);
} else {
c = addConstructor((Class) klass, classMirror, ctorMirror, isNativeHeaderMember);
}
FunctionOrValue fov = addConstructorMethorOrValue((Class) klass, classMirror, ctor, c, isNativeHeaderMember);
if (isCeylon && shouldCreateNativeHeader(c, klass)) {
Constructor hdr;
if (ctorMirror == null) {
hdr = addConstructor((Class) klass, classMirror, ctor, true);
} else {
hdr = addConstructor((Class) klass, classMirror, ctorMirror, true);
}
FunctionOrValue hdrfov = addConstructorMethorOrValue((Class) klass, classMirror, ctorMirror, hdr, true);
initNativeHeader(hdr, c);
initNativeHeader(hdrfov, fov);
} else if (isCeylon && shouldLinkNatives(c)) {
initNativeHeaderMember(c);
initNativeHeaderMember(fov);
}
}
// Everything left must be a callable constructor, so add Function+Constructor
for (MethodMirror ctorMirror : m.values()) {
Constructor c = addConstructor((Class) klass, classMirror, ctorMirror, isNativeHeaderMember);
FunctionOrValue fov = addConstructorMethorOrValue((Class) klass, classMirror, ctorMirror, c, isNativeHeaderMember);
if (isCeylon && shouldCreateNativeHeader(c, klass)) {
Constructor hdr = addConstructor((Class) klass, classMirror, ctorMirror, true);
FunctionOrValue hdrfov = addConstructorMethorOrValue((Class) klass, classMirror, ctorMirror, hdr, true);
initNativeHeader(hdr, c);
initNativeHeader(hdrfov, fov);
} else if (isCeylon && shouldLinkNatives(c)) {
initNativeHeaderMember(c);
initNativeHeaderMember(fov);
}
}
}
// Turn a list of possibly overloaded methods into a map
// of lists that contain methods with the same name
Map<String, List<MethodMirror>> methods = new LinkedHashMap<String, List<MethodMirror>>();
collectMethods(classMirror.getDirectMethods(), methods, isCeylon, isFromJDK);
if (isCeylon && klass instanceof LazyInterface && JvmBackendUtil.isCompanionClassNeeded(klass)) {
ClassMirror companionClass = ((LazyInterface) klass).companionClass;
if (companionClass != null)
collectMethods(companionClass.getDirectMethods(), methods, isCeylon, isFromJDK);
else
logWarning("CompanionClass missing for " + klass);
}
boolean seenStringAttribute = false;
boolean seenHashAttribute = false;
boolean seenStringGetter = false;
boolean seenHashGetter = false;
MethodMirror stringSetter = null;
MethodMirror hashSetter = null;
Map<String, List<MethodMirror>> getters = new HashMap<>();
Map<String, List<MethodMirror>> setters = new HashMap<>();
// Collect attributes
for (List<MethodMirror> methodMirrors : methods.values()) {
for (MethodMirror methodMirror : methodMirrors) {
// same tests as in isMethodOverloaded()
if (methodMirror.isConstructor() || isInstantiator(methodMirror)) {
break;
} else if (isGetter(methodMirror)) {
String name = getJavaAttributeName(methodMirror);
putMultiMap(getters, name, methodMirror);
} else if (isSetter(methodMirror)) {
String name = getJavaAttributeName(methodMirror);
putMultiMap(setters, name, methodMirror);
} else if (isHashAttribute(methodMirror)) {
putMultiMap(getters, "hash", methodMirror);
seenHashAttribute = true;
} else if (isStringAttribute(methodMirror)) {
putMultiMap(getters, "string", methodMirror);
seenStringAttribute = true;
} else {
// we never map getString to a property, or generate one
if (isStringGetter(methodMirror))
seenStringGetter = true;
else // same for getHash
if (isHashGetter(methodMirror))
seenHashGetter = true;
else if (isStringSetter(methodMirror)) {
stringSetter = methodMirror;
// we will perhaps add it later
continue;
} else if (isHashSetter(methodMirror)) {
hashSetter = methodMirror;
// we will perhaps add it later
continue;
}
}
}
}
// now figure out which properties to add
NEXT_PROPERTY: for (Map.Entry<String, List<MethodMirror>> getterEntry : getters.entrySet()) {
String propertyName = getterEntry.getKey();
List<MethodMirror> getterList = getterEntry.getValue();
for (MethodMirror getterMethod : getterList) {
// if it's hashCode() or toString() they win
if (isHashAttribute(getterMethod)) {
// ERASURE
// Un-erasing 'hash' attribute from 'hashCode' method
Declaration decl = addValue(klass, getterMethod, "hash", isCeylon, isNativeHeaderMember);
if (isCeylon && shouldCreateNativeHeader(decl, klass)) {
Declaration hdr = addValue(klass, getterMethod, "hash", true, true);
setNonLazyDeclarationProperties(hdr, classMirror, classMirror, classMirror, true);
initNativeHeader(hdr, decl);
} else if (isCeylon && shouldLinkNatives(decl)) {
initNativeHeaderMember(decl);
}
// remove it as a method and add all other getters with the same name
// as methods
removeMultiMap(methods, getterMethod.getName(), getterMethod);
// next property
continue NEXT_PROPERTY;
}
if (isStringAttribute(getterMethod)) {
// ERASURE
// Un-erasing 'string' attribute from 'toString' method
Declaration decl = addValue(klass, getterMethod, "string", isCeylon, isNativeHeaderMember);
if (isCeylon && shouldCreateNativeHeader(decl, klass)) {
Declaration hdr = addValue(klass, getterMethod, "string", true, true);
setNonLazyDeclarationProperties(hdr, classMirror, classMirror, classMirror, true);
initNativeHeader(hdr, decl);
} else if (isCeylon && shouldLinkNatives(decl)) {
initNativeHeaderMember(decl);
}
// remove it as a method and add all other getters with the same name
// as methods
removeMultiMap(methods, getterMethod.getName(), getterMethod);
// next property
continue NEXT_PROPERTY;
}
}
// we've weeded out toString/hashCode, now if we have a single property it's easy we just add it
if (getterList.size() == 1) {
// FTW!
MethodMirror getterMethod = getterList.get(0);
// simple attribute
Declaration decl = addValue(klass, getterMethod, propertyName, isCeylon, isNativeHeaderMember);
if (isCeylon && shouldCreateNativeHeader(decl, klass)) {
Declaration hdr = addValue(klass, getterMethod, propertyName, true, true);
setNonLazyDeclarationProperties(hdr, classMirror, classMirror, classMirror, true);
initNativeHeader(hdr, decl);
} else if (isCeylon && shouldLinkNatives(decl)) {
initNativeHeaderMember(decl);
}
// remove it as a method
removeMultiMap(methods, getterMethod.getName(), getterMethod);
// next property
continue NEXT_PROPERTY;
}
// we have more than one
// if we have a setter let's favour the one that matches the setter
List<MethodMirror> matchingSetters = setters.get(propertyName);
if (matchingSetters != null) {
if (matchingSetters.size() == 1) {
// single setter will tell us what we need
MethodMirror matchingSetter = matchingSetters.get(0);
MethodMirror bestGetter = null;
boolean booleanSetter = matchingSetter.getParameters().get(0).getType().getKind() == TypeKind.BOOLEAN;
/*
* Getters do not support overloading since they have no parameters, so they can only differ based on
* name. For boolean properties we favour "is" getters, otherwise "get" getters.
*/
for (MethodMirror getterMethod : getterList) {
if (propertiesMatch(klass, getterMethod, matchingSetter)) {
if (bestGetter == null)
bestGetter = getterMethod;
else {
// we have two getters, find the best one
if (booleanSetter) {
// favour the "is" getter
if (getterMethod.getName().startsWith("is"))
bestGetter = getterMethod;
// else keep the current best, it must be an "is" getter
} else {
// favour the "get" getter
if (getterMethod.getName().startsWith("get"))
bestGetter = getterMethod;
// else keep the current best, it must be a "get" getter
}
break;
}
}
}
if (bestGetter != null) {
// got it!
// simple attribute
Declaration decl = addValue(klass, bestGetter, propertyName, isCeylon, isNativeHeaderMember);
if (isCeylon && shouldCreateNativeHeader(decl, klass)) {
Declaration hdr = addValue(klass, bestGetter, propertyName, true, true);
setNonLazyDeclarationProperties(hdr, classMirror, classMirror, classMirror, true);
initNativeHeader(hdr, decl);
} else if (isCeylon && shouldLinkNatives(decl)) {
initNativeHeaderMember(decl);
}
// remove it as a method and add all other getters with the same name
// as methods
removeMultiMap(methods, bestGetter.getName(), bestGetter);
// next property
continue NEXT_PROPERTY;
}
// else we cannot find the right getter thanks to the setter, keep looking
}
}
// setters did not help us, we have more than one getter, one must be "is"/boolean, the other "get"
if (getterList.size() == 2) {
// if the "get" is also a boolean, prefer the "is"
MethodMirror isMethod = null;
MethodMirror getMethod = null;
for (MethodMirror getterMethod : getterList) {
if (getterMethod.getName().startsWith("is"))
isMethod = getterMethod;
else if (getterMethod.getName().startsWith("get"))
getMethod = getterMethod;
}
if (isMethod != null && getMethod != null) {
MethodMirror bestGetter;
if (getMethod.getReturnType().getKind() == TypeKind.BOOLEAN) {
// pick the is method
bestGetter = isMethod;
} else {
// just take the getter
bestGetter = getMethod;
}
// simple attribute
Declaration decl = addValue(klass, bestGetter, propertyName, isCeylon, isNativeHeaderMember);
if (isCeylon && shouldCreateNativeHeader(decl, klass)) {
Declaration hdr = addValue(klass, bestGetter, propertyName, true, true);
setNonLazyDeclarationProperties(hdr, classMirror, classMirror, classMirror, true);
initNativeHeader(hdr, decl);
} else if (isCeylon && shouldLinkNatives(decl)) {
initNativeHeaderMember(decl);
}
// remove it as a method and add all other getters with the same name
// as methods
removeMultiMap(methods, bestGetter.getName(), bestGetter);
// next property
continue NEXT_PROPERTY;
}
}
}
Set<String> fieldNames = new HashSet<String>();
// collect field names first
for (FieldMirror fieldMirror : classMirror.getDirectFields()) {
if (!keepField(fieldMirror, isCeylon, isFromJDK))
continue;
// do not change the name case here otherwise it will appear taken by itself
fieldNames.add(fieldMirror.getName());
}
// now handle fields
for (FieldMirror fieldMirror : classMirror.getDirectFields()) {
if (!keepField(fieldMirror, isCeylon, isFromJDK))
continue;
String name = fieldMirror.getName();
if (!isCeylon && !JvmBackendUtil.isInitialLowerCase(name)) {
String newName = NamingBase.getJavaBeanName(name);
if (!fieldNames.contains(newName) && !addingFieldWouldConflictWithMember(klass, newName) && !methods.containsKey(newName))
name = newName;
}
// skip the field if "we've already got one"
boolean conflicts = addingFieldWouldConflictWithMember(klass, name);
if (!conflicts) {
Declaration decl = addValue(klass, name, fieldMirror, isCeylon, isNativeHeaderMember);
if (isCeylon && shouldCreateNativeHeader(decl, klass)) {
Declaration hdr = addValue(klass, name, fieldMirror, true, true);
setNonLazyDeclarationProperties(hdr, classMirror, classMirror, classMirror, true);
initNativeHeader(hdr, decl);
} else if (isCeylon && shouldLinkNatives(decl)) {
initNativeHeaderMember(decl);
}
}
}
// Now mark all Values for which Setters exist as variable
for (List<MethodMirror> variables : setters.values()) {
for (MethodMirror setter : variables) {
String name = getJavaAttributeName(setter);
// make sure we handle private postfixes
name = JvmBackendUtil.strip(name, isCeylon, setter.isPublic());
Declaration decl = klass.getMember(name, null, false);
// skip Java fields, which we only get if there is no getter method, in that case just add the setter method
if (decl instanceof JavaBeanValue) {
JavaBeanValue value = (JavaBeanValue) decl;
// only add the setter if it has the same visibility as the getter
if (setter.isPublic() && value.mirror.isPublic() || setter.isProtected() && value.mirror.isProtected() || setter.isDefaultAccess() && value.mirror.isDefaultAccess() || (!setter.isPublic() && !value.mirror.isPublic() && !setter.isProtected() && !value.mirror.isProtected() && !setter.isDefaultAccess() && !value.mirror.isDefaultAccess())) {
VariableMirror setterParam = setter.getParameters().get(0);
Module module = ModelUtil.getModuleContainer(klass);
Type paramType = obtainType(setterParam.getType(), setterParam, klass, module, "setter '" + setter.getName() + "'", klass);
NullStatus nullPolicy = getUncheckedNullPolicy(isCeylon, setterParam.getType(), setterParam);
// if there's no annotation on the setter param, inherit annotations from getter
if (nullPolicy == NullStatus.UncheckedNull)
nullPolicy = getUncheckedNullPolicy(isCeylon, value.mirror.getReturnType(), value.mirror);
switch(nullPolicy) {
case Optional:
if (!isCeylon) {
paramType = makeOptionalTypePreserveUnderlyingType(paramType, module);
}
break;
}
// only add the setter if it has exactly the same type as the getter
if (paramType.isExactly(value.getType())) {
value.setVariable(true);
value.setSetterName(setter.getName());
if (value.isTransient()) {
// must be a real setter
makeSetter(value, null);
}
if (!isCeylon && isCoercedMethod(setter)) {
// leave it as a method so we get a fake method for it
} else {
// remove it as a method
removeMultiMap(methods, setter.getName(), setter);
}
} else
logVerbose("Setter parameter type for " + name + " does not match corresponding getter type, adding setter as a method");
} else {
logVerbose("Setter visibility for " + name + " does not match corresponding getter visibility, adding setter as a method");
}
}
}
}
// special cases if we have hashCode() setHash() and no getHash()
if (hashSetter != null) {
if (seenHashAttribute && !seenHashGetter) {
Declaration attr = klass.getDirectMember("hash", null, false);
if (attr instanceof JavaBeanValue) {
((JavaBeanValue) attr).setVariable(true);
((JavaBeanValue) attr).setSetterName(hashSetter.getName());
// remove it as a method
removeMultiMap(methods, hashSetter.getName(), hashSetter);
}
}
}
// special cases if we have toString() setString() and no getString()
if (stringSetter != null) {
if (seenStringAttribute && !seenStringGetter) {
Declaration attr = klass.getDirectMember("string", null, false);
if (attr instanceof JavaBeanValue) {
((JavaBeanValue) attr).setVariable(true);
((JavaBeanValue) attr).setSetterName(stringSetter.getName());
// remove it as a method
removeMultiMap(methods, stringSetter.getName(), stringSetter);
}
}
}
// Add the methods, treat remaining getters/setters as methods
for (List<MethodMirror> methodMirrors : methods.values()) {
boolean isOverloaded = isMethodOverloaded(methodMirrors, isCeylon);
List<Declaration> overloads = null;
for (MethodMirror methodMirror : methodMirrors) {
// normal method
Function m = addMethod(klass, methodMirror, classMirror, isCeylon, isOverloaded, isNativeHeaderMember, false);
if (!isOverloaded && isCeylon && shouldCreateNativeHeader(m, klass)) {
Declaration hdr = addMethod(klass, methodMirror, classMirror, true, isOverloaded, true, false);
setNonLazyDeclarationProperties(hdr, classMirror, classMirror, classMirror, true);
initNativeHeader(hdr, m);
} else if (isCeylon && shouldLinkNatives(m)) {
initNativeHeaderMember(m);
}
if (m.isOverloaded()) {
overloads = overloads == null ? new ArrayList<Declaration>(methodMirrors.size()) : overloads;
overloads.add(m);
}
if (isOverloaded && !isCeylon && isCoercedMethod(methodMirror)) {
Function coercionMethod = addMethod(klass, methodMirror, classMirror, isCeylon, isOverloaded, isNativeHeaderMember, true);
coercionMethod.setRealFunction(m);
overloads.add(coercionMethod);
}
}
if (overloads != null && !overloads.isEmpty()) {
// We create an extra "abstraction" method for overloaded methods
Function abstractionMethod = addMethod(klass, methodMirrors.get(0), classMirror, isCeylon, false, false, false);
abstractionMethod.setAbstraction(true);
abstractionMethod.setOverloads(overloads);
abstractionMethod.setType(newUnknownType());
}
}
// Having loaded methods and values, we can now set the constructor parameters
if (constructor != null && !isDefaultNamedCtor(classMirror, constructor) && (!(klass instanceof LazyClass) || !((LazyClass) klass).isAnonymous()))
setParameters((Class) klass, classMirror, constructor, isCeylon, klass, klass.isCoercionPoint());
// Now marry-up attributes and parameters)
if (klass instanceof Class) {
for (Declaration m : klass.getMembers()) {
if (JvmBackendUtil.isValue(m)) {
Value v = (Value) m;
Parameter p = ((Class) klass).getParameter(v.getName());
if (p != null) {
p.setHidden(true);
}
}
}
}
setExtendedType(klass, classMirror);
setSatisfiedTypes(klass, classMirror);
setCaseTypes(klass, classMirror);
setAnnotations(klass, classMirror, isNativeHeaderMember);
if (klass instanceof Interface)
klass.setSamName(isFunctionalInterfaceWithExceptions(classMirror));
// local declarations come last, because they need all members to be completed first
if (!klass.isAlias()) {
ClassMirror containerMirror = classMirror;
if (klass instanceof LazyInterface) {
ClassMirror companionClass = ((LazyInterface) klass).companionClass;
if (companionClass != null)
containerMirror = companionClass;
}
addLocalDeclarations((LazyContainer) klass, containerMirror, classMirror);
}
if (!isCeylon) {
// In java, a class can inherit a public member from a non-public supertype
for (Declaration d : klass.getMembers()) {
if (d.isShared()) {
d.setVisibleScope(null);
}
}
}
}
use of org.eclipse.ceylon.model.typechecker.model.ClassOrInterface in project ceylon by eclipse.
the class ExpressionTransformer method makeMemberValueOrFunctionDeclarationLiteral.
JCExpression makeMemberValueOrFunctionDeclarationLiteral(Node node, Declaration declaration, boolean f) {
// it's a member we get from its container declaration
if (declaration.getContainer() instanceof ClassOrInterface == false)
return makeErroneous(node, "compiler bug: " + declaration.getContainer() + " is not a supported type parameter container");
ClassOrInterface container = (ClassOrInterface) declaration.getContainer();
// use the generated class to get to the declaration literal
JCExpression metamodelCall = makeTypeDeclarationLiteral(container);
JCExpression metamodelCast = makeJavaType(typeFact().getLanguageModuleDeclarationTypeDeclaration(Decl.isConstructor(declaration) ? "ClassDeclaration" : "ClassOrInterfaceDeclaration").getType(), JT_NO_PRIMITIVES);
metamodelCall = make().TypeCast(metamodelCast, metamodelCall);
String memberClassName;
String memberAccessor;
if (declaration instanceof Class)
memberClassName = "ClassDeclaration";
else if (Decl.isConstructor(declaration))
memberClassName = "ConstructorDeclaration";
else if (declaration instanceof Interface)
memberClassName = "InterfaceDeclaration";
else if (declaration instanceof Function)
memberClassName = "FunctionDeclaration";
else if (declaration instanceof Value) {
memberClassName = "ValueDeclaration";
} else {
return makeErroneous(node, "compiler bug: " + declaration + " is not a supported declaration literal");
}
if (Decl.isConstructor(declaration))
memberAccessor = "getConstructorDeclaration";
else
memberAccessor = f ? "getMemberDeclaration" : "getDeclaredMemberDeclaration";
TypeDeclaration metamodelDecl = (TypeDeclaration) typeFact().getLanguageModuleDeclarationDeclaration(memberClassName);
JCExpression memberType = makeJavaType(metamodelDecl.getType());
JCExpression reifiedMemberType = makeReifiedTypeArgument(metamodelDecl.getType());
JCExpression memberCall = make().Apply(List.of(memberType), makeSelect(metamodelCall, memberAccessor), List.of(reifiedMemberType, ceylonLiteral(declaration.getName())));
return memberCall;
}
use of org.eclipse.ceylon.model.typechecker.model.ClassOrInterface in project ceylon by eclipse.
the class ExpressionTransformer method lostTypeParameterInInheritance.
private boolean lostTypeParameterInInheritance(ClassOrInterface exprDecl, ClassOrInterface commonDecl, boolean searchInterfaces, boolean lostTypeParameter) {
// stop if we found the common decl
if (Decl.equal(exprDecl, commonDecl))
return lostTypeParameter;
if (searchInterfaces) {
// find a match in interfaces
for (Type pt : exprDecl.getSatisfiedTypes()) {
// FIXME: this is very heavy-handed because we consider that once we've lost a type parameter we've lost them all
// but we could optimise this by checking:
// 1/ which type parameter we've really lost
// 2/ if the type parameters we're passing to our super type actually depend in any way from type parameters we've lost
boolean lostTypeParameter2 = lostTypeParameter || isTurnedToRaw(pt);
pt = simplifyType(pt);
// skip unknown types
if (pt.isUnknown())
continue;
// it has to be an interface
Interface interf = (Interface) pt.getDeclaration();
if (lostTypeParameterInInheritance(interf, commonDecl, searchInterfaces, lostTypeParameter2))
return true;
}
}
// search for super classes
Type extendedType = exprDecl.getExtendedType();
if (extendedType != null) {
// FIXME: see above
boolean lostTypeParameter2 = lostTypeParameter || isTurnedToRaw(extendedType);
extendedType = simplifyType(extendedType);
// it has to be a Class
Class extendedTypeDeclaration = (Class) extendedType.getDeclaration();
// looks like Object's superclass is Object, so stop right there
if (extendedTypeDeclaration != typeFact().getObjectDeclaration())
return lostTypeParameterInInheritance(extendedTypeDeclaration, commonDecl, searchInterfaces, lostTypeParameter2);
}
// didn't find it
return false;
}
use of org.eclipse.ceylon.model.typechecker.model.ClassOrInterface in project ceylon by eclipse.
the class ExpressionTransformer method transformBaseInstantiation.
private JCExpression transformBaseInstantiation(Invocation invocation, CallBuilder callBuilder, TransformedInvocationPrimary transformedPrimary) {
JCExpression resultExpr;
Tree.BaseTypeExpression type = (Tree.BaseTypeExpression) invocation.getPrimary();
Declaration declaration = type.getDeclaration();
invocation.location(callBuilder);
if (Strategy.generateInstantiator(declaration)) {
resultExpr = callBuilder.typeArguments(List.<JCExpression>nil()).invoke(naming.makeInstantiatorMethodName(transformedPrimary.expr, (Class) declaration)).build();
if (Strategy.isInstantiatorUntyped(declaration)) {
// $new method declared to return Object, so needs typecast
resultExpr = make().TypeCast(makeJavaType(((TypeDeclaration) declaration).getType()), resultExpr);
}
} else {
Type classType = (Type) type.getTarget();
if (isJavaArray(classType)) {
JCExpression typeExpr = makeJavaType(classType, AbstractTransformer.JT_CLASS_NEW | AbstractTransformer.JT_RAW);
callBuilder.javaArrayInstance(typeExpr);
if (isJavaObjectArray(classType)) {
Type elementType = classType.getTypeArgumentList().get(0);
MultidimensionalArray multiArray = getMultiDimensionalArrayInfo(elementType);
if (multiArray != null)
elementType = multiArray.type;
// array of Foo is fine, array of Nothing too
if (elementType.getDeclaration() instanceof ClassOrInterface || elementType.isNothing()) {
if (!elementType.getTypeArgumentList().isEmpty())
callBuilder.javaArrayInstanceNeedsCast(makeJavaType(classType, AbstractTransformer.JT_NO_PRIMITIVES));
} else {
// if it's an array of union, intersection or type param we need a runtime allocation
callBuilder.javaArrayInstanceIsGeneric(makeReifiedTypeArgument(elementType), multiArray != null ? multiArray.dimension + 1 : 1);
}
}
} else {
if (Decl.isConstructor(classType.getDeclaration())) {
classType = classType.getExtendedType();
}
JCExpression typeExpr = makeJavaType(classType, AbstractTransformer.JT_CLASS_NEW);
callBuilder.instantiate(typeExpr);
}
resultExpr = callBuilder.build();
}
return resultExpr;
}
Aggregations