Comments (13)
Awesome, thanks! I think the best place to add it is here. If there's a #[ts(bound)]
, then we can just skip the bound-generation we do in generate_where_clause
.
from ts-rs.
I'm a bit confused why this doesn't need a where D::Info: TS
bound.
Is that implied by the fact that the struct contains an Inner<D>
, which has the D::Info: TS
, and the bound is transferred to Outer
?
from ts-rs.
Ah, never mind - thought i was losing my mind here for a second.
That D::Info: TS
bound is indeed still required. I've updated the Issue.
from ts-rs.
@NyxCode You're right, I meant to write this:
impl ts_rs::TS for Outer<TsDriver>
where /* no bounds */
{
...
}
...because D
is substituted for TsDriver
with #[ts(concrete(D = TsDriver), bound = "/* no bounds */"]
. You're right that without concrete
, the bound would be needed. I might be missing something though.
from ts-rs.
Actually it looks like #264 preserves the type parameter in the impl block — is that the correct behavior?
#[derive(TS)]
#[ts(export, concrete(D = TsDriver))]
struct Outer<D: Driver> {
inner: Inner<D>,
}
Generates this:
impl<D: Driver> ts_rs::TS for Outer<D>
where
D: ts_rs::TS,
{
type WithoutGenerics = Outer<TsDriver>;
...
}
But shouldn't it generate this?
impl ts_rs::TS for Outer<TsDriver>
{
...
}
from ts-rs.
Ah, alright, now I see where the confusion came from.
So the original concrete
branch started out with impl<D: Driver> TS for MyStruct<D>
.
That worked, but required this annoying type Info: TS
bound in the definition of Driver
.
Then, we tried actually generating impl TS for MyStruct<TsDriver>
. However, we hit a hard wall going down that road. If you're interested in the details, see #264. The gist of it is that we generated <TsDriver::Info as TS>::name()
inside the impl
, which the trait solver refuses to accept. We'd have had to generate <<TsDriver as Driver>::Info as TS>::name()
instead, but that's not possible inside the proc macro (as soon as there's more than one trait bound on D
)1.
Therefore, we settled on generating impl<D: Driver> TS for MyStruct<D> where D::Info: TS
. That gives us all the benifits we'd have gotten with the other approach (namely, get rid of the type Info: TS
bound).
Everything works like it was an impl TS for MyStruct<TsDriver>
. However, MyStruct<OtherDriver>
still implements TS
if OtherDriver::Info: TS
. If you'd call MyStruct<OtherDriver>::decl()
though, it'll behave as-if it was an MyStruct<TsDriver>
.
So the tl;dr why it didnt work is: If you access an associated type of a concrete type (e.g TsDriver::Info
), Rust doesn't infer which trait it should use to get Info
. That makes sense, since it's possible that TsDriver
implemented two traits with an associated type Info
.
Footnotes
from ts-rs.
@NyxCode What do you think about requiring that the associated types be spelled out completely (ie. <X as T>::Y
)?
#[derive(TS)]
#[ts(export, concrete(D = TsDriver))]
struct Inner<D: Driver> {
info: <D as Driver>::Info,
}
Then I believe Rust would raise an error whenever it can't determine which associated type to use. That would also solve the issue of multiple trait bounds.
from ts-rs.
Absolutely, that'd have worked! With the codegen as-is, which does <{field_type} as TS>::name()
, that'd have generated <<D as Driver>::Info as TS>::name()
- exactly what we tried to do "by hand".
We didn't see any downside with generating impl<D: Driver> TS for MyStruct<D> where D::Info
, and it doesn't require that you touch the type definition at all.
from ts-rs.
Well, there is one downside, which is that you don't get a compiler error if you do MyStruct::<OtherDriver>::export()
if it's #[ts(concrete(D = TsDriver))]
. Instead, you just get the definition of MyStruct<TsDriver>
according to the #[ts(concrete(..)]
.
Since (we hope) most users just use #[ts(export)]
, this seemed like a minor issue.
from ts-rs.
@NyxCode Got it! I just tested the latest changes on main, but I'm still getting the extra bound when I #[derive(TS)]
on Outer
:
use ts_rs::TS;
trait Driver {
type Info: TS;
}
struct MyDriver;
#[derive(TS)]
struct MyInfo;
impl Driver for MyDriver {
type Info = MyInfo;
}
#[derive(TS)]
#[ts(export, concrete(D = MyDriver))]
struct Inner<D: Driver> {
info: D::Info,
}
#[derive(TS)]
#[ts(export, concrete(D = MyDriver))]
struct Outer<D: Driver> {
inner: Inner<D>,
}
impl<D: Driver> ::ts_rs::TS for Outer<D>
where
+ D: ::ts_rs::TS,
{
...
}
Basically, the current implementation requires MyDriver
itself implements TS
, not just its associated types, since it sees that D
is used "directly" in Outer
— the goal with #[ts(bound = "")]
is to remove this bound (since it's not actually necessary that D
itself implements TS
, only its associated types).
from ts-rs.
Yup, we're on the same page here!
The tradeoff between the two solutions of generating trait bounds we explored turned out to be:
- Generate perfect bounds, but fail on self-referential types
- Overestimate bounds, but allow self-referential types
So you're absolutely right here - The generated bound D: TS
is wrong, and it needs to be D::Info: TS
instead.
And it needs to be D::Info: TS
, since the impl is still generic over <D: Driver>
, even with #[ts(concrete)]
.
And I agree, #[ts(bound = "...")]
seems perfect for that.
from ts-rs.
OK great! I am putting together a bound
attribute now and will open a PR soon.
from ts-rs.
I just implemented the attribute here: main...WilsonGramer:ts-rs:bound-attribute
Let me know what you think!
from ts-rs.
Related Issues (20)
- Feature request: rust_decimal::Decimal TS implementation HOT 2
- Can we support `#[serde(with = "..")]`? HOT 11
- Feature request: `bnum` compatibility HOT 2
- bug: `impl Trait` only allowed in function and inherent method return types, not in trait method return types HOT 4
- TypeList recursion limit HOT 3
- Feature request: Export in the same file HOT 3
- bug: Using `#[ts(rename_all = "...")]` `snake_case`, `SCREAMING_SNAKE_CASE` and `kebab-case` is not compatible with serde
- Randomly failing `imports` test HOT 1
- Unqualified call to `Self::name()`
- `usize` and `isize` should be typed as `bigint` on 64-bit architectures HOT 6
- Feature request: `serde-wasm-bindgen` compatibility. HOT 4
- Feature request: How to export multiple types to the same file HOT 4
- Feature request: Typed array types HOT 1
- bug: Tuples cause imports to be missed HOT 5
- bug: files are missing final newlines
- bug: `export::path:absolute` function fails when `TS_RS_EXPORT_DIR` is set to an absolute path and the `path_bug` test is executed
- bug: TS generated tests fail on struct with `serde_json::Value` type when running `cargo test`. HOT 2
- `ts(optional)` should be working on any which has `skip_serializing_if` HOT 1
- Add all of `ts(function)` to docs. HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from ts-rs.