Search in sources :

Example 66 with ClassOrInterface

use of org.eclipse.ceylon.model.typechecker.model.ClassOrInterface in project ceylon by eclipse.

the class Singletons method defineObject.

/**
 * Generate an object definition, that is, define an anonymous class and then a function
 * to return a single instance of it.
 * @param that The node with the definition (can be ObjectDefinition, ObjectExpression, ObjectArgument)
 * @param d The Value declaration for the object
 * @param sats The list of satisfied types of the anonymous class
 * @param superType The supertype of the anonymous class
 * @param superCall The invocation of the supertype (object bla extends Foo(x))
 * @param body The object definition's body
 * @param annots The annotations (in case of ObjectDefinition)
 * @param gen The main visitor/generator.
 */
static void defineObject(final Node that, final Value d, final List<Type> sats, final Tree.SimpleType superType, final Tree.InvocationExpression superCall, final Tree.Body body, final Tree.AnnotationList annots, final GenerateJsVisitor gen, InitDeferrer initDeferrer) {
    final boolean addToPrototype = gen.opts.isOptimize() && d != null && d.isClassOrInterfaceMember();
    final boolean isObjExpr = that instanceof Tree.ObjectExpression;
    final TypeDeclaration _td = isObjExpr ? ((Tree.ObjectExpression) that).getAnonymousClass() : d.getTypeDeclaration();
    final Class c = (Class) (_td instanceof Constructor ? _td.getContainer() : _td);
    final String className = gen.getNames().name(c);
    final String objectName = gen.getNames().name(d);
    final String selfName = gen.getNames().self(c);
    final Value natd = d == null ? null : (Value) ModelUtil.getNativeDeclaration(d, Backend.JavaScript);
    if (that instanceof Tree.Declaration) {
        if (NativeUtil.isNativeHeader((Tree.Declaration) that) && natd != null) {
            // It's a native header, remember it for later when we deal with its implementation
            gen.saveNativeHeader((Tree.Declaration) that);
            return;
        }
        if (!(NativeUtil.isForBackend((Tree.Declaration) that, Backend.JavaScript) || NativeUtil.isHeaderWithoutBackend((Tree.Declaration) that, Backend.JavaScript))) {
            return;
        }
    }
    final List<Tree.Statement> stmts;
    if (d != null && NativeUtil.isForBackend(d, Backend.JavaScript)) {
        Tree.Declaration nh = gen.getNativeHeader(d);
        if (nh == null && NativeUtil.hasNativeMembers(c) && that instanceof Tree.Declaration) {
            nh = (Tree.Declaration) that;
        }
        stmts = NativeUtil.mergeStatements(body, nh, Backend.JavaScript);
    } else {
        stmts = body.getStatements();
    }
    Map<TypeParameter, Type> targs = new HashMap<>();
    if (sats != null) {
        for (Type st : sats) {
            Map<TypeParameter, Type> stargs = st.getTypeArguments();
            if (stargs != null && !stargs.isEmpty()) {
                targs.putAll(stargs);
            }
        }
    }
    gen.out(GenerateJsVisitor.function, className, targs.isEmpty() ? "()" : "($$targs$$)");
    gen.beginBlock();
    if (isObjExpr) {
        gen.out("var ", selfName, "=new ", className, ".$$;");
        final ClassOrInterface coi = ModelUtil.getContainingClassOrInterface(c.getContainer());
        if (coi != null) {
            gen.out(selfName, ".outer$=", gen.getNames().self(coi));
            gen.endLine(true);
        }
    } else {
        if (c.isMember() && !d.isStatic()) {
            gen.initSelf(that);
        }
        gen.instantiateSelf(c);
        gen.referenceOuter(c);
    }
    // TODO should we generate all this code for native headers?
    // Really we should merge the body of the header with that of the impl
    // It's the only way to make this shit work in lexical scope mode
    final List<Declaration> superDecs = new ArrayList<>();
    if (!gen.opts.isOptimize()) {
        final SuperVisitor superv = new SuperVisitor(superDecs);
        for (Tree.Statement st : stmts) {
            st.visit(superv);
        }
    }
    if (!targs.isEmpty()) {
        gen.out(selfName, ".$$targs$$=$$targs$$");
        gen.endLine(true);
    }
    TypeGenerator.callSupertypes(sats, superType, c, that, superDecs, superCall, superType == null ? null : ((Class) c.getExtendedType().getDeclaration()).getParameterList(), gen);
    gen.visitStatements(stmts);
    gen.out("return ", selfName, ";");
    gen.endBlock();
    gen.out(";", className, ".$crtmm$=");
    TypeUtils.encodeForRuntime(that, c, gen);
    gen.endLine(true);
    TypeGenerator.initializeType(that, gen, initDeferrer);
    final String objvar = (addToPrototype ? "this." : "") + gen.getNames().createTempVariable();
    if (d != null && !addToPrototype) {
        gen.out("var ", objvar);
        // If it's a property, create the object here
        if (AttributeGenerator.defineAsProperty(d)) {
            gen.out("=", className, "(");
            if (!targs.isEmpty()) {
                TypeUtils.printTypeArguments(that, targs, gen, false, null);
            }
            gen.out(")");
        }
        gen.endLine(true);
    }
    if (d != null && AttributeGenerator.defineAsProperty(d)) {
        gen.out(gen.getClAlias(), "atr$(");
        gen.outerSelf(d);
        gen.out(",'", objectName, "',function(){return ");
        if (addToPrototype) {
            gen.out("this.", gen.getNames().privateName(d));
        } else {
            gen.out(objvar);
        }
        gen.out(";},undefined,");
        TypeUtils.encodeForRuntime(that, d, annots, gen);
        gen.out(")");
        gen.endLine(true);
    } else if (d != null) {
        final String objectGetterName = gen.getNames().getter(d, false);
        gen.out(GenerateJsVisitor.function, objectGetterName, "()");
        gen.beginBlock();
        // Create the object lazily
        final String oname = gen.getNames().objectName(c);
        gen.out("if(", objvar, "===", gen.getClAlias(), "INIT$)");
        gen.generateThrow(gen.getClAlias() + "InitializationError", "Cyclic initialization trying to read the value of '" + d.getName() + "' before it was set", that);
        gen.endLine(true);
        gen.out("if(", objvar, "===undefined){", objvar, "=", gen.getClAlias(), "INIT$;", objvar, "=$init$", oname);
        if (!oname.endsWith("()")) {
            gen.out("()");
        }
        gen.out("(");
        if (!targs.isEmpty()) {
            TypeUtils.printTypeArguments(that, targs, gen, false, null);
        }
        gen.out(");", objvar, ".$crtmm$=", objectGetterName, ".$crtmm$;}");
        gen.endLine();
        gen.out("return ", objvar, ";");
        gen.endBlockNewLine();
        if (addToPrototype || d.isShared()) {
            gen.outerSelf(d);
            gen.out(".", objectGetterName, "=", objectGetterName);
            gen.endLine(true);
        }
        if (!d.isToplevel()) {
            if (gen.outerSelf(d))
                gen.out(".");
        }
        gen.out(objectGetterName, ".$crtmm$=");
        TypeUtils.encodeForRuntime(that, d, annots, gen);
        gen.endLine(true);
        gen.out(gen.getNames().getter(c, true), "=", objectGetterName);
        gen.endLine(true);
        if (d.isToplevel()) {
            final String objectGetterNameMM = gen.getNames().getter(d, true);
            gen.out("ex$.", objectGetterNameMM, "=", objectGetterNameMM);
            gen.endLine(true);
        }
    } else if (isObjExpr) {
        gen.out("return ", className, "();");
    }
}
Also used : ClassOrInterface(org.eclipse.ceylon.model.typechecker.model.ClassOrInterface) TypeParameter(org.eclipse.ceylon.model.typechecker.model.TypeParameter) SuperVisitor(org.eclipse.ceylon.compiler.js.GenerateJsVisitor.SuperVisitor) HashMap(java.util.HashMap) Constructor(org.eclipse.ceylon.model.typechecker.model.Constructor) ArrayList(java.util.ArrayList) Type(org.eclipse.ceylon.model.typechecker.model.Type) Value(org.eclipse.ceylon.model.typechecker.model.Value) Tree(org.eclipse.ceylon.compiler.typechecker.tree.Tree) Class(org.eclipse.ceylon.model.typechecker.model.Class) TypeDeclaration(org.eclipse.ceylon.model.typechecker.model.TypeDeclaration) Declaration(org.eclipse.ceylon.model.typechecker.model.Declaration) TypeDeclaration(org.eclipse.ceylon.model.typechecker.model.TypeDeclaration)

