-
Notifications
You must be signed in to change notification settings - Fork 12.7k
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
Accept Enum::<Param>::Variant {}
over Enum::Variant::<Param> {}
#69363
Conversation
src/test/ui/nll/user-annotations/pattern_substs_on_brace_enum_variant.rs
Outdated
Show resolved
Hide resolved
This comment has been minimized.
This comment has been minimized.
So, I remember the rule here - paths in "value" contexts get all their omitted generic arguments filled with inference variables ( All the examples in #69356 and in the tests are in "value" context. I did touch the implementation of this at some point, but it was rewritten so many times since then that I have no idea how this works now. |
IIRC, @varkor the author of the current implementation? |
…es of path checking
ea43e14
to
20d2258
Compare
ExprKind::Path
and ExprKind::Struct
the same for the purposes of path checkingEnum::<Param>::Variant {}
over Enum::Variant::<Param> {}
This comment has been minimized.
This comment has been minimized.
20d2258
to
9d58e12
Compare
I've got a commit to make the lint allow by default if that is preferable. Edit: Given #69363 (comment) I guess we need to make it allow by default. |
This comment has been minimized.
This comment has been minimized.
Res::Def(DefKind::Variant, def_id) | ||
if i + 2 == proj_start && segment.args.is_some() => | ||
{ | ||
// Handle `Enum::<Param>::Variant {}`. | ||
// We need to choose one here so that the method `res_to_ty` in | ||
// `astconv` works correctly, but it has to be *only* one, so track | ||
// whether we've already set the `DefId` in the previous segment. | ||
type_param_in_enum = true; | ||
Some(parent_def_id(self, def_id)) | ||
} | ||
Res::Def(DefKind::Variant, def_id) | ||
if i + 1 == proj_start | ||
&& (segment.args.is_some() || !type_param_in_enum) => | ||
{ | ||
// Handle `Enum::Variant::<Param> {}`. | ||
Some(parent_def_id(self, def_id)) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Two things here:
- you can avoid mutable state by looking at
p.segments
- btw I doubt a bit that
.args.is_some()
is the correct way to check this, it might be true even for::<>
which I'm not sure if it's compatible with the similar check in typeck
- btw I doubt a bit that
- these only make sense if the param mode is explicit, which it can never be for
Expr::Struct
right now (<Enum>::Variant {...}
is not valid syntax, andEnum::Variant
is not valid in type paths yet, only one of these two could actually be relevant here)- the comments referring to
Enum::Variant {...}
are therefore inaccurate IMO - this needs some extra checks, probably for the param mode being explicit
- it's really mostly forward compat for
enum
variant types so you could just as well add an assert thatDefKind::Variant
parts are neverParamMode::Explicit
- the comments referring to
@@ -531,6 +538,7 @@ declare_lint_pass! { | |||
PATTERNS_IN_FNS_WITHOUT_BODY, | |||
MISSING_FRAGMENT_SPECIFIER, | |||
LATE_BOUND_LIFETIME_ARGUMENTS, | |||
TYPE_PARAM_ON_VARIANT_CTOR, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure I would include CTOR
in the name. Also, this isn't limited to type parameters.
I'd call it VARIANT_GENERICS
or VARIANT_GENERIC_ARGS
.
pub fn prohibit_multiple_params<'a, T: IntoIterator<Item = &'a hir::PathSegment<'a>>>( | ||
&self, | ||
segments: T, | ||
) -> bool { | ||
let segments_with_params = segments | ||
.into_iter() | ||
.filter_map(|segment| segment.args.map(|arg| arg.span)) | ||
.collect::<Vec<_>>(); | ||
if segments_with_params.len() <= 1 { | ||
return false; | ||
} | ||
self.tcx() | ||
.sess | ||
.struct_span_err( | ||
segments_with_params, | ||
"multiple segments with type parameters are not allowed", | ||
) | ||
.note("only a single path segment can specify type parameters") | ||
.emit(); | ||
true | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is unnecessarily complicated, it doesn't distinguish this "enum
vs variant" situation from others (e.g. trying to pass generic args to a mod
) and it's wrong with generic associated items like methods or GATs.
This could be a help message on the error from prohibit_generics
, such as pointing to the enum
segment and saying "this segment already specified generic args for the enum
" or something.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is unnecessarily complicated, it doesn't distinguish this "enum vs variant" situation from others (e.g. trying to pass generic args to a mod) and it's wrong with generic associated items like methods or GATs.
That check is being done when called. If it were called without that check it would indeed be incorrect.
This could be a help message on the error from prohibit_generics, such as pointing to the enum segment and saying "this segment already specified generic args for the enum" or something.
Wanted to separate this from E0109 to potentially give it its own error code to explain that this will never be supported as opposed to the more generic current error.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
to explain that this will never be supported
What do you mean? Generics on both the enum
and a variant is a plausible feature (GADT), and generics on modules have been talked about in the past.
The error message looks pretty misleading to me, it seems to claim some absolute truth.
if sp.hi() == sp.lo() || sp == DUMMY_SP || sp.parent().is_some() { | ||
// The params were not written by the user, but rather derived. These are expected. | ||
// `Enum::Variant` where `Variant` has inferred lifetimes. | ||
return; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't like this check, and you can get rid of the lifetimes for now (they shouldn't be added to value paths anyway).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree. It's hacky as hell.
you can get rid of the lifetimes for now
How?
they shouldn't be added to value paths anyway
I've spent too much time trying to figure out of a way of making this change without affecting currently accepted code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Basically you want all Expr::Struct
with variant paths to behave in HRI lowering like they did when you had removed the DefKind::Variant
arm.
You don't want the elision lifetimes being injected at all.
They're for fn foo(x: &T) -> Enum::Variant
, or perhaps <Enum>::Variant {...}
(neither of which compile right now), not Enum::Variant {...}
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But if none of the PathSegments have the elision lifetimes injected (in src/librustc_ast_lowering/path.rs) then you get knock down errors about the type for a HirId not existing .
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
then you get knock down errors about the type for a HirId not existing
I don't recall you bringing this up, I thought it just worked while you had that arm removed? I don't see why it would, other value paths have no lifetimes injected into them at all.
☔ The latest upstream changes (presumably #68434) made this pull request unmergeable. Please resolve the merge conflicts. |
r? @varkor |
@estebank waiting on your answers to the latest questions on the above review. Thanks |
Closing this due to inactivity |
Fix #69356.
r? @petrochenkov @eddyb @Centril