Code review comment: Do we need to create a new type every time? Don't we have the previously created type already in the `foundSym`? I think we can move the lookup logic to the top of the method.

Code under review:
private BType defineSymbolsForCyclicTypeDefinitions(BLangTypeDefinition typeDef, SymbolEnv env) {
        Name newTypeDefName = names.fromIdNode(typeDef.name);
        BTypeSymbol typeDefSymbol;
        BType newTypeNode;

        switch (typeDef.typeNode.getKind()) {
            case TUPLE_TYPE_NODE:
                newTypeNode = new BTupleType(null, new ArrayList<>());
                typeDefSymbol = Symbols.createTypeSymbol(SymTag.TUPLE_TYPE, Flags.asMask(typeDef.flagSet),
                        newTypeDefName, env.enclPkg.symbol.pkgID, newTypeNode, env.scope.owner,
                        typeDef.name.pos, SOURCE);
                break;
            default:
                newTypeNode = BUnionType.create(null, new LinkedHashSet<>());
                typeDefSymbol = Symbols.createTypeSymbol(SymTag.UNION_TYPE, Flags.asMask(typeDef.flagSet),
                        newTypeDefName, env.enclPkg.symbol.pkgID, newTypeNode, env.scope.owner,
                        typeDef.name.pos, SOURCE);
        }
        newTypeNode.isCyclic = true;
        BSymbol foundSym = symResolver.lookupSymbolInMainSpace(env, names.fromIdNode(typeDef.name));
        if (foundSym == symTable.notFoundSymbol) {
            typeDef.symbol = typeDefSymbol;
            defineTypeInMainScope(typeDefSymbol, typeDef);
            newTypeNode.tsymbol = typeDefSymbol;
            newTypeNode.flags |= typeDefSymbol.flags;
            return newTypeNode;
        }
        newTypeNode = foundSym.type;
        newTypeNode.tsymbol = (BTypeSymbol) foundSym;
        newTypeNode.flags |= foundSym.flags;
        return newTypeNode;
    }

Line commented on: newTypeNode = BUnionType.create(null, new LinkedHashSet<>());

Revised code:
private BType defineSymbolsForCyclicTypeDefinitions(BLangTypeDefinition typeDef, SymbolEnv env) {
        Name newTypeDefName = names.fromIdNode(typeDef.name);
        BTypeSymbol typeDefSymbol;
        BType newTypeNode;

        BSymbol foundSym = symResolver.lookupSymbolInMainSpace(env, names.fromIdNode(typeDef.name));
        if (foundSym != symTable.notFoundSymbol) {
            newTypeNode = foundSym.type;
            return newTypeNode;
        }
        switch (typeDef.typeNode.getKind()) {
            case TUPLE_TYPE_NODE:
                newTypeNode = new BTupleType(null, new ArrayList<>(), true);
                typeDefSymbol = Symbols.createTypeSymbol(SymTag.TUPLE_TYPE, Flags.asMask(typeDef.flagSet),
                        newTypeDefName, env.enclPkg.symbol.pkgID, newTypeNode, env.scope.owner,
                        typeDef.name.pos, SOURCE);
                break;
            default:
                newTypeNode = BUnionType.create(null, new LinkedHashSet<>(), true);
                typeDefSymbol = Symbols.createTypeSymbol(SymTag.UNION_TYPE, Flags.asMask(typeDef.flagSet),
                        newTypeDefName, env.enclPkg.symbol.pkgID, newTypeNode, env.scope.owner,
                        typeDef.name.pos, SOURCE);
        }
        typeDef.symbol = typeDefSymbol;
        defineTypeInMainScope(typeDefSymbol, typeDef, env);
        newTypeNode.tsymbol = typeDefSymbol;
        newTypeNode.flags |= typeDefSymbol.flags;
        return newTypeNode;
    }