Example 67 with ClassOrInterface

use of org.eclipse.ceylon.model.typechecker.model.ClassOrInterface in project ceylon by eclipse.

the class TypeGenerator method initializeType.

/**
 * Generates a function to initialize the specified type.
 * @param initDeferrer
 */
static void initializeType(final Node type, final GenerateJsVisitor gen, InitDeferrer initDeferrer) {
    Tree.ExtendedType extendedType = null;
    Tree.SatisfiedTypes satisfiedTypes = null;
    final ClassOrInterface decl;
    final List<Tree.Statement> stmts;
    Value objDecl = null;
    if (type instanceof Tree.ClassDefinition) {
        Tree.ClassDefinition classDef = (Tree.ClassDefinition) type;
        extendedType = classDef.getExtendedType();
        satisfiedTypes = classDef.getSatisfiedTypes();
        decl = classDef.getDeclarationModel();
        Tree.Declaration nh = gen.getNativeHeader(decl);
        if (nh == null && NativeUtil.hasNativeMembers(decl)) {
            nh = classDef;
        }
        stmts = NativeUtil.mergeStatements(classDef.getClassBody(), nh, Backend.JavaScript);
    } else if (type instanceof Tree.InterfaceDefinition) {
        satisfiedTypes = ((Tree.InterfaceDefinition) type).getSatisfiedTypes();
        decl = ((Tree.InterfaceDefinition) type).getDeclarationModel();
        final Tree.InterfaceDefinition idef = (Tree.InterfaceDefinition) type;
        Tree.Declaration nh = gen.getNativeHeader(decl);
        if (nh == null && NativeUtil.hasNativeMembers(decl)) {
            nh = idef;
        }
        stmts = NativeUtil.mergeStatements(idef.getInterfaceBody(), nh, Backend.JavaScript);
    } else if (type instanceof Tree.ObjectDefinition) {
        Tree.ObjectDefinition objectDef = (Tree.ObjectDefinition) type;
        extendedType = objectDef.getExtendedType();
        satisfiedTypes = objectDef.getSatisfiedTypes();
        decl = (ClassOrInterface) objectDef.getDeclarationModel().getTypeDeclaration();
        objDecl = objectDef.getDeclarationModel();
        Tree.Declaration nh = gen.getNativeHeader(decl);
        if (nh == null && NativeUtil.hasNativeMembers(decl)) {
            nh = objectDef;
        }
        stmts = NativeUtil.mergeStatements(objectDef.getClassBody(), nh, Backend.JavaScript);
    } else if (type instanceof Tree.ObjectExpression) {
        Tree.ObjectExpression objectDef = (Tree.ObjectExpression) type;
        extendedType = objectDef.getExtendedType();
        satisfiedTypes = objectDef.getSatisfiedTypes();
        decl = (ClassOrInterface) objectDef.getAnonymousClass();
        stmts = objectDef.getClassBody().getStatements();
    } else if (type instanceof Tree.Enumerated) {
        Tree.Enumerated vc = (Tree.Enumerated) type;
        stmts = vc.getBlock().getStatements();
        decl = (ClassOrInterface) vc.getDeclarationModel().getTypeDeclaration().getContainer();
    } else {
        stmts = null;
        decl = null;
    }
    final PrototypeInitCallback callback = new PrototypeInitCallback() {

        @Override
        public void addToPrototypeCallback() {
            if (decl != null) {
                gen.addToPrototype(type, decl, stmts);
            }
        }
    };
    typeInitialization(extendedType, satisfiedTypes, decl, callback, gen, objDecl, initDeferrer);
}
Also used : ClassOrInterface(org.eclipse.ceylon.model.typechecker.model.ClassOrInterface) Value(org.eclipse.ceylon.model.typechecker.model.Value) Tree(org.eclipse.ceylon.compiler.typechecker.tree.Tree) TypedDeclaration(org.eclipse.ceylon.model.typechecker.model.TypedDeclaration) TypeDeclaration(org.eclipse.ceylon.model.typechecker.model.TypeDeclaration) Declaration(org.eclipse.ceylon.model.typechecker.model.Declaration) PrototypeInitCallback(org.eclipse.ceylon.compiler.js.GenerateJsVisitor.PrototypeInitCallback)

