Thread overview
Frontend Issues w/ implementing UFCS Partial Template Evaluation (for language server use)
Oct 01
Clouudy
2 days ago
Dennis
2 days ago
Clouudy
2 days ago
Dennis
1 day ago
Clouudy
1 day ago
Dennis
October 01

I'm currently developing a language server for D that uses the DMD frontend to perform its tasks, but one thing I'm stumped on is how to deal with templates and UFCS. From the checking around I've done within the compiler, I haven't really found a function that can evaluate only that the first argument can be used with a specific template function, but not check any other arguments or unrelated constraints.

Without the ability to perform partial template evaluation, completion from libraries such as std.algorithm would be unwieldy and inaccurate, and the completion suggestions would be about as bad as DCD's, or would be hardcoded only for standard library functions.

I know that there was already talk about getting a DMD-based language server off the ground before I started this project myself; I would appreciate it if I could get some help on solving this issue (either by suggesting methods for partial evaluation or creating them if none are completely workable), so that I can help accomplish this. Thank you.

2 days ago

On Wednesday, 1 October 2025 at 23:26:53 UTC, Clouudy wrote:

>

From the checking
around I've done within the compiler, I haven't really found a
function that can evaluate only that the first argument can
be used with a specific template function, but not check any
other arguments or unrelated constraints.

This looks like an intractable problem in the general case. Consider this function:

void f(R, E)(R r, E e) if (Check!(R, E))

When the first argument is an int for example, how would you deduce whether Check!(int, E) is satisfiable for some E? Templates are not invertible like that.

>

Without the ability to perform partial template evaluation, completion from libraries such as std.algorithm would be unwieldy and inaccurate, and the completion suggestions would be about as bad as DCD's, or would be hardcoded only for standard library functions.

Given the above, I think you still need to find a pragmatic simplification of the problem. Start with the most optimistic auto-completion possible, and collect a bunch of failure cases from real world usage where it does nonsense suggestions. Then inspect those cases and see if there's some property you can detect to prune most of the wrong candidates.

>

I know that there was already talk about getting a DMD-based language server off the ground before I started this project myself; I would appreciate it if I could get some help on solving this issue (either by suggesting methods for partial evaluation or creating them if none are completely workable), so that I can help accomplish this. Thank you.

I don't think I can offer concrete advice before trying to implement auto-completions myself first, but you're always welcome to ask more specific questions about the DMD code base.

2 days ago

On Monday, 6 October 2025 at 12:28:33 UTC, Dennis wrote:

>

On Wednesday, 1 October 2025 at 23:26:53 UTC, Clouudy wrote:

>

From the checking
around I've done within the compiler, I haven't really found a
function that can evaluate only that the first argument can
be used with a specific template function, but not check any
other arguments or unrelated constraints.

This looks like an intractable problem in the general case. Consider this function:

void f(R, E)(R r, E e) if (Check!(R, E))

When the first argument is an int for example, how would you deduce whether Check!(int, E) is satisfiable for some E? Templates are not invertible like that.

The idea I have is that you could iterate over every sub-expression within a constraint; for each sub-expression you'd determine whether it relies on just the first template parameter or if it needs other parameters as well. Then for each sub-expression that only needs the first template parameter you can verify whether that sub-expression evaluates to true or not. Any function with a definitively false constraint gets ruled out, while functions that are fully or partially/potentially true get offered as suggestions.

This would cover a lot of common constraints like whether something is a range or not, or whether it's an instance of a specific template type. I don't see any specific reason why it'd be impossible to do, at least hypothetically.

>

I don't think I can offer concrete advice before trying to implement auto-completions myself first, but you're always welcome to ask more specific questions about the DMD code base.

Like I said I have the basic strategy for how to do this down, I just need to know how the frontend works to be able to implement it. I guess the specific questions I can ask are:

  • How can I use the frontend to determine whether an expression can be evaluated or not?
  • How can I actually evaluate that expression using the frontend?
  • Would it be possible to partially match a template? As in, if DMD knows the name of the template and the first parameter, can it deduce what the actual template is, or a list of contenders?
  • Is there a way to just push through any parsing/semantic analysis errors that appear and just mark or identify parts of the AST that couldn't be resolved as a result?
  • Is there an easy way to get every possible type/variable that is visible from within a certain scope? How can I get a scope from just the line and character numbers within a file?
2 days ago

On Monday, 6 October 2025 at 18:21:21 UTC, Clouudy wrote:

>
  • How can I use the frontend to determine whether an expression can be evaluated or not?
  • How can I actually evaluate that expression using the frontend?

You can use trySemantic which returns null on failure, or the result of semantic analysis on the Expression on success. 'evaluate' in the frontend usually refers to constant folding / CTFE, but I assume you don't need that here.

>
  • Would it be possible to partially match a template? As in, if DMD knows the name of the template and the first parameter, can it deduce what the actual template is, or a list of contenders?

It's possible if you implement that logic yourself. You can maybe re-use bits like deduceType or matchArg, but dmd's functionResolve routine is made to resolve a complete argument list.

>
  • Is there a way to just push through any parsing/semantic analysis errors that appear and just mark or identify parts of the AST that couldn't be resolved as a result?

To prevent error messages from showing up, perhaps look at existing use of global.startGagging. DMD already creates error nodes (ErrorExp) for parts that fail to analyze, but it's only designed to reduce the chance of a blizzard of cascaded errors. It might not be good enough for your use case.

>
  • Is there an easy way to get every possible type/variable that is visible from within a certain scope? How can I get a scope from just the line and character numbers within a file?

DMD's scopes are a stack made just for quick lookups while compiling. It doesn't retain a nice scope graph data structure or anything, and I remember Razvan (who has been working a lot on DMD as a library) stumbling on this before.

1 day ago

On Monday, 6 October 2025 at 20:04:43 UTC, Dennis wrote:

>

On Monday, 6 October 2025 at 18:21:21 UTC, Clouudy wrote:

>
  • How can I use the frontend to determine whether an expression can be evaluated or not?
  • How can I actually evaluate that expression using the frontend?

You can use trySemantic which returns null on failure, or the result of semantic analysis on the Expression on success. 'evaluate' in the frontend usually refers to constant folding / CTFE, but I assume you don't need that here.

Isn't CTFE required to evaluate whether something is an instance of a template? How would I do that if that's true?

1 day ago

On Tuesday, 7 October 2025 at 15:57:22 UTC, Clouudy wrote:

>

Isn't CTFE required to evaluate whether something is an instance of a template? How would I do that if that's true?

CTFE may be necessary to determine the type of an Expression, for example mixin(f()) needs to evaluate f() to a string, but that is handled by semantic analysis. But when you have a call to template function f like f(x), you only need to know the type of x, not evaluate x to a value at compile time.