Exemplo n.º 1
0
        private static DataType get_instance_base_type(DataType instance_type, DataType base_type, CodeNode node_reference)
        {
            // construct a new type reference for the base type with correctly linked type arguments
            DataType instance_base_type = null;

            if (base_type.data_type is ObjectTypeSymbol)
            {
                instance_base_type = new ObjectType((ObjectTypeSymbol)base_type.data_type);
            }
            else if (base_type.data_type is Struct)
            {
                instance_base_type = new StructValueType((Struct)base_type.data_type);
            }
            else
            {
                assert_not_reached();
            }
            foreach (DataType type_arg in base_type.get_type_arguments())
            {
                // resolve type argument specified in base type (possibly recursively for nested generic types)
                var _type_arg = type_arg.get_actual_type(instance_type, null, node_reference);
                instance_base_type.add_type_argument(_type_arg);
            }
            return(instance_base_type);
        }
Exemplo n.º 2
0
        /// <summary>
        /// Analyze and check code in the specified context.
        ///
        /// <param name="context">a code context</param>
        /// </summary>
        public void analyze(CodeContext context)
        {
            this.context = context;

            root_symbol = context.root;

            bool_type   = new BooleanType((Struct)root_symbol.scope.lookup("bool"));
            string_type = new ObjectType((Class)root_symbol.scope.lookup("string"));
            int_type    = new IntegerType((Struct)root_symbol.scope.lookup("int"));
            uint_type   = new IntegerType((Struct)root_symbol.scope.lookup("uint"));

            uchar_type   = new IntegerType((Struct)root_symbol.scope.lookup("uchar"));
            int8_type    = new IntegerType((Struct)root_symbol.scope.lookup("int8"));
            short_type   = new IntegerType((Struct)root_symbol.scope.lookup("short"));
            ushort_type  = new IntegerType((Struct)root_symbol.scope.lookup("ushort"));
            long_type    = new IntegerType((Struct)root_symbol.scope.lookup("long"));
            ulong_type   = new IntegerType((Struct)root_symbol.scope.lookup("ulong"));
            size_t_type  = new IntegerType((Struct)root_symbol.scope.lookup("size_t"));
            ssize_t_type = new IntegerType((Struct)root_symbol.scope.lookup("ssize_t"));
            double_type  = new FloatingType((Struct)root_symbol.scope.lookup("double"));
            va_list_type = new StructValueType((Struct)root_symbol.scope.lookup("va_list"));

            var unichar_struct = (Struct)root_symbol.scope.lookup("unichar");

            if (unichar_struct != null)
            {
                unichar_type = new IntegerType(unichar_struct);
            }

            var glib_ns = root_symbol.scope.lookup("GLib");

            object_type   = (Class)glib_ns.scope.lookup("Object");
            type_type     = new IntegerType((Struct)glib_ns.scope.lookup("Type"));
            gvalue_type   = new StructValueType((Struct)glib_ns.scope.lookup("Value"));
            gvariant_type = new ObjectType((Class)glib_ns.scope.lookup("Variant"));

            glist_type       = new ObjectType((Class)glib_ns.scope.lookup("List"));
            gslist_type      = new ObjectType((Class)glib_ns.scope.lookup("SList"));
            garray_type      = new ObjectType((Class)glib_ns.scope.lookup("Array"));
            gvaluearray_type = new ObjectType((Class)glib_ns.scope.lookup("ValueArray"));

            gerror_type = (Class)glib_ns.scope.lookup("Error");
            regex_type  = new ObjectType((Class)root_symbol.scope.lookup("GLib").scope.lookup("Regex"));

            gsource_type = (Class)glib_ns.scope.lookup("Source");

            current_symbol = root_symbol;
            context.root.check(context);
            context.accept(this);
        }
