Пример #1
0
static ast_t* lookup_base(typecheck_t* t, ast_t* from, ast_t* orig,
  ast_t* type, const char* name, bool errors)
{
  switch(ast_id(type))
  {
    case TK_UNIONTYPE:
      if(errors)
        ast_error(from, "can't lookup by name on a union type");

      return NULL;

    case TK_ISECTTYPE:
    {
      ast_t* child = ast_child(type);

      while(child != NULL)
      {
        ast_t* result = lookup_base(t, from, orig, child, name, false);

        if(result != NULL)
          return result;

        child = ast_sibling(child);
      }

      ast_error(from, "couldn't find '%s'", name);
      return NULL;
    }

    case TK_TUPLETYPE:
      if(errors)
        ast_error(from, "can't lookup by name on a tuple");

      return NULL;

    case TK_NOMINAL:
      return lookup_nominal(t, from, orig, type, name, errors);

    case TK_ARROW:
      return lookup_base(t, from, orig, ast_childidx(type, 1), name, errors);

    case TK_TYPEPARAMREF:
      return lookup_typeparam(t, from, orig, type, name, errors);

    case TK_FUNTYPE:
      if(errors)
        ast_error(from, "can't lookup by name on a function type");

      return NULL;

    case TK_INFERTYPE:
      // Can only happen due to a local inference fail earlier
      return NULL;

    default: {}
  }

  assert(0);
  return NULL;
}
Пример #2
0
static ast_t* lookup_base(pass_opt_t* opt, ast_t* from, ast_t* orig,
                          ast_t* type, const char* name, bool errors)
{
    switch(ast_id(type))
    {
    case TK_UNIONTYPE:
    {
        ast_t* child = ast_child(type);
        ast_t* result = NULL;
        bool ok = true;

        while(child != NULL)
        {
            ast_t* r = lookup_base(opt, from, child, child, name, errors);

            if(r == NULL)
            {
                // All possible types in the union must have this.
                if(errors)
                {
                    ast_error(from, "couldn't find %s in %s",
                              name, ast_print_type(child));
                }

                ok = false;
            } else {
                switch(ast_id(r))
                {
                case TK_FVAR:
                case TK_FLET:
                case TK_EMBED:
                    if(errors)
                    {
                        ast_error(from,
                                  "can't lookup field %s in %s in a union type",
                                  name, ast_print_type(child));
                    }

                    ok = false;
                    break;

                default:
                    if(result == NULL)
                    {
                        // If we don't have a result yet, use this one.
                        result = r;
                    } else if(!is_subtype(r, result, false)) {
                        if(is_subtype(result, r, false))
                        {
                            // Use the supertype function. Require the most specific
                            // arguments and return the least specific result.
                            // TODO: union the signatures, to handle arg names and
                            // default arguments.
                            ast_free_unattached(result);
                            result = r;
                        } else {
                            if(errors)
                            {
                                ast_error(from,
                                          "a member of the union type has an incompatible method "
                                          "signature");
                                ast_error(result, "first implementation is here");
                                ast_error(r, "second implementation is here");
                            }

                            ast_free_unattached(r);
                            ok = false;
                        }
                    }
                    break;
                }
            }

            child = ast_sibling(child);
        }

        if(!ok)
        {
            ast_free_unattached(result);
            result = NULL;
        }

        return result;
    }

    case TK_ISECTTYPE:
    {
        ast_t* child = ast_child(type);
        ast_t* result = NULL;
        bool ok = true;

        while(child != NULL)
        {
            ast_t* r = lookup_base(opt, from, child, child, name, false);

            if(r != NULL)
            {
                switch(ast_id(r))
                {
                case TK_FVAR:
                case TK_FLET:
                case TK_EMBED:
                    // Ignore fields.
                    break;

                default:
                    if(result == NULL)
                    {
                        // If we don't have a result yet, use this one.
                        result = r;
                    } else if(!is_subtype(result, r, false)) {
                        if(is_subtype(r, result, false))
                        {
                            // Use the subtype function. Require the least specific
                            // arguments and return the most specific result.
                            ast_free_unattached(result);
                            result = r;
                        }

                        // TODO: isect the signatures, to handle arg names and
                        // default arguments. This is done even when the functions have
                        // no subtype relationship.
                    }
                    break;
                }
            }

            child = ast_sibling(child);
        }

        if(errors && (result == NULL))
            ast_error(from, "couldn't find '%s'", name);

        if(!ok)
        {
            ast_free_unattached(result);
            result = NULL;
        }

        return result;
    }

    case TK_TUPLETYPE:
        if(errors)
            ast_error(from, "can't lookup by name on a tuple");

        return NULL;

    case TK_NOMINAL:
        return lookup_nominal(opt, from, orig, type, name, errors);

    case TK_ARROW:
        return lookup_base(opt, from, orig, ast_childidx(type, 1), name, errors);

    case TK_TYPEPARAMREF:
        return lookup_typeparam(opt, from, orig, type, name, errors);

    case TK_FUNTYPE:
        if(errors)
            ast_error(from, "can't lookup by name on a function type");

        return NULL;

    case TK_INFERTYPE:
    case TK_ERRORTYPE:
        // Can only happen due to a local inference fail earlier
        return NULL;

    default:
    {}
    }

    assert(0);
    return NULL;
}