Skip to content
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

Use diagnostic::on_unimplemented to make compile errors more helpful and less intimidating #231

Open
lloydmeta opened this issue May 3, 2024 · 0 comments

Comments

@lloydmeta
Copy link
Owner

lloydmeta commented May 3, 2024

Right now, compile-time errors on transmogrify can be truly terrifying and unhelpful.

The new #[diagnostic::on_unimplemented] attribute from 1.78.0 might be helpful here.

That said, much of the functionality around LabelledGeneric and friends are built on top of smaller, more basic traits, which are based on other traits.... so I'm not really sure how far we can really go. Worth a think though.

frunk/core/src/labelled.rs

Lines 829 to 911 in 1ca9c99

/// Non-trivial implementation of `Transmogrifier` where similarly-shaped `Source` and `Target` types are
/// both Labelled HLists, but do not immediately transform into one another due to mis-matched
/// fields, possibly recursively so.
impl<
SourceHead,
SourceTail,
TargetHeadName,
TargetHeadValue,
TargetTail,
PluckSourceHeadNameIndex,
TransMogSourceHeadValueIndices,
TransMogTailIndices,
>
Transmogrifier<
HCons<Field<TargetHeadName, TargetHeadValue>, TargetTail>,
HCons<
DoTransmog<PluckSourceHeadNameIndex, TransMogSourceHeadValueIndices>,
TransMogTailIndices,
>,
> for HCons<SourceHead, SourceTail>
where
// Pluck a value out of the Source by the Head Target Name
HCons<SourceHead, SourceTail>: ByNameFieldPlucker<TargetHeadName, PluckSourceHeadNameIndex>,
// The value we pluck out needs to be able to be transmogrified to the Head Target Value type
Field<
TargetHeadName,
<HCons<SourceHead, SourceTail> as ByNameFieldPlucker<
TargetHeadName,
PluckSourceHeadNameIndex,
>>::TargetValue,
>: Transmogrifier<TargetHeadValue, TransMogSourceHeadValueIndices>,
// The remainder from plucking out the Head Target Name must be able to be transmogrified to the
// target tail, utilising the other remaining indices
<HCons<SourceHead, SourceTail> as ByNameFieldPlucker<
TargetHeadName,
PluckSourceHeadNameIndex,
>>::Remainder: Transmogrifier<TargetTail, TransMogTailIndices>,
{
#[inline(always)]
fn transmogrify(self) -> HCons<Field<TargetHeadName, TargetHeadValue>, TargetTail> {
let (source_field_for_head_target_name, remainder) = self.pluck_by_name();
let name = source_field_for_head_target_name.name;
let transmogrified_value: TargetHeadValue =
source_field_for_head_target_name.transmogrify();
let as_field: Field<TargetHeadName, TargetHeadValue> =
field_with_name(name, transmogrified_value);
HCons {
head: as_field,
tail: remainder.transmogrify(),
}
}
}
impl<Source, Target, TransmogIndices>
Transmogrifier<Target, LabelledGenericTransmogIndicesWrapper<TransmogIndices>> for Source
where
Source: LabelledGeneric,
Target: LabelledGeneric,
<Source as LabelledGeneric>::Repr:
Transmogrifier<<Target as LabelledGeneric>::Repr, TransmogIndices>,
{
#[inline(always)]
fn transmogrify(self) -> Target {
let source_as_repr = self.into();
let source_transmogged = source_as_repr.transmogrify();
<Target as LabelledGeneric>::from(source_transmogged)
}
}
// Implementation for when the source value is plucked
impl<Source, TargetName, TargetValue, TransmogIndices>
Transmogrifier<TargetValue, PluckedLabelledGenericIndicesWrapper<TransmogIndices>>
for Field<TargetName, Source>
where
Source: LabelledGeneric,
TargetValue: LabelledGeneric,
Source: Transmogrifier<TargetValue, TransmogIndices>,
{
#[inline(always)]
fn transmogrify(self) -> TargetValue {
self.value.transmogrify()
}
}

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

No branches or pull requests

1 participant