/* * Copyright Red Hat Inc. and/or its affiliates and other contributors * as indicated by the authors tag. All rights reserved. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU General Public License version 2. * * This particular file is subject to the "Classpath" exception as provided in the * LICENSE file that accompanied this code. * * This program is distributed in the hope that it will be useful, but WITHOUT A * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public License for more details. * You should have received a copy of the GNU General Public License, * along with this distribution; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ package com.redhat.ceylon.compiler.java.loader; import java.util.Collections; import com.redhat.ceylon.compiler.java.tools.LanguageCompiler; import com.redhat.ceylon.compiler.typechecker.context.Context; import com.redhat.ceylon.model.typechecker.model.Class; import com.redhat.ceylon.model.typechecker.model.Declaration; import com.redhat.ceylon.model.typechecker.model.Interface; import com.redhat.ceylon.model.typechecker.model.Type; import com.redhat.ceylon.model.typechecker.model.TypeDeclaration; import com.redhat.ceylon.model.typechecker.model.TypedDeclaration; import com.redhat.ceylon.model.typechecker.model.Unit; import com.redhat.ceylon.model.typechecker.model.UnknownType; import com.redhat.ceylon.model.typechecker.model.ModelUtil; import com.sun.tools.javac.util.List; public class TypeFactory extends Unit { private Context context; public static TypeFactory instance(com.sun.tools.javac.util.Context context) { TypeFactory instance = context.get(TypeFactory.class); if (instance == null) { instance = new TypeFactory(LanguageCompiler.getCeylonContextInstance(context)); context.put(TypeFactory.class, instance); } return instance; } public TypeFactory(Context context) { this.context = context; } public Context getContext() { return context; } /** * Determines whether the given Type is a union * @param pt * @return whether the type is a union type */ public boolean isUnion(Type pt) { if (pt==null) return false; return pt.isUnion() && pt.getCaseTypes().size() > 1; } /** * Determines whether the given Type is an intersection * @param pt * @return whether the type is an intersection type */ public boolean isIntersection(Type pt) { if (pt==null) return false; return pt.isIntersection() && pt.getSatisfiedTypes().size() > 1; } public TypeDeclaration getArraySequenceDeclaration() { return (Class) getLanguageModuleDeclaration("ArraySequence"); } public Type getArraySequenceType(Type et) { return ModelUtil.appliedType(getArraySequenceDeclaration(), et); } /** * Returns a Type corresponding to {@code Array<T>} * @param et The Type corresponding to {@code T} * @return The Type corresponding to {@code Array<T>} */ public Type getArrayType(Type et) { return ModelUtil.appliedType(getArrayDeclaration(), et); } public Type getArrayElementType(Type type) { Type st = type.getSupertype(getArrayDeclaration()); if (st!=null && st.getTypeArguments().size()==1) { return st.getTypeArgumentList().get(0); } else { return null; } } public Type getCallableType(java.util.List<Type> typeArgs) { if (typeArgs.size()!=2) { throw new IllegalArgumentException("Callable type always has two arguments: " + typeArgs); } if (!typeArgs.get(1).isSubtypeOf( getSequentialDeclaration().appliedType( null, Collections.singletonList(getAnythingType())))) { throw new IllegalArgumentException("Callable's second argument should be sequential " + typeArgs.get(1)); } return getCallableDeclaration().appliedType(null, typeArgs); } public Type getCallableType(Type resultType) { return getCallableType(List.<Type>of(resultType,getEmptyType())); } public Type getUnknownType() { return new UnknownType(this).getType(); } public Type getIteratedAbsentType(Type type) { Type st = type.getSupertype(getIterableDeclaration()); if (st!=null && st.getTypeArguments().size()>1) { return st.getTypeArgumentList().get(1); } else { return null; } } public Declaration getBooleanTrueDeclaration() { return getLanguageModuleDeclaration("true"); } public Declaration getBooleanFalseDeclaration() { return getLanguageModuleDeclaration("false"); } public TypeDeclaration getBooleanTrueClassDeclaration() { Declaration trueDecl = getBooleanTrueDeclaration(); return trueDecl instanceof TypedDeclaration ? ((TypedDeclaration)trueDecl).getTypeDeclaration() : null; } public TypeDeclaration getBooleanFalseClassDeclaration() { Declaration trueDecl = getBooleanFalseDeclaration(); return trueDecl instanceof TypedDeclaration ? ((TypedDeclaration)trueDecl).getTypeDeclaration() : null; } public TypeDeclaration getMetamodelTypeDeclaration() { return (TypeDeclaration) getLanguageModuleModelDeclaration("Type"); } public TypedDeclaration getMetamodelNothingTypeDeclaration() { return (TypedDeclaration) getLanguageModuleModelDeclaration("nothingType"); } public TypeDeclaration getMetamodelDeclarationDeclaration() { return (TypeDeclaration) getLanguageModuleDeclarationDeclaration("Declaration"); } public TypeDeclaration getAssertionErrorDeclaration() { return (TypeDeclaration)getLanguageModuleDeclaration("AssertionError"); } public Type getReferenceType(Type value) { final Type serializedValueType; TypeDeclaration referenceTypeDecl = (TypeDeclaration)getLanguageModuleSerializationDeclaration("Reference"); serializedValueType = referenceTypeDecl.appliedType(null, Collections.singletonList(value)); return serializedValueType; } public Type getDeconstructorType() { return ((TypeDeclaration)getLanguageModuleSerializationDeclaration("Deconstructor")).getType(); } /** * Copy of Unit.isTupleLengthUnbounded which is more strict on what we consider variadic. For example * we do not consider Args|[] as a variadic tuple in a Callable. See https://github.com/ceylon/ceylon-compiler/issues/1908 */ public boolean isTupleOfVariadicCallable(Type args) { if (args!=null) { /*Boolean simpleTupleLengthUnbounded = isSimpleTupleLengthUnbounded(args); if (simpleTupleLengthUnbounded != null) { return simpleTupleLengthUnbounded.booleanValue(); }*/ if (isEmptyType(args)) { return false; } else if (isVariadicElement(args)) { return true; } Class td = getTupleDeclaration(); Type tuple = nonemptyArgs(args) .getSupertype(td); if (tuple==null) { return false; } else { while (true) { java.util.List<Type> tal = tuple.getTypeArgumentList(); if (tal.size()>=3) { Type rest = tal.get(2); if (rest==null) { return false; } else if (isEmptyType(rest)) { return false; } else if (isVariadicElement(rest)) { return true; } else { tuple = nonemptyArgs(rest) .getSupertype(td); if (tuple==null) { return false; } //else continue the loop! } } else { return false; } } } } return false; } private boolean isVariadicElement(Type args) { return args.isClassOrInterface() && (args.isSequential() || args.isSequence()); } /** * Get the interface for {@code java.io.Serializable} from * {@code java.base}, or null if it could not be found. * @return */ public Interface getJavaIoSerializable() { for (com.redhat.ceylon.model.typechecker.model.Module m : context.getModules().getListOfModules()) { if ("java.base".equals(m.getNameAsString())) { return (Interface)m.getPackage("java.io").getDirectMember("Serializable", null, false); } } return null; } public Type getJavaIoSerializableType() { Interface ser = getJavaIoSerializable(); if (ser != null) { return ser.getType(); } else { return null; } } }