// Note that, within this function, the the conversion's type // is equivalent to the destination type. // // FIXME: Factor out the "conformance checking" code. Expr* admit_binary_conv(Context& cxt, Conversion_cons& c, Binary_expr& e) { // Determine if the operands can be converted to the // declared type of the required expressin. Binary_expr& a = cast<Binary_expr>(c.expression()); Type& t1 = declared_type(a.left()); Type& t2 = declared_type(a.right()); try { copy_initialize(cxt, t1, e.left()); copy_initialize(cxt, t2, e.right()); } catch(Translation_error&) { return nullptr; } // Adjust the type of the expression under test to that of // the required expression. // // FIXME: It's possible that we need to preserve the original // conversions in order to sort candidates. Consider: // // requires (T a, T const b) { // f(a) -> T; // #1 // f(b) -> T const; // #2 // } // // In an algorithm that uses a f(x) where x is const, we would // prefer #1. Perhaps we should collect viable conversion // and then sort at the end. Note that this is true for simple // typings also. // // FIXME: Add constructors to the builder. This is just plain dumb. return new Dependent_conv(c.type(), e); }
Expr* admit_call_expr(Context& cxt, Usage& c, Call_expr& e) { Call_expr& a = cast<Call_expr>(c.expression()); // Build the list of parameter types from the declared types // of operands in the constraint. Type_list ts {&declared_type(a.function())}; for (Expr& e0 : a.arguments()) ts.push_back(declared_type(e0)); // Build the list of arguments from e. Note that the first // argument is actually the function. Expr_list es {&e.function()}; for (Expr& e0 : e.arguments()) es.push_back(e0); // If conversion fails, this is not accessible. try { initialize_parameters(cxt, ts, es); } catch (Translation_error&) { return nullptr; } // Adjust the type and admit the expression. e.type_ = &a.type(); return &e; }
Type* specializeType_div(Term* term) { Type* left = declared_type(term->input(0)); Type* right = declared_type(term->input(1)); if ((left == TYPES.int_type || left == TYPES.float_type) && (right == TYPES.int_type || right == TYPES.float_type)) return TYPES.float_type; return TYPES.any; }
Type* output_placeholder_specializeType(Term* caller) { // Don't specialize if the type was explicitly declared if (caller->boolProp(s_ExplicitType, false)) return declared_type(caller); // Special case: if we're an accumulatingOutput then the output type is List. if (caller->boolProp(s_AccumulatingOutput, false)) return TYPES.list; if (caller->input(0) == NULL) return NULL; return declared_type(caller->input(0)); }
// Direct initialzie `d` by a brace-enclosed list of expressions // `es`. Expr& Parser::on_brace_initialization(Decl& d, Expr_list& es) { Expr& i = list_initialize(cxt, declared_type(d), es); initialize_declaration(d, i); return i; }
void branch_update_state_type(Branch* branch) { if (branch_state_type_is_out_of_date(branch)) { // TODO: Handle the case where the stateType should go from non-NULL to NULL // Recreate the state type Type* type = create_compound_type(); // TODO: give this new type a nice name for (int i=0; i < branch->length(); i++) { Term* term = branch->get(i); if (term == NULL) continue; if (term->function != FUNCS.unpack_state || FUNCS.unpack_state == NULL) continue; Term* identifyingTerm = term->input(1); compound_type_append_field(type, declared_type(term), unique_name(identifyingTerm)); } branch->stateType = type; // Might need to update any existing pack_state calls. branch_update_existing_pack_state_calls(branch); } }
void block_update_state_type(Block* block) { if (!block_state_type_is_out_of_date(block)) return; // Recreate the state type Type* type = create_compound_type(); // TODO: give this new type a nice name for (int i=0; i < block->length(); i++) { Term* term = block->get(i); if (term == NULL) continue; if (term->function != FUNCS.unpack_state || FUNCS.unpack_state == NULL) continue; Term* identifyingTerm = term->input(1); caValue* fieldName = get_unique_name(identifyingTerm); ca_assert(is_string(fieldName)); ca_assert(!string_eq(fieldName, "")); compound_type_append_field(type, declared_type(term), as_cstring(fieldName)); } block->stateType = type; block_remove_property(block, sym_DirtyStateType); // Might need to update any existing pack_state calls. block_update_pack_state_calls(block); }
ciType* Local::exact_type() const { ciType* type = declared_type(); // for primitive arrays, the declared type is the exact type if (type->is_type_array_klass()) { return type; } else if (type->is_instance_klass()) { ciInstanceKlass* ik = (ciInstanceKlass*)type; if (ik->is_loaded() && ik->is_final() && !ik->is_interface()) { return type; } } else if (type->is_obj_array_klass()) { ciObjArrayKlass* oak = (ciObjArrayKlass*)type; ciType* base = oak->base_element_type(); if (base->is_instance_klass()) { ciInstanceKlass* ik = base->as_instance_klass(); if (ik->is_loaded() && ik->is_final()) { return type; } } else if (base->is_primitive_type()) { return type; } } return NULL; }
// Copy initialize the declaration `d` with `e`. Expr& Parser::on_equal_initialization(Decl& d, Expr& e) { Expr& i = copy_initialize(cxt, declared_type(d), e); initialize_declaration(d, i); return i; }
// Select a default initializer for `d`. // // FIXME: This relies on the construction of placeholder nodes // in the initialization branch. That seems wrong. We should be // able to convey syntax via flags. Expr& Parser::on_default_initialization(Decl& d) { Type& t = declared_type(d); Expr& i = default_initialize(cxt, t); initialize_declaration(d, i); return i; }
void staticTypeQuery(Type* type, StaticTypeQuery* query) { Type* subjectType = declared_type(query->subject); if (subjectType->getIndex != NULL && subjectType->numElements != NULL) query->succeed(); else query->fail(); }
Block* statically_resolve_dynamic_method(Term* term) { ca_assert(term->function == FUNCS.dynamic_method); Value nameLocation; nameLocation.set_list(2); nameLocation.index(0)->set(term->getProp(s_method_name)); nameLocation.index(1)->set_term(term); return find_method_on_type(declared_type(term), &nameLocation); }
ciType* LoadField::exact_type() const { ciType* type = declared_type(); // for primitive arrays, the declared type is the exact type if (type->is_type_array_klass()) { return type; } if (type->is_instance_klass()) { ciInstanceKlass* ik = (ciInstanceKlass*)type; if (ik->is_loaded() && ik->is_final()) { return type; } } return NULL; }
// Allocate space for an object of type `t`. No value initialization // procedure is invoked. // // This currently works by prototyping an object of the approppriate // shape and storing that for the declaration. // // TODO: It would be better if we could just emplace the approiately // shaped object directly into the store. Value& Evaluator::alloca(Decl const& d) { struct fn { Value operator()(Type const& t) { banjo_unhandled_case(t); } Value operator()(Boolean_type const&) { return 0; } Value operator()(Integer_type const&) { return 0; } Value operator()(Float_type const&) { return 0.0; } Value operator()(Function_type const&) { return Function_value(nullptr); } Value operator()(Reference_type const&) { return Reference_value(nullptr); } }; return store(d, apply(declared_type(d), fn{})); }
Expr* admit_binary_expr(Context& cxt, Usage& c, Binary_expr& e) { // Determine if the operands can be converted to the // declared type of the required expressin. Binary_expr& a = cast<Binary_expr>(c.expression()); Type& t1 = declared_type(a.left()); Type& t2 = declared_type(a.right()); try { copy_initialize(cxt, t1, e.left()); copy_initialize(cxt, t2, e.right()); } catch(Translation_error&) { return nullptr; } // Adjust the type of the expression under test to that of // the required expression. // // FIXME: See the notes on admit_binary_conv. We may want // to preserve the conversions for the purpose of ordering. e.type_ = &a.type(); return &e; }
void hosted_get_index(caStack* stack) { caValue* list = circa_input(stack, 0); int index = circa_int_input(stack, 1); if (index < 0) { char indexStr[40]; sprintf(indexStr, "Negative index: %d", index); return circa_output_error(stack, indexStr); } else if (index >= list_length(list)) { char indexStr[40]; sprintf(indexStr, "Index out of range: %d", index); return circa_output_error(stack, indexStr); } caValue* result = get_index(list, index); copy(result, circa_output(stack, 0)); cast(circa_output(stack, 0), declared_type((Term*) circa_caller_term(stack))); }
Term* rebind_possible_accessor(Branch* branch, Term* accessor, Term* result) { // Check if this isn't a recognized accessor. if (!has_empty_name(accessor)) { // Just create a named copy of 'result'. return apply(branch, FUNCS.copy, TermList(result), accessor->nameSymbol); } TermList accessorChain; trace_accessor_chain(accessor, &accessorChain); Term* head = accessorChain[0]; // Create the selector Term* selector = write_selector_for_accessor_chain(branch, &accessorChain); Term* set = apply(branch, FUNCS.set_with_selector, TermList(head, selector, result), head->nameSymbol); change_declared_type(set, declared_type(head)); return set; }
bool branch_state_type_is_out_of_date(Branch* branch) { // Alloc an array that tracks, for each field in the existing stateType, // whether we have found a corresponding term for that field. bool* typeFieldFound = NULL; int existingFieldCount = 0; if (branch->stateType != NULL) { existingFieldCount = compound_type_get_field_count(branch->stateType); size_t size = sizeof(bool) * existingFieldCount; typeFieldFound = (bool*) malloc(size); memset(typeFieldFound, 0, size); } // Walk through every term and check whether every unpack_state call is already // mentioned in the state type. for (int i=0; i < branch->length(); i++) { Term* term = branch->get(i); if (term == NULL) continue; if (term->function != FUNCS.unpack_state) continue; // Found an unpack_state call Term* identifyingTerm = term->input(1); // If the branch doesn't yet have a stateType then that's an update. if (branch->stateType == NULL) goto return_true; // Look for the field name int fieldIndex = list_find_field_index_by_name(branch->stateType, unique_name(identifyingTerm)); // If the name isn't found then that's an update if (fieldIndex == -1) goto return_true; // If the type doesn't match then that's an update if (compound_type_get_field_type(branch->stateType, fieldIndex) != declared_type(term)) goto return_true; // Record this field index as 'found' typeFieldFound[fieldIndex] = true; } // If there were any fields in the type that weren't found in the branch, then // that's an update. if (typeFieldFound != NULL) { for (int i=0; i < existingFieldCount; i++) { if (!typeFieldFound[i]) goto return_true; } } // No reason to update, return false. free(typeFieldFound); return false; return_true: free(typeFieldFound); return true; }
Synthetic_expr& Builder::synthesize_expression(Decl& d) { return make<Synthetic_expr>(declared_type(d), d); }
// Returns the declared type of an expression. In general, this is type of // the expression. However, for id-expressions, we actually use the declared // type of the referenced declaration. Type const& declared_type(Expr const& e) { return declared_type(modify(e)); }