use of com.redhat.ceylon.model.typechecker.model.Scope in project ceylon-compiler by ceylon.
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) {
if (qualExpr == null && // statics are not members that can be inherited
!decl.isStaticallyImportable() && !Decl.isConstructor(decl) && decl.isMember() && // and have a name mapping)
expr.getTarget().getDeclaration() == decl && !Decl.isLocalToInitializer(decl) && !isWithinSuperInvocation()) {
// First check whether the expression is captured from an enclosing scope
TypeDeclaration outer = null;
// get the ClassOrInterface container of the declaration
Scope stop = Decl.getClassOrInterfaceContainer(decl, false);
if (stop instanceof TypeDeclaration) {
// reified scope
Scope scope = expr.getScope();
while (!(scope instanceof Package)) {
if (scope.equals(stop)) {
outer = (TypeDeclaration) stop;
break;
}
scope = scope.getContainer();
}
}
// If not it might be inherited...
if (outer == null) {
outer = expr.getScope().getInheritingDeclaration(decl);
}
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 (decl.isClassMember() && ((Class) decl.getContainer()).isAnonymous() && ((Class) decl.getContainer()).isToplevel()) {
Class container = (Class) decl.getContainer();
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 com.redhat.ceylon.model.typechecker.model.Scope in project ceylon-compiler by ceylon.
the class ExpressionTransformer method functionalParameterRequiresCallable.
/**
* Determines whether we need to generate an AbstractCallable when taking
* a method reference to a method that's declared as a FunctionalParameter
*/
private boolean functionalParameterRequiresCallable(Function functionalParameter, Tree.StaticMemberOrTypeExpression expr) {
if (!functionalParameter.isParameter()) {
throw new BugException();
}
boolean hasMethod = JvmBackendUtil.createMethod(functionalParameter);
if (!hasMethod) {
// A functional parameter that's not method wrapped will already be Callable-wrapped
return false;
}
// Optimization: If we're in a scope where the Callable field is visible
// we don't need to create a method ref
Scope scope = expr.getScope();
while (true) {
if (scope instanceof Package) {
break;
}
if (scope.equals(functionalParameter.getContainer())) {
return false;
}
scope = scope.getContainer();
}
// Otherwise we do require an AbstractCallable.
return true;
}
use of com.redhat.ceylon.model.typechecker.model.Scope in project ceylon-compiler by ceylon.
the class CodegenUtil method isContainerFunctionalParameter.
public static boolean isContainerFunctionalParameter(Declaration declaration) {
Scope containerScope = declaration.getContainer();
Declaration containerDeclaration;
if (containerScope instanceof Specification) {
containerDeclaration = ((Specification) containerScope).getDeclaration();
} else if (containerScope instanceof Declaration) {
containerDeclaration = (Declaration) containerScope;
} else {
throw BugException.unhandledCase(containerScope);
}
return containerDeclaration instanceof Function && ((Function) containerDeclaration).isParameter();
}
use of com.redhat.ceylon.model.typechecker.model.Scope in project ceylon-compiler by ceylon.
the class CodegenUtil method getJavaNameOfDeclaration.
/**
* <p>Returns the fully qualified name java name of the given declaration,
* for example
* {@code ceylon.language.sum_.sum} or {@code my.package.Outer.Inner}.
* for any toplevel or externally visible Ceylon declaration.</p>
*
* <p>Used by the IDE to support finding/renaming Ceylon declarations
* called from Java.</p>
*/
public static String getJavaNameOfDeclaration(Declaration decl) {
Scope s = decl.getScope();
while (!(s instanceof Package)) {
if (!(s instanceof TypeDeclaration)) {
throw new IllegalArgumentException();
}
s = s.getContainer();
}
String result;
Naming n = new Naming(null, null);
if (decl instanceof TypeDeclaration) {
result = n.makeTypeDeclarationName((TypeDeclaration) decl, DeclNameFlag.QUALIFIED);
// remove initial .
result = result.substring(1);
if (decl.isAnonymous()) {
result += "." + Unfix.get_.toString();
}
} else if (decl instanceof TypedDeclaration) {
if (decl.isToplevel()) {
result = n.getName((TypedDeclaration) decl, Naming.NA_FQ | Naming.NA_WRAPPER | Naming.NA_MEMBER);
// remove initial .
result = result.substring(1);
} else {
Scope container = decl.getContainer();
if (container instanceof TypeDeclaration) {
String qualifier = getJavaNameOfDeclaration((TypeDeclaration) container);
result = qualifier + n.getName((TypedDeclaration) decl, Naming.NA_MEMBER);
} else {
throw new IllegalArgumentException();
}
}
} else {
throw new RuntimeException();
}
return result;
}
use of com.redhat.ceylon.model.typechecker.model.Scope in project ceylon-compiler by ceylon.
the class AbstractTransformer method makeReifiedTypeArgumentResolved.
private JCExpression makeReifiedTypeArgumentResolved(Type pt, boolean qualified) {
if (pt.isUnion()) {
// FIXME: refactor this shite
List<JCExpression> typeTestArguments = List.nil();
java.util.List<Type> typeParameters = pt.getCaseTypes();
if (typeParameters.size() == 2) {
Type alternative = null;
if (typeParameters.get(0).isEmpty())
alternative = typeParameters.get(1);
else if (typeParameters.get(1).isEmpty())
alternative = typeParameters.get(0);
if (alternative != null && alternative.isTuple()) {
JCExpression tupleType = makeTupleTypeDescriptor(alternative, true);
if (tupleType != null)
return tupleType;
}
}
for (int i = typeParameters.size() - 1; i >= 0; i--) {
typeTestArguments = typeTestArguments.prepend(makeReifiedTypeArgument(typeParameters.get(i)));
}
return make().Apply(null, makeSelect(makeTypeDescriptorType(), "union"), typeTestArguments);
} else if (pt.isIntersection()) {
List<JCExpression> typeTestArguments = List.nil();
java.util.List<Type> typeParameters = pt.getSatisfiedTypes();
for (int i = typeParameters.size() - 1; i >= 0; i--) {
typeTestArguments = typeTestArguments.prepend(makeReifiedTypeArgument(typeParameters.get(i)));
}
return make().Apply(null, makeSelect(makeTypeDescriptorType(), "intersection"), typeTestArguments);
} else if (pt.isNothing()) {
return makeNothingTypeDescriptor();
}
TypeDeclaration declaration = pt.getDeclaration();
if (declaration instanceof Constructor) {
pt = pt.getExtendedType();
declaration = pt.getDeclaration();
}
if (pt.isClassOrInterface()) {
if (declaration.isJavaEnum()) {
pt = pt.getExtendedType();
declaration = pt.getDeclaration();
}
// see if we have an alias for it
if (supportsReifiedAlias((ClassOrInterface) declaration)) {
JCExpression qualifier = naming.makeDeclarationName(declaration, DeclNameFlag.QUALIFIED);
return makeSelect(qualifier, naming.getTypeDescriptorAliasName());
}
if (pt.isTuple()) {
JCExpression tupleType = makeTupleTypeDescriptor(pt, false);
if (tupleType != null)
return tupleType;
}
// no alias, must build it
List<JCExpression> typeTestArguments = makeReifiedTypeArgumentsResolved(pt.getTypeArgumentList(), qualified);
JCExpression thisType = makeUnerasedClassLiteral(declaration);
// do we have variance overrides?
Map<TypeParameter, SiteVariance> varianceOverrides = pt.getVarianceOverrides();
if (!varianceOverrides.isEmpty()) {
// we need to pass them as second argument then, in an array
ListBuffer<JCExpression> varianceElements = new ListBuffer<JCExpression>();
for (TypeParameter typeParameter : declaration.getTypeParameters()) {
SiteVariance useSiteVariance = varianceOverrides.get(typeParameter);
String selector;
if (useSiteVariance != null) {
switch(useSiteVariance) {
case IN:
selector = "IN";
break;
case OUT:
selector = "OUT";
break;
default:
selector = "NONE";
break;
}
} else {
selector = "NONE";
}
JCExpression varianceElement = make().Select(makeIdent(syms().ceylonVarianceType), names().fromString(selector));
varianceElements.append(varianceElement);
}
JCNewArray varianceArray = make().NewArray(makeIdent(syms().ceylonVarianceType), List.<JCExpression>nil(), varianceElements.toList());
typeTestArguments = typeTestArguments.prepend(varianceArray);
}
typeTestArguments = typeTestArguments.prepend(thisType);
JCExpression classDescriptor = make().Apply(null, makeSelect(makeTypeDescriptorType(), "klass"), typeTestArguments);
Type qualifyingType = pt.getQualifyingType();
JCExpression containerType = null;
if (qualifyingType == null && // ignore qualifying types of static java declarations
(Decl.isCeylon(declaration) || !declaration.isStaticallyImportable())) {
// it may be contained in a function or value, and we want its type
Declaration enclosingDeclaration = getDeclarationContainer(declaration);
if (enclosingDeclaration instanceof TypedDeclaration)
containerType = makeTypedDeclarationTypeDescriptorResolved((TypedDeclaration) enclosingDeclaration);
else if (enclosingDeclaration instanceof TypeDeclaration) {
qualifyingType = ((TypeDeclaration) enclosingDeclaration).getType();
}
}
if (qualifyingType != null && qualifyingType.getDeclaration() instanceof Constructor) {
qualifyingType = qualifyingType.getQualifyingType();
}
if (qualifyingType != null) {
containerType = makeReifiedTypeArgumentResolved(qualifyingType, true);
}
if (containerType == null) {
return classDescriptor;
} else {
return make().Apply(null, makeSelect(makeTypeDescriptorType(), "member"), List.of(containerType, classDescriptor));
}
} else if (pt.isTypeParameter()) {
TypeParameter tp = (TypeParameter) declaration;
String name = naming.getTypeArgumentDescriptorName(tp);
if (!qualified || isTypeParameterSubstituted(tp))
return makeUnquotedIdent(name);
Scope container = tp.getContainer();
JCExpression qualifier = null;
if (container instanceof Class) {
qualifier = naming.makeQualifiedThis(makeJavaType(((Class) container).getType(), JT_RAW));
} else if (container instanceof Interface) {
qualifier = naming.makeQualifiedThis(makeJavaType(((Interface) container).getType(), JT_COMPANION | JT_RAW));
} else if (container instanceof Function) {
// name must be a unique name, as returned by getTypeArgumentDescriptorName
return makeUnquotedIdent(name);
} else {
throw BugException.unhandledCase(container);
}
return makeSelect(qualifier, name);
} else {
throw BugException.unhandledDeclarationCase(declaration);
}
}
Aggregations