Exemplo n.º 3
0
        public override bool check(CodeContext context)
        {
            if (is_checked)
            {
                return(!error);
            }

            is_checked = true;

            if (member_name != null)
            {
                if (!member_name.check(context))
                {
                    error = true;
                    return(false);
                }
            }

            TypeSymbol type = null;

            if (type_reference == null)
            {
                if (member_name == null)
                {
                    error = true;
                    Report.error(source_reference, "Incomplete object creation expression");
                    return(false);
                }

                if (member_name.symbol_reference == null)
                {
                    error = true;
                    return(false);
                }

                var constructor_sym = member_name.symbol_reference;
                var type_sym        = member_name.symbol_reference;

                var type_args = member_name.get_type_arguments();

                if (constructor_sym is Method)
                {
                    type_sym = constructor_sym.parent_symbol;

                    var constructor = (Method)constructor_sym;
                    if (!(constructor_sym is CreationMethod))
                    {
                        error = true;
                        Report.error(source_reference, "`%s' is not a creation method".printf(constructor.get_full_name()));
                        return(false);
                    }

                    symbol_reference = constructor;

                    // inner expression can also be base access when chaining constructors
                    var ma = member_name.inner as MemberAccess;
                    if (ma != null)
                    {
                        type_args = ma.get_type_arguments();
                    }
                }

                if (type_sym is Class)
                {
                    type = (TypeSymbol)type_sym;
                    if (((Class)type).is_error_base)
                    {
                        type_reference = new ErrorType(null, null, source_reference);
                    }
                    else
                    {
                        type_reference = new ObjectType((Class)type);
                    }
                }
                else if (type_sym is Struct)
                {
                    type           = (TypeSymbol)type_sym;
                    type_reference = new StructValueType((Struct)type);
                }
                else if (type_sym is ErrorCode)
                {
                    type_reference   = new ErrorType((ErrorDomain)type_sym.parent_symbol, (ErrorCode)type_sym, source_reference);
                    symbol_reference = type_sym;
                }
                else
                {
                    error = true;
                    Report.error(source_reference, "`%s' is not a class, struct, or error code".printf(type_sym.get_full_name()));
                    return(false);
                }

                foreach (DataType type_arg in type_args)
                {
                    type_reference.add_type_argument(type_arg);
                }
            }
            else
            {
                type = type_reference.data_type;
            }

            value_type             = type_reference.copy();
            value_type.value_owned = true;

            bool may_throw = false;

            int given_num_type_args    = type_reference.get_type_arguments().Count;
            int expected_num_type_args = 0;

            if (type is Class)
            {
                var cl = (Class)type;

                expected_num_type_args = cl.get_type_parameters().Count;

                if (struct_creation)
                {
                    error = true;
                    Report.error(source_reference, "syntax error, use `new' to create new objects");
                    return(false);
                }

                if (cl.is_abstract)
                {
                    value_type = null;
                    error      = true;
                    Report.error(source_reference, "Can't create instance of abstract class `%s'".printf(cl.get_full_name()));
                    return(false);
                }

                if (symbol_reference == null)
                {
                    symbol_reference = cl.default_construction_method;

                    if (symbol_reference == null)
                    {
                        error = true;
                        Report.error(source_reference, "`%s' does not have a default constructor".printf(cl.get_full_name()));
                        return(false);
                    }

                    // track usage for flow analyzer
                    symbol_reference.used = true;
                    symbol_reference.version.check(source_reference);
                }

                if (symbol_reference != null &&
                    (symbol_reference.access == SymbolAccessibility.PRIVATE || symbol_reference.access == SymbolAccessibility.PROTECTED))
                {
                    bool in_target_type = false;
                    for (Symbol this_symbol = context.analyzer.current_symbol; this_symbol != null; this_symbol = this_symbol.parent_symbol)
                    {
                        if (this_symbol == cl)
                        {
                            in_target_type = true;
                            break;
                        }
                    }

                    if (!in_target_type)
                    {
                        error = true;
                        Report.error(source_reference, "Access to non-public constructor `%s' denied".printf(symbol_reference.get_full_name()));
                        return(false);
                    }
                }

                while (cl != null)
                {
                    // FIXME: use target values in the codegen
                    if (cl.get_attribute_string("CCode", "ref_sink_function") != null)
                    {
                        value_type.floating_reference = true;
                        break;
                    }

                    cl = cl.base_class;
                }
            }
            else if (type is Struct)
            {
                var st = (Struct)type;

                expected_num_type_args = st.get_type_parameters().Count;

                if (!struct_creation && !context.deprecated)
                {
                    Report.warning(source_reference, "deprecated syntax, don't use `new' to initialize structs");
                }

                if (symbol_reference == null)
                {
                    symbol_reference = st.default_construction_method;
                }

                if (st.is_simple_type() && symbol_reference == null && object_initializer.Count == 0)
                {
                    error = true;
                    Report.error(source_reference, "`%s' does not have a default constructor".printf(st.get_full_name()));
                    return(false);
                }
            }

            if (expected_num_type_args > given_num_type_args)
            {
                error = true;
                Report.error(source_reference, "too few type arguments");
                return(false);
            }
            else if (expected_num_type_args < given_num_type_args)
            {
                error = true;
                Report.error(source_reference, "too many type arguments");
                return(false);
            }

            if (symbol_reference == null && get_argument_list().Count != 0)
            {
                value_type = null;
                error      = true;
                Report.error(source_reference, "No arguments allowed when constructing type `%s'".printf(type.get_full_name()));
                return(false);
            }

            if (symbol_reference is Method)
            {
                var m = (Method)symbol_reference;

                if (is_yield_expression)
                {
                    if (!m.coroutine)
                    {
                        error = true;
                        Report.error(source_reference, "yield expression requires async method");
                    }
                    if (context.analyzer.current_method == null || !context.analyzer.current_method.coroutine)
                    {
                        error = true;
                        Report.error(source_reference, "yield expression not available outside async method");
                    }
                }

                // FIXME partial code duplication of MethodCall.check

                Expression last_arg = null;

                var args = get_argument_list();
                IEnumerator <Expression> arg_it = args.GetEnumerator();
                foreach (Parameter param in m.get_parameters())
                {
                    if (param.ellipsis)
                    {
                        break;
                    }

                    if (arg_it.MoveNext())
                    {
                        Expression arg = arg_it.Current;

                        /* store expected type for callback parameters */
                        arg.formal_target_type = param.variable_type;
                        arg.target_type        = arg.formal_target_type.get_actual_type(value_type, null, this);

                        last_arg = arg;
                    }
                }

                // printf arguments
                if (m.printf_format)
                {
                    StringLiteral format_literal = null;
                    if (last_arg != null)
                    {
                        // use last argument as format string
                        format_literal = StringLiteral.get_format_literal(last_arg);
                        if (format_literal == null && args.Count == m.get_parameters().Count - 1)
                        {
                            // insert "%s" to avoid issues with embedded %
                            format_literal             = new StringLiteral("\"%s\"");
                            format_literal.target_type = context.analyzer.string_type.copy();
                            argument_list.Insert(args.Count - 1, format_literal);

                            // recreate iterator and skip to right position
                            arg_it = argument_list.GetEnumerator();
                            foreach (Parameter param in m.get_parameters())
                            {
                                if (param.ellipsis)
                                {
                                    break;
                                }
                                arg_it.MoveNext();
                            }
                        }
                    }
                    if (format_literal != null)
                    {
                        string format = format_literal.eval();
                        if (!context.analyzer.check_print_format(format, arg_it, source_reference))
                        {
                            return(false);
                        }
                    }
                }

                foreach (Expression arg in args.ToList())
                {
                    arg.check(context);
                }

                context.analyzer.check_arguments(this, new MethodType(m), m.get_parameters(), args);

                foreach (DataType error_type in m.get_error_types())
                {
                    may_throw = true;

                    // ensure we can trace back which expression may throw errors of this type
                    var call_error_type = error_type.copy();
                    call_error_type.source_reference = source_reference;

                    add_error_type(call_error_type);
                }
            }
            else if (type_reference is ErrorType)
            {
                if (type_reference != null)
                {
                    type_reference.check(context);
                }

                if (member_name != null)
                {
                    member_name.check(context);
                }

                foreach (Expression arg in argument_list)
                {
                    arg.check(context);
                }

                foreach (MemberInitializer init in object_initializer)
                {
                    init.check(context);
                }

                if (get_argument_list().Count == 0)
                {
                    error = true;
                    Report.error(source_reference, "Too few arguments, errors need at least 1 argument");
                }
                else
                {
                    IEnumerator <Expression> arg_it = get_argument_list().GetEnumerator();
                    arg_it.MoveNext();
                    var ex = arg_it.Current;
                    if (ex.value_type == null || !ex.value_type.compatible(context.analyzer.string_type))
                    {
                        error = true;
                        Report.error(source_reference, "Invalid type for argument 1");
                    }

                    var format_literal = StringLiteral.get_format_literal(ex);
                    if (format_literal != null)
                    {
                        var format = format_literal.eval();
                        if (!context.analyzer.check_print_format(format, arg_it, source_reference))
                        {
                            error = true;
                            return(false);
                        }
                    }

                    arg_it = get_argument_list().GetEnumerator();
                    arg_it.MoveNext();
                    if (!context.analyzer.check_variadic_arguments(arg_it, 1, source_reference))
                    {
                        error = true;
                        return(false);
                    }
                }
            }

            foreach (MemberInitializer init in get_object_initializer())
            {
                context.analyzer.visit_member_initializer(init, type_reference);
            }

            if (may_throw)
            {
                if (parent_node is LocalVariable || parent_node is ExpressionStatement)
                {
                    // simple statements, no side effects after method call
                }
                else if (!(context.analyzer.current_symbol is Block))
                {
                    // can't handle errors in field initializers
                    Report.error(source_reference, "Field initializers must not throw errors");
                }
                else
                {
                    // store parent_node as we need to replace the expression in the old parent node later on
                    var old_parent_node = parent_node;

                    var local = new LocalVariable(value_type.copy(), get_temp_name(), null, source_reference);
                    var decl  = new DeclarationStatement(local, source_reference);

                    insert_statement(context.analyzer.insert_block, decl);

                    var temp_access = SemanticAnalyzer.create_temp_access(local, target_type);
                    // don't set initializer earlier as this changes parent_node and parent_statement
                    local.initializer = this;
                    decl.check(context);


                    // move temp variable to insert block to ensure the
                    // variable is in the same block as the declaration
                    // otherwise there will be scoping issues in the generated code
                    var block = (Block)context.analyzer.current_symbol;
                    block.remove_local_variable(local);
                    context.analyzer.insert_block.add_local_variable(local);

                    old_parent_node.replace_expression(this, temp_access);
                    temp_access.check(context);
                }
            }

            return(!error);
        }
