4 ms·
I've got a compiler for a hobby language that uses this technique too (I probably got it from you, unless I heard it from someone else). It's really really nice
by munificent 2y ago
I've got a compiler for a hobby language that uses this technique too (I probably got it from you, unless I heard it from someone else). It's really really nice. Super easy to implement and really does cut down on cascaded errors.
I also use it during type checking. There is a special "error" type. If an expression produces a type error, the yielded type of that expression becomes "error". Surrounding expressions that consume that type will see the error type and suppress any other type errors they might otherwise produce. That way, you only see the original type error.
- WalterBright 2y agoYup, dmd also has an error type: https://github.com/dlang/dmd/blob/master/compiler/src/dmd/mtype.d#L1633 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/mt...
- nathan_douglas 2y agoFunny, I was just gonna comment and say that I learned this One Weird Trick… and then realized I’d learned it from you. (Hi, Bob! I was actually just using your recursive shadowcasting algorithm as a reference yesterday.) I feel like I just got an Erdos number or something.
- munificent 2y ago:D
- tnh 2y ago> Surrounding expressions that consume that type will see the error type and suppress any other type errors they might otherwise produce. We added a slightly-cursed version of this to clang. The goal was: include more broken code in the AST instead of dropping it on the floor, without adding noisy error cascades. The problem is, adding a special case to all "surrounding expressions that consume that type" is literally thousands of places. It's often unclear exactly what to do, because "consume" means so many things in C++ (think overload resolution and argument-dependent lookup) and because certain type errors are used in metaprogramming (thanks, SFINAE). So this would cost a lot of complexity, and it's too late to redesign clang around it. But C++ already has a mechanism to suppress typechecking! Inside a template, most analysis of code that depends on a template parameter is deferred until instantiation. The implementation of this is hugely complicated and expensive to maintain, but that cost is sunk. So we piggy-backed on this mechanism: clang's error type is `<dependent type>`. The type of this expression depends on how the programmer fixes their error :-) And that's the story of how C gained dependent types (https://godbolt.org/z/szGdeGhrr https://godbolt.org/z/szGdeGhrr), because why should C++ have all the fun? (This leaves out a bunch of nuance, of course the truth is always more complicated)
- munificent 2y agoI love/hate/but-really-love/but-totally-hate this.
- WalterBright 2y agoIn D, all semantic analysis of a template waits until instantiation time. This is because D is designed so that the syntax parsing does not need a symbol table. In C++, I solved this problem by simply matching { } in the template body, and accumulating a list of tokens within the { }. Then, when instantiated, the template parameter values were known, and the template syntax could then be semantically analyzed. It was simple and effective. But I was informed that C++ required the syntax parsing and semantics for non-dependent types without instantiation. I asked why, and the answer was "to check for errors without needing to instantiate it." I responded with "of what use is checking it if it is never used or tested?" And that was the end of that. > The implementation of this is hugely complicated and expensive to maintain I quietly revolted and refused to implement that disaster. AFAIK there was never a problem with deferring parsing/semantic until instantiation.
- Matheus28 2y agoIsn't that what msvc does? I remember it's a little weird about when it actually checks for errors in templated code
- WalterBright 2y agoI have no idea what msvc does with this.
- tnh 2y agoYes (at least approximately, I'm fuzzy on the details). These days it supports both. (IIRC the default is legacy/nonstandard, you select the standard behavior with /fpermission-, and VS adds /fpermission- to newly generated projects) https://devblogs.microsoft.com/cppblog/two-phase-name-lookup-support-comes-to-msvc/ https://devblogs.microsoft.com/cppblog/two-phase-name-lookup...
- 2y ago