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

Rollup of 6 pull requests #117590

Merged
merged 14 commits into from
Nov 4, 2023
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
20 changes: 12 additions & 8 deletions compiler/rustc_infer/src/infer/error_reporting/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2444,18 +2444,22 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
let suggestion =
if has_lifetimes { format!(" + {lt_name}") } else { format!(": {lt_name}") };
suggs.push((sp, suggestion))
} else {
let generics = self.tcx.hir().get_generics(suggestion_scope).unwrap();
} else if let Some(generics) = self.tcx.hir().get_generics(suggestion_scope) {
let pred = format!("{bound_kind}: {lt_name}");
let suggestion = format!("{} {}", generics.add_where_or_trailing_comma(), pred,);
let suggestion = format!("{} {}", generics.add_where_or_trailing_comma(), pred);
suggs.push((generics.tail_span_for_predicate_suggestion(), suggestion))
} else {
let consider = format!("{msg} `{bound_kind}: {sub}`...");
err.help(consider);
}

err.multipart_suggestion_verbose(
format!("{msg}"),
suggs,
Applicability::MaybeIncorrect, // Issue #41966
);
if !suggs.is_empty() {
err.multipart_suggestion_verbose(
format!("{msg}"),
suggs,
Applicability::MaybeIncorrect, // Issue #41966
);
}
}

err
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/infer/canonical.rs
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ pub enum CanonicalVarKind<'tcx> {
Effect,

/// A "placeholder" that represents "any const".
PlaceholderConst(ty::PlaceholderConst<'tcx>, Ty<'tcx>),
PlaceholderConst(ty::PlaceholderConst, Ty<'tcx>),
}

