use of com.redhat.ceylon.model.typechecker.model.Type in project ceylon-compiler by ceylon.
the class AbstractTransformer method makeTupleTypeDescriptor.
private JCExpression makeTupleTypeDescriptor(Type pt, boolean firstElementOptional) {
java.util.List<Type> tupleElementTypes = typeFact().getTupleElementTypes(pt);
boolean isVariadic = typeFact().isTupleLengthUnbounded(pt);
boolean atLeastOne = false;
boolean needsRestSplit = false;
Type restType = null;
if (isVariadic) {
// unwrap the last element
restType = tupleElementTypes.get(tupleElementTypes.size() - 1);
// to optimise
if (restType.isUnknown())
return null;
tupleElementTypes.set(tupleElementTypes.size() - 1, typeFact.getSequentialElementType(restType));
atLeastOne = restType.getDeclaration().inherits(typeFact().getSequenceDeclaration());
// the last rest element may be a type param, in which case we resolve it at runtime
needsRestSplit = !restType.getDeclaration().equals(typeFact.getSequenceDeclaration()) && !restType.getDeclaration().equals(typeFact.getSequentialDeclaration());
}
int firstDefaulted;
if (!firstElementOptional) {
// only do this crazy computation if the first element is not optional (case of []|[A] which is a union type really)
int minimumLength = typeFact().getTupleMinimumLength(pt);
// [B+] -> 1
if (atLeastOne)
minimumLength--;
// [A,B=] -> 1
// [A=,B*] -> 0
// [A,B+] -> 1
// [B*] -> 0
// [B+] -> 0
// [A,B=] -> 2
// [A=,B*] -> 1
// [A,B+] -> 1
// [B*] -> 0
// [B+] -> 0
int nonVariadicParams = tupleElementTypes.size();
if (isVariadic)
nonVariadicParams--;
// [A,B=] -> 2!=1 -> 1
// [A=,B*] -> 1!=0 -> 0
// [A,B+] -> 1==1 -> -1
// [B*] -> 0==0 -> -1
// [B+] -> 0==0 -> -1
firstDefaulted = nonVariadicParams != minimumLength ? minimumLength : -1;
} else {
firstDefaulted = 0;
}
JCExpression restTypeDescriptor = null;
JCExpression restElementTypeDescriptor = null;
if (needsRestSplit) {
Type restElementType = tupleElementTypes.get(tupleElementTypes.size() - 1);
tupleElementTypes.remove(tupleElementTypes.size() - 1);
restTypeDescriptor = makeReifiedTypeArgumentResolved(restType, false);
restElementTypeDescriptor = makeReifiedTypeArgumentResolved(restElementType, false);
}
ListBuffer<JCExpression> args = new ListBuffer<JCExpression>();
if (needsRestSplit) {
args.append(restTypeDescriptor);
args.append(restElementTypeDescriptor);
} else {
args.append(makeBoolean(isVariadic));
args.append(makeBoolean(atLeastOne));
}
args.append(makeInteger(firstDefaulted));
for (Type element : tupleElementTypes) {
args.append(makeReifiedTypeArgumentResolved(element, false));
}
JCExpression tupleDescriptor = make().Apply(null, makeSelect(makeTypeDescriptorType(), needsRestSplit ? "tupleWithRest" : "tuple"), args.toList());
return tupleDescriptor;
}
use of com.redhat.ceylon.model.typechecker.model.Type in project ceylon-compiler by ceylon.
the class AbstractTransformer method hasDependentCovariantTypeParameters.
boolean hasDependentCovariantTypeParameters(Type type) {
if (type.isUnion()) {
for (Type m : type.getCaseTypes()) if (hasDependentCovariantTypeParameters(m))
return true;
return false;
}
if (type.isIntersection()) {
for (Type m : type.getSatisfiedTypes()) if (hasDependentCovariantTypeParameters(m))
return true;
return false;
}
// check its type arguments
// special case for Callable which has only a single type param in Java
boolean isCallable = isCeylonCallable(type);
// check if any type parameter is dependent on and covariant
TypeDeclaration declaration = type.getDeclaration();
java.util.List<TypeParameter> typeParams = declaration.getTypeParameters();
Map<TypeParameter, Type> typeArguments = type.getTypeArguments();
for (TypeParameter typeParam : typeParams) {
Type typeArg = typeArguments.get(typeParam);
if (type.isCovariant(typeParam) && hasDependentTypeParameters(typeParams, typeParam)) {
// see if the type argument in question contains type parameters and is erased to Object
if (containsTypeParameter(typeArg) && willEraseToObject(typeArg))
return true;
}
// now check if we the type argument has the same problem
if (hasDependentCovariantTypeParameters(typeArg))
return true;
// stop after the first type arg for Callable
if (isCallable)
break;
}
return false;
}
use of com.redhat.ceylon.model.typechecker.model.Type in project ceylon-compiler by ceylon.
the class ClassTransformer method transformClassAlias.
private void transformClassAlias(final Tree.ClassDeclaration def, ClassDefinitionBuilder classBuilder) {
ClassAlias model = (ClassAlias) def.getDeclarationModel();
Type aliasedClass = model.getExtendedType();
TypeDeclaration classOrCtor = def.getClassSpecifier().getType().getDeclarationModel();
while (classOrCtor instanceof ClassAlias) {
classOrCtor = ((ClassAlias) classOrCtor).getConstructor();
}
classBuilder.annotations(makeAtAlias(aliasedClass, classOrCtor instanceof Constructor ? (Constructor) classOrCtor : null));
classBuilder.isAlias(true);
MethodDefinitionBuilder instantiator = transformClassAliasInstantiator(def, model, aliasedClass);
ClassDefinitionBuilder cbInstantiator = null;
switch(Strategy.defaultParameterMethodOwner(model)) {
case STATIC:
cbInstantiator = classBuilder;
break;
case OUTER:
cbInstantiator = classBuilder.getContainingClassBuilder();
break;
case OUTER_COMPANION:
cbInstantiator = classBuilder.getContainingClassBuilder().getCompanionBuilder(Decl.getClassOrInterfaceContainer(model, true));
break;
default:
throw BugException.unhandledEnumCase(Strategy.defaultParameterMethodOwner(model));
}
cbInstantiator.method(instantiator);
}
use of com.redhat.ceylon.model.typechecker.model.Type in project ceylon-compiler by ceylon.
the class ClassTransformer method addAmbiguousMembers.
private void addAmbiguousMembers(ClassDefinitionBuilder classBuilder, Interface model) {
// only if we refine more than one interface
java.util.List<Type> satisfiedTypes = model.getSatisfiedTypes();
if (satisfiedTypes.size() <= 1)
return;
Set<Interface> satisfiedInterfaces = new HashSet<Interface>();
for (Type interfaceDecl : model.getSatisfiedTypes()) {
collectInterfaces((Interface) interfaceDecl.getDeclaration(), satisfiedInterfaces);
}
Set<Interface> ambiguousInterfaces = new HashSet<Interface>();
for (Interface satisfiedInterface : satisfiedInterfaces) {
if (isInheritedWithDifferentTypeArguments(satisfiedInterface, model.getType()) != null) {
ambiguousInterfaces.add(satisfiedInterface);
}
}
Set<String> treated = new HashSet<String>();
for (Interface ambiguousInterface : ambiguousInterfaces) {
for (Declaration member : ambiguousInterface.getMembers()) {
String name = member.getName();
// skip if already handled
if (treated.contains(name))
continue;
// skip if it's implemented directly
if (model.getDirectMember(name, null, false) != null) {
treated.add(name);
continue;
}
// find if we have different implementations in two direct interfaces
LOOKUP: for (int i = 0; i < satisfiedTypes.size(); i++) {
Type firstInterface = satisfiedTypes.get(i);
Declaration member1 = firstInterface.getDeclaration().getMember(name, null, false);
// if we can't find it in this interface, move to the next
if (member1 == null)
continue;
// try to find member in other interfaces
for (int j = i + 1; j < satisfiedTypes.size(); j++) {
Type secondInterface = satisfiedTypes.get(j);
Declaration member2 = secondInterface.getDeclaration().getMember(name, null, false);
// if we can't find it in this interface, move to the next
if (member2 == null)
continue;
// we have it in two separate interfaces
Reference typedMember1 = firstInterface.getTypedReference(member1, Collections.<Type>emptyList());
Reference typedMember2 = secondInterface.getTypedReference(member2, Collections.<Type>emptyList());
Type type1 = simplifyType(typedMember1.getType());
Type type2 = simplifyType(typedMember2.getType());
if (!type1.isExactly(type2)) {
// treat it and stop looking for other interfaces
addAmbiguousMember(classBuilder, model, name);
break LOOKUP;
}
}
}
// that member has no conflict
treated.add(name);
}
}
}
use of com.redhat.ceylon.model.typechecker.model.Type in project ceylon-compiler by ceylon.
the class ClassTransformer method transformSpecifiedMethodBody.
List<JCStatement> transformSpecifiedMethodBody(Tree.MethodDeclaration def, SpecifierExpression specifierExpression) {
final Function model = def.getDeclarationModel();
List<JCStatement> body;
Tree.MethodDeclaration methodDecl = def;
boolean isLazy = specifierExpression instanceof Tree.LazySpecifierExpression;
boolean returnNull = false;
JCExpression bodyExpr;
Tree.Term term = null;
if (specifierExpression != null && specifierExpression.getExpression() != null) {
term = Decl.unwrapExpressionsUntilTerm(specifierExpression.getExpression());
HasErrorException error = errors().getFirstExpressionErrorAndMarkBrokenness(term);
if (error != null) {
return List.<JCStatement>of(this.makeThrowUnresolvedCompilationError(error));
}
}
if (!isLazy && term instanceof Tree.FunctionArgument) {
// Function specified with lambda: Don't bother generating a
// Callable, just transform the expr to use as the method body.
Tree.FunctionArgument fa = (Tree.FunctionArgument) term;
Type resultType = model.getType();
returnNull = isAnything(resultType) && fa.getExpression().getUnboxed();
final java.util.List<Tree.Parameter> lambdaParams = fa.getParameterLists().get(0).getParameters();
final java.util.List<Tree.Parameter> defParams = def.getParameterLists().get(0).getParameters();
List<Substitution> substitutions = List.nil();
for (int ii = 0; ii < lambdaParams.size(); ii++) {
substitutions = substitutions.append(naming.addVariableSubst((TypedDeclaration) lambdaParams.get(ii).getParameterModel().getModel(), defParams.get(ii).getParameterModel().getName()));
}
bodyExpr = gen().expressionGen().transformExpression(fa.getExpression(), returnNull ? BoxingStrategy.INDIFFERENT : CodegenUtil.getBoxingStrategy(model), resultType);
for (Substitution subs : substitutions) {
subs.close();
}
} else if (!isLazy && typeFact().isCallableType(term.getTypeModel())) {
returnNull = isAnything(term.getTypeModel()) && term.getUnboxed();
Function method = methodDecl.getDeclarationModel();
boolean lazy = specifierExpression instanceof Tree.LazySpecifierExpression;
boolean inlined = CodegenUtil.canOptimiseMethodSpecifier(term, method);
Invocation invocation;
if ((lazy || inlined) && term instanceof Tree.MemberOrTypeExpression && ((Tree.MemberOrTypeExpression) term).getDeclaration() instanceof Functional) {
Declaration primaryDeclaration = ((Tree.MemberOrTypeExpression) term).getDeclaration();
Reference producedReference = ((Tree.MemberOrTypeExpression) term).getTarget();
invocation = new MethodReferenceSpecifierInvocation(this, (Tree.MemberOrTypeExpression) term, primaryDeclaration, producedReference, method, specifierExpression);
} else if (!lazy && !inlined) {
// must be a callable we stored
String name = naming.getMethodSpecifierAttributeName(method);
invocation = new CallableSpecifierInvocation(this, method, naming.makeUnquotedIdent(name), term, term);
} else if (isCeylonCallableSubtype(term.getTypeModel())) {
invocation = new CallableSpecifierInvocation(this, method, expressionGen().transformExpression(term), term, term);
} else {
throw new BugException(term, "unhandled primary: " + term == null ? "null" : term.getNodeType());
}
invocation.handleBoxing(true);
invocation.setErased(CodegenUtil.hasTypeErased(term) || getReturnTypeOfCallable(term.getTypeModel()).isNothing());
bodyExpr = expressionGen().transformInvocation(invocation);
} else {
bodyExpr = expressionGen().transformExpression(model, term);
// The innermost of an MPL method declared void needs to return null
returnNull = Decl.isUnboxedVoid(model) && Decl.isMpl(model);
}
if (!Decl.isUnboxedVoid(model) || Decl.isMpl(model) || Strategy.useBoxedVoid(model)) {
if (returnNull) {
body = List.<JCStatement>of(make().Exec(bodyExpr), make().Return(makeNull()));
} else {
body = List.<JCStatement>of(make().Return(bodyExpr));
}
} else {
body = List.<JCStatement>of(make().Exec(bodyExpr));
}
return body;
}
Aggregations