Skip to content

Commit

Permalink
Auto merge of #93938 - BoxyUwU:fix_res_self_ty, r=lcnr
Browse files Browse the repository at this point in the history
Make `Res::SelfTy` a struct variant and update docs

I found pattern matching on a `(Option<DefId>, Option<(DefId, bool)>)` to not be super readable, additionally the doc comments on the types in a tuple variant aren't visible anywhere at use sites as far as I can tell (using rust analyzer + vscode)

The docs incorrectly assumed that the `DefId` in `Option<(DefId, bool)>` would only ever be for an impl item and I also found the code examples to be somewhat unclear about which `DefId` was being talked about.

r? `@lcnr` since you reviewed the last PR changing these docs
  • Loading branch information
bors committed Feb 14, 2022
2 parents 902e590 + 48a79bc commit b321742
Show file tree
Hide file tree
Showing 27 changed files with 102 additions and 83 deletions.
74 changes: 41 additions & 33 deletions compiler/rustc_hir/src/def.rs
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)>,
},
/// 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
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
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
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
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
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
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
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
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
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
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
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
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
Expand Up @@ -2811,7 +2811,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
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
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
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
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

0 comments on commit b321742

Please sign in to comment.