Пример #1
0
// Reify the method with the type parameters from trait definition
// and type arguments from trait reference.
// Also handles modifying return types from behaviours, etc.
// Returns the reified type, which must be freed later, or NULL on error.
static ast_t* reify_provides_type(ast_t* method, ast_t* trait_ref,
  pass_opt_t* opt)
{
  assert(method != NULL);
  assert(trait_ref != NULL);

  // Apply the type args (if any) from the trait reference to the type
  // parameters from the trait definition.
  ast_t* trait_def = (ast_t*)ast_data(trait_ref);
  assert(trait_def != NULL);
  ast_t* type_args = ast_childidx(trait_ref, 2);
  ast_t* type_params = ast_childidx(trait_def, 1);

  if(!reify_defaults(type_params, type_args, true, opt))
    return NULL;

  ast_t* reified = reify(method, type_params, type_args, opt);

  if(reified == NULL)
    return NULL;

  AST_GET_CHILDREN(reified, cap, id, typeparams, params, result,
    can_error, body, doc);

  return reified;
}
Пример #2
0
static bool check_type_params(pass_opt_t* opt, ast_t** astp)
{
  ast_t* lhs = *astp;
  ast_t* type = ast_type(lhs);

  if(is_typecheck_error(type))
    return false;

  ast_t* typeparams = ast_childidx(type, 1);
  assert(ast_id(type) == TK_FUNTYPE);

  if(ast_id(typeparams) == TK_NONE)
    return true;

  BUILD(typeargs, typeparams, NODE(TK_TYPEARGS));

  if(!reify_defaults(typeparams, typeargs, true, opt))
  {
    ast_free_unattached(typeargs);
    return false;
  }

  if(!check_constraints(lhs, typeparams, typeargs, true, opt))
  {
    ast_free_unattached(typeargs);
    return false;
  }

  type = reify(type, typeparams, typeargs, opt);
  typeparams = ast_childidx(type, 1);
  ast_replace(&typeparams, ast_from(typeparams, TK_NONE));

  REPLACE(astp, NODE(ast_id(lhs), TREE(lhs) TREE(typeargs)));
  ast_settype(*astp, type);

  return true;
}
Пример #3
0
bool expr_qualify(pass_opt_t* opt, ast_t** astp)
{
  // Left is a postfix expression, right is a typeargs.
  ast_t* ast = *astp;
  AST_GET_CHILDREN(ast, left, right);
  ast_t* type = ast_type(left);
  assert(ast_id(right) == TK_TYPEARGS);

  if(is_typecheck_error(type))
    return false;

  switch(ast_id(left))
  {
    case TK_TYPEREF:
    {
      // Qualify the type.
      assert(ast_id(type) == TK_NOMINAL);

      // If the type isn't polymorphic or the type is already qualified,
      // sugar .apply().
      ast_t* def = names_def(opt, type);
      ast_t* typeparams = ast_childidx(def, 1);

      if((ast_id(typeparams) == TK_NONE) ||
        (ast_id(ast_childidx(type, 2)) != TK_NONE))
      {
        if(!expr_nominal(opt, &type))
          return false;

        break;
      }

      type = ast_dup(type);
      ast_t* typeargs = ast_childidx(type, 2);
      ast_replace(&typeargs, right);
      ast_settype(ast, type);
      ast_setid(ast, TK_TYPEREF);

      return expr_typeref(opt, astp);
    }

    case TK_NEWREF:
    case TK_NEWBEREF:
    case TK_BEREF:
    case TK_FUNREF:
    case TK_NEWAPP:
    case TK_BEAPP:
    case TK_FUNAPP:
    {
      // Qualify the function.
      assert(ast_id(type) == TK_FUNTYPE);
      ast_t* typeparams = ast_childidx(type, 1);

      if(!reify_defaults(typeparams, right, true, opt))
        return false;

      if(!check_constraints(left, typeparams, right, true, opt))
        return false;

      type = reify(type, typeparams, right, opt);
      typeparams = ast_childidx(type, 1);
      ast_replace(&typeparams, ast_from(typeparams, TK_NONE));

      ast_settype(ast, type);
      ast_setid(ast, ast_id(left));
      ast_inheritflags(ast);
      return true;
    }

    default: {}
  }

  // Sugar .apply()
  ast_t* dot = ast_from(left, TK_DOT);
  ast_add(dot, ast_from_string(left, "apply"));
  ast_swap(left, dot);
  ast_add(dot, left);

  if(!expr_dot(opt, &dot))
    return false;

  return expr_qualify(opt, astp);
}
Пример #4
0
bool expr_nominal(pass_opt_t* opt, ast_t** astp)
{
  // Resolve type aliases and typeparam references.
  if(!names_nominal(opt, *astp, astp, true))
    return false;

  ast_t* ast = *astp;

  switch(ast_id(ast))
  {
    case TK_TYPEPARAMREF:
      return flatten_typeparamref(ast) == AST_OK;

    case TK_NOMINAL:
      break;

    default:
      return true;
  }

  // If still nominal, check constraints.
  ast_t* def = (ast_t*)ast_data(ast);

  // Special case: don't check the constraint of a Pointer. This allows a
  // Pointer[Pointer[A]], which is normally not allowed, as a Pointer[A] is
  // not a subtype of Any.
  ast_t* id = ast_child(def);
  const char* name = ast_name(id);

  if(!strcmp(name, "Pointer"))
    return true;

  ast_t* typeparams = ast_childidx(def, 1);
  ast_t* typeargs = ast_childidx(ast, 2);

  if(!reify_defaults(typeparams, typeargs, true))
    return false;

  if(!strcmp(name, "MaybePointer"))
  {
    // MaybePointer[A] must be bound to a struct.
    assert(ast_childcount(typeargs) == 1);
    ast_t* typeparam = ast_child(typeparams);
    ast_t* typearg = ast_child(typeargs);
    bool ok = false;

    switch(ast_id(typearg))
    {
      case TK_NOMINAL:
      {
        ast_t* def = (ast_t*)ast_data(typearg);
        ok = ast_id(def) == TK_STRUCT;
        break;
      }

      case TK_TYPEPARAMREF:
      {
        ast_t* def = (ast_t*)ast_data(typearg);
        ok = def == typeparam;
        break;
      }

      default: {}
    }

    if(!ok)
    {
      ast_error(ast,
        "%s is not allowed: the type argument to MaybePointer must be a struct",
        ast_print_type(ast));

      return false;
    }
  }

  return check_constraints(typeargs, typeparams, typeargs, true);
}
Пример #5
0
bool expr_nominal(pass_opt_t* opt, ast_t** astp)
{
  // Resolve type aliases and typeparam references.
  if(!names_nominal(opt, *astp, astp, true))
    return false;

  ast_t* ast = *astp;

  switch(ast_id(ast))
  {
    case TK_TYPEPARAMREF:
      return flatten_typeparamref(opt, ast) == AST_OK;

    case TK_NOMINAL:
      break;

    default:
      return true;
  }

  // If still nominal, check constraints.
  ast_t* def = (ast_t*)ast_data(ast);

  // Special case: don't check the constraint of a Pointer or an Array. These
  // builtin types have no contraint on their type parameter, and it is safe
  // to bind a struct as a type argument (which is not safe on any user defined
  // type, as that type might then be used for pattern matching).
  if(is_pointer(ast) || is_literal(ast, "Array"))
    return true;

  ast_t* typeparams = ast_childidx(def, 1);
  ast_t* typeargs = ast_childidx(ast, 2);

  if(!reify_defaults(typeparams, typeargs, true, opt))
    return false;

  if(is_maybe(ast))
  {
    // MaybePointer[A] must be bound to a struct.
    assert(ast_childcount(typeargs) == 1);
    ast_t* typeparam = ast_child(typeparams);
    ast_t* typearg = ast_child(typeargs);
    bool ok = false;

    switch(ast_id(typearg))
    {
      case TK_NOMINAL:
      {
        ast_t* def = (ast_t*)ast_data(typearg);
        ok = ast_id(def) == TK_STRUCT;
        break;
      }

      case TK_TYPEPARAMREF:
      {
        ast_t* def = (ast_t*)ast_data(typearg);
        ok = def == typeparam;
        break;
      }

      default: {}
    }

    if(!ok)
    {
      ast_error(opt->check.errors, ast,
        "%s is not allowed: "
        "the type argument to MaybePointer must be a struct",
        ast_print_type(ast));

      return false;
    }

    return true;
  }

  return check_constraints(typeargs, typeparams, typeargs, true, opt);
}
Пример #6
0
// Process the method provided to the given entity.
// Stage 2.
static bool provided_methods(pass_opt_t* opt, ast_t* entity)
{
  assert(entity != NULL);

  ast_t* provides = ast_childidx(entity, 3);
  ast_t* entity_members = ast_childidx(entity, 4);
  ast_t* last_member = ast_childlast(entity_members);
  bool r = true;

  // Run through our provides list
  for(ast_t* p = ast_child(provides); p != NULL; p = ast_sibling(p))
  {
    ast_t* trait_def = (ast_t*)ast_data(p);
    assert(trait_def != NULL);

    ast_t* type_args = ast_childidx(p, 2);
    ast_t* type_params = ast_childidx(trait_def, 1);
    ast_t* members = ast_childidx(trait_def, 4);

    // Run through the methods of each provided type
    for(ast_t* m = ast_child(members); m != NULL; m = ast_sibling(m))
    {
      // Check behaviour compatability
      if(ast_id(m) == TK_BE)
      {
        switch(ast_id(entity))
        {
          case TK_PRIMITIVE:
            ast_error(entity,
              "primitives can't provide traits that have behaviours");
            r = false;
            continue;

          case TK_STRUCT:
            ast_error(entity,
              "structs can't provide traits that have behaviours");
            r = false;
            continue;

          case TK_CLASS:
            ast_error(entity,
              "classes can't provide traits that have behaviours");
            r = false;
            continue;

          default: {}
        }
      }

      if(is_method(m))
      {
        // We have a provided method
        // Reify the method with the type parameters from trait definition and
        // type arguments from trait reference
        if(!reify_defaults(type_params, type_args, true))
          return false;

        ast_t* reified = reify(m, type_params, type_args);

        if(reified == NULL) // Reification error, already reported
          return false;

        if(!provided_method(opt, entity, reified, m, &last_member))
          r = false;
      }
    }
  }

  return r;
}