Example 68 with ClassOrInterface

use of org.eclipse.ceylon.model.typechecker.model.ClassOrInterface in project ceylon by eclipse.

the class TypeGenerator method typeInitialization.

/**
 * This is now the main method to generate the type initialization code.
 * @param extendedType The type that is being extended.
 * @param satisfiedTypes The types satisfied by the type being initialized.
 * @param d The declaration for the type being initialized
 * @param callback A callback to add something more to the type initializer in prototype style.
 * @param initDeferrer something which lets us put statements at the end of the container initialiser, if it's not null (it's null for toplevels)
 */
static void typeInitialization(final Tree.ExtendedType extendedType, final Tree.SatisfiedTypes satisfiedTypes, final ClassOrInterface d, PrototypeInitCallback callback, final GenerateJsVisitor gen, final Value objectDeclaration, InitDeferrer initDeferrer) {
    final boolean isInterface = d instanceof org.eclipse.ceylon.model.typechecker.model.Interface;
    String initFuncName = isInterface ? "initTypeProtoI" : "initTypeProto";
    final String typename = gen.getNames().name(d);
    final String initname;
    if (d.isAnonymous()) {
        String _initname = gen.getNames().objectName(d);
        if (d.isToplevel()) {
            initname = "$init$" + _initname.substring(0, _initname.length() - 2);
        } else {
            initname = "$init$" + _initname;
        }
    } else {
        initname = "$init$" + typename;
    }
    gen.out("function ", initname, "()");
    gen.beginBlock();
    gen.out("if(", typename, ".$$===undefined)");
    gen.beginBlock();
    boolean genIniter = true;
    if (TypeUtils.isNativeExternal(d)) {
        // Allow native types to have their own initialization code
        genIniter = !gen.stitchInitializer(d);
    }
    if (genIniter) {
        gen.out(gen.getClAlias(), initFuncName, "(", typename, ",'", d.getQualifiedNameString(), "'");
        final List<Tree.StaticType> supers = satisfiedTypes == null ? Collections.<Tree.StaticType>emptyList() : new ArrayList<Tree.StaticType>(satisfiedTypes.getTypes().size() + 1);
        if (extendedType != null) {
            if (satisfiedTypes == null) {
                String fname = typeFunctionName(extendedType.getType(), d, gen);
                gen.out(",", fname);
            } else {
                supers.add(extendedType.getType());
            }
        } else if (!isInterface) {
            gen.out(",", gen.getClAlias(), "Basic");
        }
        if (satisfiedTypes != null) {
            supers.addAll(satisfiedTypes.getTypes());
            Collections.sort(supers, new StaticTypeComparator());
            for (Tree.StaticType satType : supers) {
                String fname = typeFunctionName(satType, d, gen);
                gen.out(",", fname);
            }
        }
        gen.out(");");
    }
    // Add ref to outer type
    if (d.isMember()) {
        StringBuilder containers = new StringBuilder();
        Scope _d2 = d;
        while (_d2 instanceof ClassOrInterface) {
            if (containers.length() > 0) {
                containers.insert(0, '.');
            }
            containers.insert(0, gen.getNames().name((Declaration) _d2));
            _d2 = _d2.getContainer();
        }
        gen.endLine();
        gen.out(containers.toString(), "=", typename, ";");
    }
    // The class definition needs to be inside the init function if we want forwards decls to work in prototype style
    if (gen.opts.isOptimize()) {
        gen.endLine();
        callback.addToPrototypeCallback();
    }
    gen.endBlockNewLine();
    gen.out("return ", typename, ";");
    gen.endBlockNewLine();
    // If it's nested, share the init function
    if (d.isStatic()) {
        gen.out(gen.getNames().name(ModelUtil.getContainingClassOrInterface(d.getContainer())), ".$st$.", initname, "=", initname, ";");
    } else if (gen.outerSelf(d)) {
        gen.out(".", initname, "=", initname, ";");
    }
    if (initDeferrer != null) {
        initDeferrer.deferred.add(initname + "();");
    } else {
        gen.out(initname, "();");
    }
}
Also used : ClassOrInterface(org.eclipse.ceylon.model.typechecker.model.ClassOrInterface) Scope(org.eclipse.ceylon.model.typechecker.model.Scope) StaticType(org.eclipse.ceylon.compiler.typechecker.tree.Tree.StaticType) Tree(org.eclipse.ceylon.compiler.typechecker.tree.Tree) StaticType(org.eclipse.ceylon.compiler.typechecker.tree.Tree.StaticType) TypedDeclaration(org.eclipse.ceylon.model.typechecker.model.TypedDeclaration) TypeDeclaration(org.eclipse.ceylon.model.typechecker.model.TypeDeclaration) Declaration(org.eclipse.ceylon.model.typechecker.model.Declaration) Interface(org.eclipse.ceylon.model.typechecker.model.Interface) ClassOrInterface(org.eclipse.ceylon.model.typechecker.model.ClassOrInterface)