Exemplo n.º 4
0
        public static DataType get_data_type_for_symbol(TypeSymbol sym)
        {
            DataType type = null;

            List <TypeParameter> type_parameters = null;

            if (sym is ObjectTypeSymbol)
            {
                type            = new ObjectType((ObjectTypeSymbol)sym);
                type_parameters = ((ObjectTypeSymbol)sym).get_type_parameters();
            }
            else if (sym is Struct)
            {
                var st = (Struct)sym;
                if (st.is_boolean_type())
                {
                    type = new BooleanType(st);
                }
                else if (st.is_integer_type())
                {
                    type = new IntegerType(st);
                }
                else if (st.is_floating_type())
                {
                    type = new FloatingType(st);
                }
                else
                {
                    type = new StructValueType(st);
                }
                type_parameters = st.get_type_parameters();
            }
            else if (sym is ValaEnum)
            {
                type = new EnumValueType((ValaEnum)sym);
            }
            else if (sym is ErrorDomain)
            {
                type = new ErrorType((ErrorDomain)sym, null);
            }
            else if (sym is ErrorCode)
            {
                type = new ErrorType((ErrorDomain)sym.parent_symbol, (ErrorCode)sym);
            }
            else
            {
                Report.error(null, "internal error: `%s' is not a supported type".printf(sym.get_full_name()));
                return(new InvalidType());
            }

            if (type_parameters != null)
            {
                foreach (var type_param in type_parameters)
                {
                    var type_arg = new GenericType(type_param);
                    type_arg.value_owned = true;
                    type.add_type_argument(type_arg);
                }
            }

            return(type);
        }