Skip to content

[clangd enhancement] enhancing the non-template completion experience with type holes #137111

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
illusory0x0 opened this issue Apr 24, 2025 · 10 comments
Labels

Comments

@illusory0x0
Copy link

illusory0x0 commented Apr 24, 2025

Use type holes to help write code, reduce to many parse error or unbound variables. then clangd can use AST correct program to give we more useful information.

  • named requirement
  • ambiguous
  • type infomation
@frederick-vs-ja
Copy link
Contributor

I can't infer the exact issue from the current description. Do you want to add a helper header with proposed contents to clangd (or elsewhere)?

@illusory0x0
Copy link
Author

#pragma once
#include <utility>

namespace type_holes {
struct Hole {
  template <typename T> operator T() const noexcept {
    return std::declval<T>();
  }
};
constexpr auto _ = Hole{};
constexpr auto $hole = Hole{};
constexpr auto hole = Hole{}; // If the code does not use type holes, it will not cause a compilation error because the template is not instantiated.
} // namespace type_holes
#include <type_holes.h>
using namespace type_holes;

int main() {
  std::vector<int> vec = _; 
 

  vec.push_back(0);
  // vec.push_back(value_type &&x)


}

@illusory0x0 illusory0x0 changed the title enhancing the non-template completion experience with type holes [clangd] enhancing the non-template completion experience with type holes Apr 24, 2025
@illusory0x0
Copy link
Author

I can't infer the exact issue from the current description.

I apologize for not realizing that this is an issues for llvm-project, there are many other different components and I should have been more specific in describing which compiler component is the issues.

@frederick-vs-ja
Copy link
Contributor

I can't infer the exact issue from the current description.

I apologize for not realizing that this is an issues for llvm-project, there are many other different components and I should have been more specific in describing which compiler component is the issues.

Oh, I could infer that this is clangd-related according to your previous issues. But it's unclear what should be done. Did you ask a question, request enhancement, or report a bug?

@llvmbot
Copy link
Member

llvmbot commented Apr 24, 2025

@llvm/issue-subscribers-clangd

Author: 猗露 (illusory0x0)

It looks better than before.

Image

Image

struct Hole {
  template&lt;typename T&gt;
  operator T() const noexcept {
    return std::declval&lt;T&gt;();
  }
};


auto $hole = Hole{};

struct X {
  X foo(int x, int y) {
    return $hole;
  }

};

@illusory0x0 illusory0x0 changed the title [clangd] enhancing the non-template completion experience with type holes [clangd enhancement] enhancing the non-template completion experience with type holes Apr 24, 2025
@HighCommander4
Copy link
Collaborator

I'm also confused. Could you describe please:

  • What editor operation(s) you are performing (e.g. "invoke code completion at this location")
  • What would you like to happen
  • What actually happens

@illusory0x0
Copy link
Author

@HighCommander4

invoke code completion at this location

when I typing vec.push_back, press Enter or Tab key to accept completion item.

Expected behavior

I would like clangd to support User defined placeholder.

{
   "clangd.completion.placeholder" : "$hole"
}

expect it complete result is vec.push_back($hole). User can define a expression which can implicit convert to any type as follows. use type holes can reduce too many complier error, such as Expected expressionclang(expected_expression)

Image

If clangd complete a type hole, we can hove on this hole, then we can know what the type is expected in this argument.

Image

the default behavior cause parse error and undeclared identifier we can't any useful information.

Image

If clangd complete User defined type holes, we can get more useful information. such as named requirements

Image

or ambiguous.

Step 1

Image

replace a hole with 1.2, then Candidate function count is less than before.

Step 2

Image

#pragma once
#include <utility>

namespace type_holes {
struct Hole {
  template <typename T> operator T() const noexcept {
    return std::declval<T>();
  // If the user code does not use type holes,
  // it will not cause a compilation error because the template is not instantiated.
  }
};
constexpr auto _ = Hole{};
constexpr auto $hole = Hole{};
constexpr auto hole = Hole{}; 
} // namespace type_holes

Actual behavor

clangd will complete both type and parameter vec.push_back(value_type&& x),
This triggers a lot of compile errors, we can't use hover on the variables to get some useful type information.

Reference

But what are typed holes, and how do they help us write code?

https://wiki.haskell.org/GHC/Typed_holes

@illusory0x0
Copy link
Author

illusory0x0 commented Apr 24, 2025

I found related issue in here #63565 (comment), I think we can add a new option to support this feature.

@HighCommander4
Copy link
Collaborator

HighCommander4 commented Apr 25, 2025

Ok, thanks, I think I understand the feature request now.

Note that the intention behind placeholders is that you immediately type over them (and the editor facilitates this by pre-selecting the first one and making it so that Tab jumps to the next one). The placeholder contents (e.g. parameter_type&& parameter_name) are intended to be a hint to help you decide what to type; you're not meant to leave the placeholder contents in the code and try to compile the result.

Perhaps you would find ArgumentLists: Delimiters (or in older clangd versions, --function-arg-placeholders=false) to be an improvement over the default behaviour already.

@illusory0x0
Copy link
Author

Note that the intention behind placeholders if that you immediately type over them (and the editor facilitates this by pre-selecting the first one and making it so that Tab jumps to the next one). The placeholder contents (e.g. parameter_type&& parameter_name) are intended to be a hint to help you decide what to type;

use holes we not need immediately handle all type check error, We can solve later code then fix before code, we can jump random access to write code, not always from top to bottom.

you're not meant to leave the placeholder contents in the code and try to compile the result.

I found a solution allow this unimplemented code trigger error in runtime not complietime. sometime we want to write some scaffold not indent immediately implementation it.

#pragma once

namespace type_holes {
struct Hole {
  template <typename T> operator T() { throw "unreachable"; }
};
constexpr auto _ = Hole{};
constexpr auto hole = Hole{};
} // namespace type_holes

Perhaps you would find ArgumentLists: Delimiters (or in older clangd versions, --function-arg-placeholders=false) to be an improvement over the default behaviour already.
(and the editor facilitates this by pre-selecting the first one and making it so that Tab jumps to the next one).

use ArgumentLists: Delimiters we only enjoy the type hint in first completion, we have to fill arguments to avoid to many error, but sometime not want to handle this immediately, I would like to keep all code type correct first then fill implementations.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

5 participants