Example 69 with ClassOrInterface

use of org.eclipse.ceylon.model.typechecker.model.ClassOrInterface in project ceylon by eclipse.

the class TypeGenerator method typeFunctionName.

/**
 * Returns the name of the type or its $init$ function if it's local.
 */
static String typeFunctionName(final Tree.StaticType type, final ClassOrInterface coi, final GenerateJsVisitor gen) {
    TypeDeclaration d = type.getTypeModel().getDeclaration();
    final boolean removeAlias = d == null || !d.isClassOrInterfaceMember() || d instanceof Interface;
    if ((removeAlias && d.isAlias()) || d instanceof Constructor) {
        Type extendedType = d.getExtendedType();
        d = extendedType == null ? null : extendedType.getDeclaration();
    }
    Declaration cont = ModelUtil.getContainingDeclaration(d);
    final boolean inProto = gen.opts.isOptimize() && cont instanceof TypeDeclaration;
    final boolean imported = gen.isImported(type.getUnit().getPackage(), d);
    String dname = gen.getNames().name(d);
    if (d.isAlias()) {
        TypeDeclaration d2 = d;
        while (d2.isAlias()) {
            d2 = d2.getExtendedType().getDeclaration();
        }
        dname = gen.getNames().name(d2);
    }
    final String initName = "$init$" + dname + "()";
    if (!imported && !d.isClassOrInterfaceMember()) {
        return initName;
    }
    if (inProto && coi.isMember() && !d.isAlias() && (coi.getContainer() == cont || ModelUtil.contains(d, coi))) {
        // use its $init$ function
        return initName;
    }
    String tfn;
    // #628 If coi is anonymous and inside cont, qualify the path from cont instead
    if (coi != null && coi.isAnonymous() && cont instanceof Scope && ModelUtil.contains((Scope) cont, coi)) {
        tfn = gen.qualifiedPath(type, cont, inProto);
    } else if (inProto && d.isClassOrInterfaceMember()) {
        return pathToType(type, d, gen);
    } else {
        tfn = gen.qualifiedPath(type, d, inProto);
    }
    tfn = gen.memberAccessBase(type, d, false, tfn);
    if (removeAlias && !imported) {
        int idx = tfn.lastIndexOf('.');
        if (idx > 0) {
            tfn = tfn.substring(0, idx + 1) + initName;
        } else {
            tfn = initName;
        }
    }
    return tfn;
}
Also used : Type(org.eclipse.ceylon.model.typechecker.model.Type) StaticType(org.eclipse.ceylon.compiler.typechecker.tree.Tree.StaticType) Scope(org.eclipse.ceylon.model.typechecker.model.Scope) Constructor(org.eclipse.ceylon.model.typechecker.model.Constructor) TypedDeclaration(org.eclipse.ceylon.model.typechecker.model.TypedDeclaration) TypeDeclaration(org.eclipse.ceylon.model.typechecker.model.TypeDeclaration) Declaration(org.eclipse.ceylon.model.typechecker.model.Declaration) TypeDeclaration(org.eclipse.ceylon.model.typechecker.model.TypeDeclaration) Interface(org.eclipse.ceylon.model.typechecker.model.Interface) ClassOrInterface(org.eclipse.ceylon.model.typechecker.model.ClassOrInterface)

