Skip to content

Make Res::SelfTy a struct variant and update docs #93938

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

Merged
merged 4 commits into from
Feb 14, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 41 additions & 33 deletions compiler/rustc_hir/src/def.rs
Original file line number Diff line number Diff line change
Expand Up @@ -266,59 +266,67 @@ pub enum Res<Id = hir::HirId> {
///
/// **Belongs to the type namespace.**
PrimTy(hir::PrimTy),
/// The `Self` type, optionally with the trait it is associated with
/// and optionally with the [`DefId`] of the impl it is associated with.
/// The `Self` type, optionally with the [`DefId`] of the trait it belongs to and
/// optionally with the [`DefId`] of the item introducing the `Self` type alias.
///
/// **Belongs to the type namespace.**
///
/// For example, the `Self` in
///
/// Examples:
/// ```
/// struct Bar(Box<Self>);
/// // `Res::SelfTy { trait_: None, alias_of: Some(Bar) }`
///
/// trait Foo {
/// fn foo() -> Box<Self>;
/// // `Res::SelfTy { trait_: Some(Foo), alias_of: None }`
/// }
/// ```
///
/// would have the [`DefId`] of `Foo` associated with it. The `Self` in
///
/// ```
/// struct Bar;
///
/// impl Bar {
/// fn new() -> Self { Bar }
/// fn blah() {
/// let _: Self;
/// // `Res::SelfTy { trait_: None, alias_of: Some(::{impl#0}) }`
/// }
/// }
/// ```
///
/// would have the [`DefId`] of the impl associated with it. Finally, the `Self` in
///
/// ```
/// impl Foo for Bar {
/// fn foo() -> Box<Self> { Box::new(Bar) }
/// fn foo() -> Box<Self> {
/// // `Res::SelfTy { trait_: Some(Foo), alias_of: Some(::{impl#1}) }`
/// let _: Self;
/// // `Res::SelfTy { trait_: Some(Foo), alias_of: Some(::{impl#1}) }`
///
/// todo!()
/// }
/// }
/// ```
///
/// would have both the [`DefId`] of `Foo` and the [`DefId`] of the impl
/// associated with it.
///
/// *See also [`Res::SelfCtor`].*
///
/// -----
///
/// HACK(min_const_generics): impl self types also have an optional requirement to **not** mention
/// HACK(min_const_generics): self types also have an optional requirement to **not** mention
/// any generic parameters to allow the following with `min_const_generics`:
/// ```
/// impl Foo { fn test() -> [u8; std::mem::size_of::<Self>()] { todo!() } }
///
/// struct Bar([u8; baz::<Self>()]);
/// const fn baz<T>() -> usize { 10 }
/// ```
/// We do however allow `Self` in repeat expression even if it is generic to not break code
/// which already works on stable while causing the `const_evaluatable_unchecked` future compat lint.
///
/// FIXME(generic_const_exprs): Remove this bodge once that feature is stable.
SelfTy(
/// Optionally, the trait associated with this `Self` type.
Option<DefId>,
/// Optionally, the impl associated with this `Self` type.
Option<(DefId, bool)>,
),
/// which already works on stable while causing the `const_evaluatable_unchecked` future compat lint:
/// ```
/// fn foo<T>() {
/// let _bar = [1_u8; std::mem::size_of::<*mut T>()];
/// }
/// ```
// FIXME(generic_const_exprs): Remove this bodge once that feature is stable.
SelfTy {
/// The trait this `Self` is a generic arg for.
trait_: Option<DefId>,
/// The item introducing the `Self` type alias. Can be used in the `type_of` query
/// to get the underlying type. Additionally whether the `Self` type is disallowed
/// from mentioning generics (i.e. when used in an anonymous constant).
alias_to: Option<(DefId, bool)>,
Comment on lines +323 to +328
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for naming these fields and improving the docs! I had a lot of trouble understanding this when I wrote the current version of the docs.

Why is alias_to an Option, though? When would it be None?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

inside of a trait def alias_to is None

trait Foo {
    fn foo() -> Self;
    // `Res::SelfTy { trait_: Some(Foo), alias_to: None }`
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, makes sense, thanks :)

Could you add a comment about that?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops, just realized this was already merged 😅

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a comment about this if you look at the examples above the SelfTy variant

Copy link
Member

@camelid camelid Feb 17, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! That covers it.

},
/// A tool attribute module; e.g., the `rustfmt` in `#[rustfmt::skip]`.
///
/// **Belongs to the type namespace.**
Expand Down Expand Up @@ -550,7 +558,7 @@ impl<Id> Res<Id> {

Res::Local(..)
| Res::PrimTy(..)
| Res::SelfTy(..)
| Res::SelfTy { .. }
| Res::SelfCtor(..)
| Res::ToolMod
| Res::NonMacroAttr(..)
Expand All @@ -573,7 +581,7 @@ impl<Id> Res<Id> {
Res::SelfCtor(..) => "self constructor",
Res::PrimTy(..) => "builtin type",
Res::Local(..) => "local variable",
Res::SelfTy(..) => "self type",
Res::SelfTy { .. } => "self type",
Res::ToolMod => "tool module",
Res::NonMacroAttr(attr_kind) => attr_kind.descr(),
Res::Err => "unresolved item",
Expand All @@ -596,7 +604,7 @@ impl<Id> Res<Id> {
Res::SelfCtor(id) => Res::SelfCtor(id),
Res::PrimTy(id) => Res::PrimTy(id),
Res::Local(id) => Res::Local(map(id)),
Res::SelfTy(a, b) => Res::SelfTy(a, b),
Res::SelfTy { trait_, alias_to } => Res::SelfTy { trait_, alias_to },
Res::ToolMod => Res::ToolMod,
Res::NonMacroAttr(attr_kind) => Res::NonMacroAttr(attr_kind),
Res::Err => Res::Err,
Expand All @@ -620,7 +628,7 @@ impl<Id> Res<Id> {
pub fn ns(&self) -> Option<Namespace> {
match self {
Res::Def(kind, ..) => kind.ns(),
Res::PrimTy(..) | Res::SelfTy(..) | Res::ToolMod => Some(Namespace::TypeNS),
Res::PrimTy(..) | Res::SelfTy { .. } | Res::ToolMod => Some(Namespace::TypeNS),
Res::SelfCtor(..) | Res::Local(..) => Some(Namespace::ValueNS),
Res::NonMacroAttr(..) => Some(Namespace::MacroNS),
Res::Err => None,
Expand Down
5 changes: 2 additions & 3 deletions compiler/rustc_hir/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -640,9 +640,8 @@ impl<'hir> WhereBoundPredicate<'hir> {
_ => return false,
};
match path.res {
Res::Def(DefKind::TyParam, def_id) | Res::SelfTy(Some(def_id), None) => {
def_id == param_def_id
}
Res::Def(DefKind::TyParam, def_id)
| Res::SelfTy { trait_: Some(def_id), alias_to: None } => def_id == param_def_id,
_ => false,
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,8 @@ impl<'tcx> Visitor<'tcx> for TypeParamSpanVisitor<'tcx> {
.map(|res| {
matches!(
res,
Res::SelfTy(_, _) | Res::Def(hir::def::DefKind::TyParam, _)
Res::SelfTy { trait_: _, alias_to: _ }
| Res::Def(hir::def::DefKind::TyParam, _)
)
})
.unwrap_or(false) =>
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_lint/src/internal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ fn is_ty_or_ty_ctxt(cx: &LateContext<'_>, ty: &Ty<'_>) -> Option<String> {
}
}
// Only lint on `&Ty` and `&TyCtxt` if it is used outside of a trait.
Res::SelfTy(None, Some((did, _))) => {
Res::SelfTy { trait_: None, alias_to: Some((did, _)) } => {
if let ty::Adt(adt, substs) = cx.tcx.type_of(did).kind() {
if let Some(name @ (sym::Ty | sym::TyCtxt)) =
cx.tcx.get_diagnostic_name(adt.did)
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_lint/src/pass_by_value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ fn path_for_pass_by_value(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> Option<Stri
let path_segment = path.segments.last().unwrap();
return Some(format!("{}{}", name, gen_args(cx, path_segment)));
}
Res::SelfTy(None, Some((did, _))) => {
Res::SelfTy { trait_: None, alias_to: Some((did, _)) } => {
if let ty::Adt(adt, substs) = cx.tcx.type_of(did).kind() {
if cx.tcx.has_attr(adt.did, sym::rustc_pass_by_value) {
return Some(cx.tcx.def_path_str_with_substs(adt.did, substs));
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/ty/adt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -395,7 +395,7 @@ impl<'tcx> AdtDef {
| Res::Def(DefKind::Union, _)
| Res::Def(DefKind::TyAlias, _)
| Res::Def(DefKind::AssocTy, _)
| Res::SelfTy(..)
| Res::SelfTy { .. }
| Res::SelfCtor(..) => self.non_enum_variant(),
_ => bug!("unexpected res {:?} in variant_of_res", res),
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_mir_build/src/thir/pattern/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -417,7 +417,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
| DefKind::AssocTy,
_,
)
| Res::SelfTy(..)
| Res::SelfTy { .. }
| Res::SelfCtor(..) => PatKind::Leaf { subpatterns },
_ => {
let pattern_error = match res {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_passes/src/dead.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
self.check_def_id(variant_id);
}
}
Res::SelfTy(t, i) => {
Res::SelfTy { trait_: t, alias_to: i } => {
if let Some(t) = t {
self.check_def_id(t);
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_privacy/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1350,7 +1350,7 @@ struct ObsoleteCheckTypeForPrivatenessVisitor<'a, 'b, 'tcx> {
impl<'a, 'tcx> ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> {
fn path_is_private_type(&self, path: &hir::Path<'_>) -> bool {
let did = match path.res {
Res::PrimTy(..) | Res::SelfTy(..) | Res::Err => return false,
Res::PrimTy(..) | Res::SelfTy { .. } | Res::Err => return false,
res => res.def_id(),
};

Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_resolve/src/build_reduced_graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -991,7 +991,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
_,
)
| Res::Local(..)
| Res::SelfTy(..)
| Res::SelfTy { .. }
| Res::SelfCtor(..)
| Res::Err => bug!("unexpected resolution: {:?}", res),
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_resolve/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ impl<'a> Resolver<'a> {

let sm = self.session.source_map();
match outer_res {
Res::SelfTy(maybe_trait_defid, maybe_impl_defid) => {
Res::SelfTy { trait_: maybe_trait_defid, alias_to: maybe_impl_defid } => {
if let Some(impl_span) =
maybe_impl_defid.and_then(|(def_id, _)| self.opt_span(def_id))
{
Expand Down
27 changes: 16 additions & 11 deletions compiler/rustc_resolve/src/late.rs
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ impl<'a> PathSource<'a> {
| DefKind::ForeignTy,
_,
) | Res::PrimTy(..)
| Res::SelfTy(..)
| Res::SelfTy { .. }
),
PathSource::Trait(AliasPossibility::No) => matches!(res, Res::Def(DefKind::Trait, _)),
PathSource::Trait(AliasPossibility::Maybe) => {
Expand Down Expand Up @@ -326,7 +326,7 @@ impl<'a> PathSource<'a> {
| DefKind::TyAlias
| DefKind::AssocTy,
_,
) | Res::SelfTy(..)
) | Res::SelfTy { .. }
),
PathSource::TraitItem(ns) => match res {
Res::Def(DefKind::AssocConst | DefKind::AssocFn, _) if ns == ValueNS => true,
Expand Down Expand Up @@ -911,9 +911,12 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
self.with_current_self_item(item, |this| {
this.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| {
let item_def_id = this.r.local_def_id(item.id).to_def_id();
this.with_self_rib(Res::SelfTy(None, Some((item_def_id, false))), |this| {
visit::walk_item(this, item);
});
this.with_self_rib(
Res::SelfTy { trait_: None, alias_to: Some((item_def_id, false)) },
|this| {
visit::walk_item(this, item);
},
);
});
});
}
Expand Down Expand Up @@ -999,8 +1002,8 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
self.compute_num_lifetime_params(item.id, generics);
// Create a new rib for the trait-wide type parameters.
self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| {
let local_def_id = this.r.local_def_id(item.id).to_def_id();
this.with_self_rib(Res::SelfTy(Some(local_def_id), None), |this| {
let def = this.r.local_def_id(item.id).to_def_id();
this.with_self_rib(Res::SelfTy { trait_: Some(def), alias_to: None }, |this| {
this.visit_generics(generics);
walk_list!(this, visit_param_bound, bounds);

Expand Down Expand Up @@ -1051,8 +1054,8 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
self.compute_num_lifetime_params(item.id, generics);
// Create a new rib for the trait-wide type parameters.
self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| {
let local_def_id = this.r.local_def_id(item.id).to_def_id();
this.with_self_rib(Res::SelfTy(Some(local_def_id), None), |this| {
let def = this.r.local_def_id(item.id).to_def_id();
this.with_self_rib(Res::SelfTy { trait_: Some(def), alias_to: None }, |this| {
this.visit_generics(generics);
walk_list!(this, visit_param_bound, bounds);
});
Expand Down Expand Up @@ -1296,7 +1299,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
// If applicable, create a rib for the type parameters.
self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| {
// Dummy self type for better errors if `Self` is used in the trait path.
this.with_self_rib(Res::SelfTy(None, None), |this| {
this.with_self_rib(Res::SelfTy { trait_: None, alias_to: None }, |this| {
// Resolve the trait reference, if necessary.
this.with_optional_trait_ref(opt_trait_reference.as_ref(), |this, trait_id| {
let item_def_id = this.r.local_def_id(item_id);
Expand All @@ -1307,7 +1310,9 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
}

let item_def_id = item_def_id.to_def_id();
this.with_self_rib(Res::SelfTy(trait_id, Some((item_def_id, false))), |this| {
let res =
Res::SelfTy { trait_: trait_id, alias_to: Some((item_def_id, false)) };
this.with_self_rib(res, |this| {
if let Some(trait_ref) = opt_trait_reference.as_ref() {
// Resolve type arguments in the trait path.
visit::walk_trait_ref(this, trait_ref);
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_resolve/src/late/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1189,7 +1189,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
Applicability::HasPlaceholders,
);
}
(Res::SelfTy(..), _) if ns == ValueNS => {
(Res::SelfTy { .. }, _) if ns == ValueNS => {
err.span_label(span, fallback_label);
err.note("can't use `Self` as a constructor, you must use the implemented struct");
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_resolve/src/late/lifetimes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2793,7 +2793,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
// Look for `self: &'a Self` - also desugared from `&'a self`,
// and if that matches, use it for elision and return early.
fn is_self_ty(&self, res: Res) -> bool {
if let Res::SelfTy(..) = res {
if let Res::SelfTy { .. } = res {
return true;
}

Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_resolve/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2784,7 +2784,7 @@ impl<'a> Resolver<'a> {
return Res::Err;
}
}
Res::Def(DefKind::TyParam, _) | Res::SelfTy(..) => {
Res::Def(DefKind::TyParam, _) | Res::SelfTy { .. } => {
for rib in ribs {
let has_generic_params: HasGenericParams = match rib.kind {
NormalRibKind
Expand All @@ -2804,8 +2804,8 @@ impl<'a> Resolver<'a> {
// HACK(min_const_generics): If we encounter `Self` in an anonymous constant
// we can't easily tell if it's generic at this stage, so we instead remember
// this and then enforce the self type to be concrete later on.
if let Res::SelfTy(trait_def, Some((impl_def, _))) = res {
res = Res::SelfTy(trait_def, Some((impl_def, true)));
if let Res::SelfTy { trait_, alias_to: Some((def, _)) } = res {
res = Res::SelfTy { trait_, alias_to: Some((def, true)) }
} else {
if record_used {
self.report_error(
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_save_analysis/src/dump_visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -921,7 +921,7 @@ impl<'tcx> DumpVisitor<'tcx> {
| HirDefKind::AssocTy,
_,
)
| Res::SelfTy(..) => {
| Res::SelfTy { .. } => {
self.dump_path_segment_ref(id, &hir::PathSegment::from_ident(ident));
}
def => {
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_save_analysis/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -749,7 +749,7 @@ impl<'tcx> SaveContext<'tcx> {
_,
)
| Res::PrimTy(..)
| Res::SelfTy(..)
| Res::SelfTy { .. }
| Res::ToolMod
| Res::NonMacroAttr(..)
| Res::SelfCtor(..)
Expand Down Expand Up @@ -814,7 +814,7 @@ impl<'tcx> SaveContext<'tcx> {

fn lookup_def_id(&self, ref_id: hir::HirId) -> Option<DefId> {
match self.get_path_res(ref_id) {
Res::PrimTy(_) | Res::SelfTy(..) | Res::Err => None,
Res::PrimTy(_) | Res::SelfTy { .. } | Res::Err => None,
def => def.opt_def_id(),
}
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_save_analysis/src/sig.rs
Original file line number Diff line number Diff line change
Expand Up @@ -573,7 +573,7 @@ impl<'hir> Sig for hir::Path<'hir> {
let res = scx.get_path_res(id.ok_or("Missing id for Path")?);

let (name, start, end) = match res {
Res::PrimTy(..) | Res::SelfTy(..) | Res::Err => {
Res::PrimTy(..) | Res::SelfTy { .. } | Res::Err => {
return Ok(Signature { text: path_to_string(self), defs: vec![], refs: vec![] });
}
Res::Def(DefKind::AssocConst | DefKind::Variant | DefKind::Ctor(..), _) => {
Expand Down
Loading