impl<'tcx> CanonicalVarKind<'tcx> {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/ty/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ impl<'tcx> Const<'tcx> {
#[inline]
pub fn new_placeholder(
tcx: TyCtxt<'tcx>,
placeholder: ty::PlaceholderConst<'tcx>,
placeholder: ty::PlaceholderConst,
ty: Ty<'tcx>,
) -> Const<'tcx> {
Const::new(tcx, ty::ConstKind::Placeholder(placeholder), ty)
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
type Const = ty::Const<'tcx>;
type InferConst = ty::InferConst;
type AliasConst = ty::UnevaluatedConst<'tcx>;
type PlaceholderConst = ty::PlaceholderConst<'tcx>;
type PlaceholderConst = ty::PlaceholderConst;
type ParamConst = ty::ParamConst;
type BoundConst = ty::BoundVar;
type ValueConst = ty::ValTree<'tcx>;
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1527,7 +1527,7 @@ pub struct BoundConst<'tcx> {
pub ty: Ty<'tcx>,
}

pub type PlaceholderConst<'tcx> = Placeholder<BoundVar>;
pub type PlaceholderConst = Placeholder<BoundVar>;

/// When type checking, we use the `ParamEnv` to track
/// details about the set of where-clauses that are in scope at this
Expand Down
10 changes: 5 additions & 5 deletions compiler/rustc_trait_selection/src/traits/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -783,7 +783,7 @@ pub struct BoundVarReplacer<'me, 'tcx> {
// the `var` (but we *could* bring that into scope if we were to track them as we pass them).
mapped_regions: BTreeMap<ty::PlaceholderRegion, ty::BoundRegion>,
mapped_types: BTreeMap<ty::PlaceholderType, ty::BoundTy>,
mapped_consts: BTreeMap<ty::PlaceholderConst<'tcx>, ty::BoundVar>,
mapped_consts: BTreeMap<ty::PlaceholderConst, ty::BoundVar>,
// The current depth relative to *this* folding, *not* the entire normalization. In other words,
// the depth of binders we've passed here.
current_index: ty::DebruijnIndex,
Expand Down Expand Up @@ -843,11 +843,11 @@ impl<'me, 'tcx> BoundVarReplacer<'me, 'tcx> {
T,
BTreeMap<ty::PlaceholderRegion, ty::BoundRegion>,
BTreeMap<ty::PlaceholderType, ty::BoundTy>,
BTreeMap<ty::PlaceholderConst<'tcx>, ty::BoundVar>,
BTreeMap<ty::PlaceholderConst, ty::BoundVar>,
) {
let mapped_regions: BTreeMap<ty::PlaceholderRegion, ty::BoundRegion> = BTreeMap::new();
let mapped_types: BTreeMap<ty::PlaceholderType, ty::BoundTy> = BTreeMap::new();
let mapped_consts: BTreeMap<ty::PlaceholderConst<'tcx>, ty::BoundVar> = BTreeMap::new();
let mapped_consts: BTreeMap<ty::PlaceholderConst, ty::BoundVar> = BTreeMap::new();

let mut replacer = BoundVarReplacer {
infcx,
Expand Down Expand Up @@ -966,7 +966,7 @@ pub struct PlaceholderReplacer<'me, 'tcx> {
infcx: &'me InferCtxt<'tcx>,
mapped_regions: BTreeMap<ty::PlaceholderRegion, ty::BoundRegion>,
mapped_types: BTreeMap<ty::PlaceholderType, ty::BoundTy>,
mapped_consts: BTreeMap<ty::PlaceholderConst<'tcx>, ty::BoundVar>,
mapped_consts: BTreeMap<ty::PlaceholderConst, ty::BoundVar>,
universe_indices: &'me [Option<ty::UniverseIndex>],
current_index: ty::DebruijnIndex,
}
Expand All @@ -976,7 +976,7 @@ impl<'me, 'tcx> PlaceholderReplacer<'me, 'tcx> {
infcx: &'me InferCtxt<'tcx>,
mapped_regions: BTreeMap<ty::PlaceholderRegion, ty::BoundRegion>,
mapped_types: BTreeMap<ty::PlaceholderType, ty::BoundTy>,
mapped_consts: BTreeMap<ty::PlaceholderConst<'tcx>, ty::BoundVar>,
mapped_consts: BTreeMap<ty::PlaceholderConst, ty::BoundVar>,
universe_indices: &'me [Option<ty::UniverseIndex>],
value: T,
) -> T {
Expand Down
4 changes: 2 additions & 2 deletions library/core/src/convert/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ pub const fn identity<T>(x: T) -> T {
///
/// [dereferenceable types]: core::ops::Deref
/// [pointed-to value]: core::ops::Deref::Target
/// ['`Deref` coercion']: core::ops::Deref#more-on-deref-coercion
/// ['`Deref` coercion']: core::ops::Deref#deref-coercion
///
/// ```
/// let x = Box::new(5i32);
Expand Down Expand Up @@ -244,7 +244,7 @@ pub trait AsRef<T: ?Sized> {
///
/// [mutably dereferenceable types]: core::ops::DerefMut
/// [pointed-to value]: core::ops::Deref::Target
/// ['`Deref` coercion']: core::ops::DerefMut#more-on-deref-coercion
/// ['`Deref` coercion']: core::ops::DerefMut#mutable-deref-coercion
///
/// ```
/// let mut x = Box::new(5i32);
Expand Down
162 changes: 123 additions & 39 deletions library/core/src/ops/deref.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,40 +3,107 @@
/// In addition to being used for explicit dereferencing operations with the
/// (unary) `*` operator in immutable contexts, `Deref` is also used implicitly
/// by the compiler in many circumstances. This mechanism is called
/// ['`Deref` coercion'][more]. In mutable contexts, [`DerefMut`] is used.
/// ["`Deref` coercion"][coercion]. In mutable contexts, [`DerefMut`] is used and
/// mutable deref coercion similarly occurs.
///
/// Implementing `Deref` for smart pointers makes accessing the data behind them
/// convenient, which is why they implement `Deref`. On the other hand, the
/// rules regarding `Deref` and [`DerefMut`] were designed specifically to
/// accommodate smart pointers. Because of this, **`Deref` should only be
/// implemented for smart pointers** to avoid confusion.
/// **Warning:** Deref coercion is a powerful language feature which has
/// far-reaching implications for every type that implements `Deref`. The
/// compiler will silently insert calls to `Deref::deref`. For this reason, one
/// should be careful about implementing `Deref` and only do so when deref
/// coercion is desirable. See [below][implementing] for advice on when this is
/// typically desirable or undesirable.
///
/// For similar reasons, **this trait should never fail**. Failure during
/// dereferencing can be extremely confusing when `Deref` is invoked implicitly.
/// Types that implement `Deref` or `DerefMut` are often called "smart
/// pointers" and the mechanism of deref coercion has been specifically designed
/// to facilitate the pointer-like behaviour that name suggests. Often, the
/// purpose of a "smart pointer" type is to change the ownership semantics
/// of a contained value (for example, [`Rc`][rc] or [`Cow`][cow]) or the
/// storage semantics of a contained value (for example, [`Box`][box]).
///
/// Violating these requirements is a logic error. The behavior resulting from a logic error is not
/// specified, but users of the trait must ensure that such logic errors do *not* result in
/// undefined behavior. This means that `unsafe` code **must not** rely on the correctness of this
/// method.
/// # Deref coercion
///
/// # More on `Deref` coercion
/// If `T` implements `Deref<Target = U>`, and `v` is a value of type `T`, then:
///
/// If `T` implements `Deref<Target = U>`, and `x` is a value of type `T`, then:
///
/// * In immutable contexts, `*x` (where `T` is neither a reference nor a raw pointer)
/// is equivalent to `*Deref::deref(&x)`.
/// * In immutable contexts, `*v` (where `T` is neither a reference nor a raw
/// pointer) is equivalent to `*Deref::deref(&v)`.
/// * Values of type `&T` are coerced to values of type `&U`
/// * `T` implicitly implements all the (immutable) methods of the type `U`.
/// * `T` implicitly implements all the methods of the type `U` which take the
/// `&self` receiver.
///
/// For more details, visit [the chapter in *The Rust Programming Language*][book]
/// as well as the reference sections on [the dereference operator][ref-deref-op],
/// [method resolution] and [type coercions].
/// [method resolution], and [type coercions].
///
/// # When to implement `Deref` or `DerefMut`
///
/// The same advice applies to both deref traits. In general, deref traits
/// **should** be implemented if:
///
/// 1. a value of the type transparently behaves like a value of the target
/// type;
/// 1. the implementation of the deref function is cheap; and
/// 1. users of the type will not be surprised by any deref coercion behaviour.
///
/// In general, deref traits **should not** be implemented if:
///
/// 1. the deref implementations could fail unexpectedly; or
/// 1. the type has methods that are likely to collide with methods on the
/// target type; or
/// 1. committing to deref coercion as part of the public API is not desirable.
///
/// Note that there's a large difference between implementing deref traits
/// generically over many target types, and doing so only for specific target
/// types.
///
/// Generic implementations, such as for [`Box<T>`][box] (which is generic over
/// every type and dereferences to `T`) should be careful to provide few or no
/// methods, since the target type is unknown and therefore every method could
/// collide with one on the target type, causing confusion for users.
/// `impl<T> Box<T>` has no methods (though several associated functions),
/// partly for this reason.
///
/// Specific implementations, such as for [`String`][string] (whose `Deref`
/// implementation has `Target = str`) can have many methods, since avoiding
/// collision is much easier. `String` and `str` both have many methods, and
/// `String` additionally behaves as if it has every method of `str` because of
/// deref coercion. The implementing type may also be generic while the
/// implementation is still specific in this sense; for example, [`Vec<T>`][vec]
/// dereferences to `[T]`, so methods of `T` are not applicable.
///
/// Consider also that deref coericion means that deref traits are a much larger
/// part of a type's public API than any other trait as it is implicitly called
/// by the compiler. Therefore, it is advisable to consider whether this is
/// something you are comfortable supporting as a public API.
///
/// The [`AsRef`] and [`Borrow`][core::borrow::Borrow] traits have very similar
/// signatures to `Deref`. It may be desirable to implement either or both of
/// these, whether in addition to or rather than deref traits. See their
/// documentation for details.
///
/// # Fallibility
///
/// **This trait's method should never unexpectedly fail**. Deref coercion means
/// the compiler will often insert calls to `Deref::deref` implicitly. Failure
/// during dereferencing can be extremely confusing when `Deref` is invoked
/// implicitly. In the majority of uses it should be infallible, though it may
/// be acceptable to panic if the type is misused through programmer error, for
/// example.
///
/// However, infallibility is not enforced and therefore not guaranteed.
/// As such, `unsafe` code should not rely on infallibility in general for
/// soundness.
///
/// [book]: ../../book/ch15-02-deref.html
/// [more]: #more-on-deref-coercion
/// [coercion]: #deref-coercion
/// [implementing]: #when-to-implement-deref-or-derefmut
/// [ref-deref-op]: ../../reference/expressions/operator-expr.html#the-dereference-operator
/// [method resolution]: ../../reference/expressions/method-call-expr.html
/// [type coercions]: ../../reference/type-coercions.html
/// [box]: ../../alloc/boxed/struct.Box.html
/// [string]: ../../alloc/string/struct.String.html
/// [vec]: ../../alloc/vec/struct.Vec.html
/// [rc]: ../../alloc/rc/struct.Rc.html
/// [cow]: ../../alloc/borrow/enum.Cow.html
///
/// # Examples
///
Expand Down Expand Up @@ -107,42 +174,59 @@ impl<T: ?Sized> Deref for &mut T {
/// In addition to being used for explicit dereferencing operations with the
/// (unary) `*` operator in mutable contexts, `DerefMut` is also used implicitly
/// by the compiler in many circumstances. This mechanism is called
/// ['`Deref` coercion'][more]. In immutable contexts, [`Deref`] is used.
///
/// Implementing `DerefMut` for smart pointers makes mutating the data behind
/// them convenient, which is why they implement `DerefMut`. On the other hand,
/// the rules regarding [`Deref`] and `DerefMut` were designed specifically to
/// accommodate smart pointers. Because of this, **`DerefMut` should only be
/// implemented for smart pointers** to avoid confusion.
/// ["mutable deref coercion"][coercion]. In immutable contexts, [`Deref`] is used.
///
/// For similar reasons, **this trait should never fail**. Failure during
/// dereferencing can be extremely confusing when `DerefMut` is invoked
/// implicitly.
/// **Warning:** Deref coercion is a powerful language feature which has
/// far-reaching implications for every type that implements `DerefMut`. The
/// compiler will silently insert calls to `DerefMut::deref_mut`. For this
/// reason, one should be careful about implementing `DerefMut` and only do so
/// when mutable deref coercion is desirable. See [the `Deref` docs][implementing]
/// for advice on when this is typically desirable or undesirable.
///
/// Violating these requirements is a logic error. The behavior resulting from a logic error is not
/// specified, but users of the trait must ensure that such logic errors do *not* result in
/// undefined behavior. This means that `unsafe` code **must not** rely on the correctness of this
/// method.
/// Types that implement `DerefMut` or `Deref` are often called "smart
/// pointers" and the mechanism of deref coercion has been specifically designed
/// to facilitate the pointer-like behaviour that name suggests. Often, the
/// purpose of a "smart pointer" type is to change the ownership semantics
/// of a contained value (for example, [`Rc`][rc] or [`Cow`][cow]) or the
/// storage semantics of a contained value (for example, [`Box`][box]).
///
/// # More on `Deref` coercion
/// # Mutable deref coercion
///
/// If `T` implements `DerefMut<Target = U>`, and `x` is a value of type `T`,
/// If `T` implements `DerefMut<Target = U>`, and `v` is a value of type `T`,
/// then:
///
/// * In mutable contexts, `*x` (where `T` is neither a reference nor a raw pointer)
/// is equivalent to `*DerefMut::deref_mut(&mut x)`.
/// * In mutable contexts, `*v` (where `T` is neither a reference nor a raw pointer)
/// is equivalent to `*DerefMut::deref_mut(&mut v)`.
/// * Values of type `&mut T` are coerced to values of type `&mut U`
/// * `T` implicitly implements all the (mutable) methods of the type `U`.
///
/// For more details, visit [the chapter in *The Rust Programming Language*][book]
/// as well as the reference sections on [the dereference operator][ref-deref-op],
/// [method resolution] and [type coercions].
///
/// # Fallibility
///
/// **This trait's method should never unexpectedly fail**. Deref coercion means
/// the compiler will often insert calls to `DerefMut::deref_mut` implicitly.
/// Failure during dereferencing can be extremely confusing when `DerefMut` is
/// invoked implicitly. In the majority of uses it should be infallible, though
/// it may be acceptable to panic if the type is misused through programmer
/// error, for example.
///
/// However, infallibility is not enforced and therefore not guaranteed.
/// As such, `unsafe` code should not rely on infallibility in general for
/// soundness.
///
/// [book]: ../../book/ch15-02-deref.html
/// [more]: #more-on-deref-coercion
/// [coercion]: #mutable-deref-coercion
/// [implementing]: Deref#when-to-implement-deref-or-derefmut
/// [ref-deref-op]: ../../reference/expressions/operator-expr.html#the-dereference-operator
/// [method resolution]: ../../reference/expressions/method-call-expr.html
/// [type coercions]: ../../reference/type-coercions.html
/// [box]: ../../alloc/boxed/struct.Box.html
/// [string]: ../../alloc/string/struct.String.html
/// [rc]: ../../alloc/rc/struct.Rc.html
/// [cow]: ../../alloc/borrow/enum.Cow.html
///
/// # Examples
///
Expand Down
Loading
Loading