Example 70 with ClassOrInterface

use of org.eclipse.ceylon.model.typechecker.model.ClassOrInterface in project ceylon by eclipse.

the class JsonPackage method getTypeFromJson.

/**
 * Looks up a type from model data, creating it if necessary. The returned type will have its
 * type parameters substituted if needed.
 */
private Type getTypeFromJson(Map<String, Object> m, Declaration container, List<TypeParameter> typeParams) {
    TypeDeclaration td = null;
    if (m.get(KEY_METATYPE) instanceof TypeDeclaration) {
        td = (TypeDeclaration) m.get(KEY_METATYPE);
        if (td instanceof ClassOrInterface && td.getUnit().getPackage() instanceof JsonPackage) {
            ((JsonPackage) td.getUnit().getPackage()).load(td.getName(), typeParams);
        }
    }
    final String tname = (String) m.get(KEY_NAME);
    if ("$U".equals(tname)) {
        m.put(KEY_METATYPE, unknown);
        return unknown.getType();
    }
    if (td == null && m.containsKey("comp")) {
        @SuppressWarnings("unchecked") final List<Map<String, Object>> tmaps = (List<Map<String, Object>>) m.get(KEY_TYPES);
        final ArrayList<Type> types = new ArrayList<>(tmaps.size());
        if ("u".equals(m.get("comp"))) {
            UnionType ut = new UnionType(u2);
            for (Map<String, Object> tmap : tmaps) {
                types.add(getTypeFromJson(tmap, container, typeParams));
            }
            ut.setCaseTypes(types);
            td = ut;
        } else if ("i".equals(m.get("comp"))) {
            IntersectionType it = new IntersectionType(u2);
            for (Map<String, Object> tmap : tmaps) {
                types.add(getTypeFromJson(tmap, container, typeParams));
            }
            it.setSatisfiedTypes(types);
            td = it;
        } else {
            throw new IllegalArgumentException("Invalid composite type '" + m.get("comp") + "'");
        }
    } else if (td == null) {
        final String pname = (String) m.get(KEY_PACKAGE);
        if (pname == null) {
            // It's a ref to a type parameter
            final List<TypeParameter> containerTypeParameters;
            if (container instanceof Constructor) {
                containerTypeParameters = ((Generic) container.getContainer()).getTypeParameters();
            } else if (container instanceof Generic) {
                containerTypeParameters = container.getTypeParameters();
            } else {
                containerTypeParameters = null;
            }
            if (containerTypeParameters != null) {
                for (TypeParameter typeParam : containerTypeParameters) {
                    if (typeParam.getName().equals(tname)) {
                        td = typeParam;
                    }
                }
            }
            if (td == null && typeParams != null) {
                for (TypeParameter typeParam : typeParams) {
                    if (typeParam.getName().equals(tname)) {
                        td = typeParam;
                    }
                }
            }
        } else {
            String mname = (String) m.get(KEY_MODULE);
            if ("$".equals(mname)) {
                mname = LANGUAGE_MODULE_NAME;
            }
            org.eclipse.ceylon.model.typechecker.model.Package rp;
            if ("$".equals(pname) || LANGUAGE_MODULE_NAME.equals(pname)) {
                // Language module package
                rp = isLanguagePackage() ? this : getModule().getLanguageModule().getDirectPackage(LANGUAGE_MODULE_NAME);
            } else if (mname == null) {
                // local type
                if (".".equals(pname)) {
                    rp = this;
                    if (container instanceof TypeDeclaration && tname.equals(container.getName())) {
                        td = (TypeDeclaration) container;
                    }
                } else {
                    rp = getModule().getDirectPackage(pname);
                }
            } else {
                rp = getModule().getPackage(pname);
            }
            if (rp == null) {
                throw new CompilerErrorException("Package not found: " + pname);
            }
            if (rp != this && rp instanceof JsonPackage && !((JsonPackage) rp).loaded) {
                ((JsonPackage) rp).loadIfNecessary();
            }
            final boolean nested = tname.indexOf('.') > 0;
            final String level1 = nested ? tname.substring(0, tname.indexOf('.')) : tname;
            if (rp != null && !nested) {
                Declaration d = rp.getDirectMember(tname, null, false);
                if (d instanceof TypeDeclaration) {
                    td = (TypeDeclaration) d;
                    if (td.isTuple()) {
                        if (m.containsKey(KEY_TYPES)) {
                            @SuppressWarnings("unchecked") List<Map<String, Object>> elemaps = (List<Map<String, Object>>) m.get(KEY_TYPES);
                            ArrayList<Type> elems = new ArrayList<>(elemaps.size());
                            for (Map<String, Object> elem : elemaps) {
                                elems.add(getTypeFromJson(elem, container, typeParams));
                            }
                            Type tail = elems.get(elems.size() - 1);
                            if ((tail.isSequence() || tail.isSequential()) && !tail.isTuple() && !tail.isEmpty()) {
                                elems.remove(elems.size() - 1);
                            } else {
                                tail = null;
                            }
                            return u2.getTupleType(elems, tail, -1);
                        } else if (m.containsKey("count")) {
                            @SuppressWarnings("unchecked") Map<String, Object> elem = (Map<String, Object>) m.get(KEY_TYPE);
                            Type[] elems = new Type[(int) m.remove("count")];
                            Arrays.fill(elems, getTypeFromJson(elem, container, typeParams));
                            return u2.getTupleType(Arrays.asList(elems), null, -1);
                        }
                    }
                } else if (d instanceof FunctionOrValue) {
                    td = ((FunctionOrValue) d).getTypeDeclaration();
                }
            }
            if (td == null && rp instanceof JsonPackage) {
                if (nested) {
                    td = ((JsonPackage) rp).loadNestedType(tname, typeParams);
                } else {
                    td = (TypeDeclaration) ((JsonPackage) rp).load(tname, typeParams);
                }
            }
            // Then look in the top-level declarations
            if (nested && td == null) {
                for (Declaration d : rp.getMembers()) {
                    if (d instanceof TypeDeclaration && level1.equals(d.getName())) {
                        td = (TypeDeclaration) d;
                    }
                }
                final String[] path = tname.split("\\.");
                for (int i = 1; i < path.length; i++) {
                    td = (TypeDeclaration) td.getDirectMember(path[i], null, false);
                }
            }
        }
    }
    // From 1.2.3 we stored type arguments in maps
    final Type newType = loadTypeArguments(m, td, container, typeParams);
    if (newType != null) {
        return newType;
    }
    // This is the old pre 1.2.3 stuff
    @SuppressWarnings("unchecked") final List<Map<String, Object>> modelParms = (List<Map<String, Object>>) m.get(KEY_TYPE_PARAMS);
    if (td != null && modelParms != null) {
        // Substitute type parameters
        final HashMap<TypeParameter, Type> concretes = new HashMap<>();
        HashMap<TypeParameter, SiteVariance> variances = null;
        if (td.getTypeParameters().size() < modelParms.size()) {
            if (td.getUnit().getPackage() == this) {
                parseTypeParameters(modelParms, td, null);
            }
        }
        final Iterator<TypeParameter> viter = td.getTypeParameters().iterator();
        for (Map<String, Object> ptparm : modelParms) {
            TypeParameter _cparm = viter.next();
            if (ptparm.containsKey(KEY_PACKAGE) || ptparm.containsKey(KEY_TYPES)) {
                // Substitute for proper type
                final Type _pt = getTypeFromJson(ptparm, container, typeParams);
                concretes.put(_cparm, _pt);
            } else if (ptparm.containsKey(KEY_NAME) && typeParams != null) {
                // Look for type parameter with same name
                for (TypeParameter typeParam : typeParams) {
                    if (typeParam.getName().equals(ptparm.get(KEY_NAME))) {
                        concretes.put(_cparm, typeParam.getType());
                    }
                }
            }
            Integer usv = (Integer) ptparm.get(KEY_US_VARIANCE);
            if (usv != null) {
                if (variances == null) {
                    variances = new HashMap<>();
                }
                variances.put(_cparm, SiteVariance.values()[usv]);
            }
        }
        if (!concretes.isEmpty()) {
            return td.getType().substitute(concretes, variances);
        }
    }
    if (td == null) {
        try {
            throw new IllegalArgumentException(String.format("Couldn't find type %s::%s for %s in %s<%s> (FROM pkg %s)", m.get(KEY_PACKAGE), m.get(KEY_NAME), m.get(KEY_MODULE), m, typeParams, getNameAsString()));
        } catch (IllegalArgumentException ex) {
            ex.printStackTrace();
        }
    }
    return td.getType();
}
Also used : ClassOrInterface(org.eclipse.ceylon.model.typechecker.model.ClassOrInterface) UnionType(org.eclipse.ceylon.model.typechecker.model.UnionType) TypeParameter(org.eclipse.ceylon.model.typechecker.model.TypeParameter) HashMap(java.util.HashMap) Generic(org.eclipse.ceylon.model.typechecker.model.Generic) ArrayList(java.util.ArrayList) List(java.util.List) ParameterList(org.eclipse.ceylon.model.typechecker.model.ParameterList) ArrayList(java.util.ArrayList) TypeDeclaration(org.eclipse.ceylon.model.typechecker.model.TypeDeclaration) Declaration(org.eclipse.ceylon.model.typechecker.model.Declaration) CompilerErrorException(org.eclipse.ceylon.compiler.js.CompilerErrorException) Constructor(org.eclipse.ceylon.model.typechecker.model.Constructor) IntersectionType(org.eclipse.ceylon.model.typechecker.model.IntersectionType) NothingType(org.eclipse.ceylon.model.typechecker.model.NothingType) UnionType(org.eclipse.ceylon.model.typechecker.model.UnionType) Type(org.eclipse.ceylon.model.typechecker.model.Type) UnknownType(org.eclipse.ceylon.model.typechecker.model.UnknownType) IntersectionType(org.eclipse.ceylon.model.typechecker.model.IntersectionType) SiteVariance(org.eclipse.ceylon.model.typechecker.model.SiteVariance) TypeDeclaration(org.eclipse.ceylon.model.typechecker.model.TypeDeclaration) Map(java.util.Map) HashMap(java.util.HashMap) FunctionOrValue(org.eclipse.ceylon.model.typechecker.model.FunctionOrValue)

Aggregations

ClassOrInterface (org.eclipse.ceylon.model.typechecker.model.ClassOrInterface)102 TypeDeclaration (org.eclipse.ceylon.model.typechecker.model.TypeDeclaration)62 Declaration (org.eclipse.ceylon.model.typechecker.model.Declaration)48 TypedDeclaration (org.eclipse.ceylon.model.typechecker.model.TypedDeclaration)46 Type (org.eclipse.ceylon.model.typechecker.model.Type)44 Tree (org.eclipse.ceylon.compiler.typechecker.tree.Tree)27 Class (org.eclipse.ceylon.model.typechecker.model.Class)24 Interface (org.eclipse.ceylon.model.typechecker.model.Interface)23 Scope (org.eclipse.ceylon.model.typechecker.model.Scope)23 TypeParameter (org.eclipse.ceylon.model.typechecker.model.TypeParameter)20 ModelUtil.getContainingClassOrInterface (org.eclipse.ceylon.model.typechecker.model.ModelUtil.getContainingClassOrInterface)19 Value (org.eclipse.ceylon.model.typechecker.model.Value)19 ModelUtil.appliedType (org.eclipse.ceylon.model.typechecker.model.ModelUtil.appliedType)18 ArrayList (java.util.ArrayList)17 FunctionOrValue (org.eclipse.ceylon.model.typechecker.model.FunctionOrValue)17 Constructor (org.eclipse.ceylon.model.typechecker.model.Constructor)16 Function (org.eclipse.ceylon.model.typechecker.model.Function)14 LazyInterface (org.eclipse.ceylon.model.loader.model.LazyInterface)13 JCExpression (org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCExpression)12 UnknownType (org.eclipse.ceylon.model.typechecker.model.UnknownType)12