mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 00:03:43 +00:00
Auto merge of #132919 - matthiaskrgr:rollup-ogghyvp, r=matthiaskrgr
Rollup of 7 pull requests Successful merges: - #120077 (Add Set entry API ) - #132144 (Arbitrary self types v2: (unused) Receiver trait) - #132297 (Document some `check_expr` methods, and other misc `hir_typeck` tweaks) - #132820 (Add a default implementation for CodegenBackend::link) - #132881 (triagebot: Autolabel rustdoc book) - #132912 (Simplify some places that deal with generic parameter defaults) - #132916 (Unvacation fmease) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
67f21277cd
@ -1,12 +0,0 @@
|
||||
use rustc_codegen_ssa::back::archive::{
|
||||
ArArchiveBuilder, ArchiveBuilder, ArchiveBuilderBuilder, DEFAULT_OBJECT_READER,
|
||||
};
|
||||
use rustc_session::Session;
|
||||
|
||||
pub(crate) struct ArArchiveBuilderBuilder;
|
||||
|
||||
impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder {
|
||||
fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box<dyn ArchiveBuilder + 'a> {
|
||||
Box::new(ArArchiveBuilder::new(sess, &DEFAULT_OBJECT_READER))
|
||||
}
|
||||
}
|
@ -43,7 +43,6 @@ use rustc_codegen_ssa::CodegenResults;
|
||||
use rustc_codegen_ssa::back::versioned_llvm_target;
|
||||
use rustc_codegen_ssa::traits::CodegenBackend;
|
||||
use rustc_data_structures::profiling::SelfProfilerRef;
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
use rustc_metadata::EncodedMetadata;
|
||||
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
|
||||
use rustc_session::Session;
|
||||
@ -56,7 +55,6 @@ use crate::prelude::*;
|
||||
mod abi;
|
||||
mod allocator;
|
||||
mod analyze;
|
||||
mod archive;
|
||||
mod base;
|
||||
mod cast;
|
||||
mod codegen_i128;
|
||||
@ -249,17 +247,6 @@ impl CodegenBackend for CraneliftCodegenBackend {
|
||||
self.config.borrow().as_ref().unwrap(),
|
||||
)
|
||||
}
|
||||
|
||||
fn link(
|
||||
&self,
|
||||
sess: &Session,
|
||||
codegen_results: CodegenResults,
|
||||
outputs: &OutputFilenames,
|
||||
) -> Result<(), ErrorGuaranteed> {
|
||||
use rustc_codegen_ssa::back::link::link_binary;
|
||||
|
||||
link_binary(sess, &crate::archive::ArArchiveBuilderBuilder, &codegen_results, outputs)
|
||||
}
|
||||
}
|
||||
|
||||
fn target_triple(sess: &Session) -> target_lexicon::Triple {
|
||||
|
@ -1,25 +0,0 @@
|
||||
use std::path::Path;
|
||||
|
||||
use rustc_codegen_ssa::back::archive::{
|
||||
ArArchiveBuilder, ArchiveBuilder, ArchiveBuilderBuilder, DEFAULT_OBJECT_READER,
|
||||
ImportLibraryItem,
|
||||
};
|
||||
use rustc_session::Session;
|
||||
|
||||
pub(crate) struct ArArchiveBuilderBuilder;
|
||||
|
||||
impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder {
|
||||
fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box<dyn ArchiveBuilder + 'a> {
|
||||
Box::new(ArArchiveBuilder::new(sess, &DEFAULT_OBJECT_READER))
|
||||
}
|
||||
|
||||
fn create_dll_import_lib(
|
||||
&self,
|
||||
_sess: &Session,
|
||||
_lib_name: &str,
|
||||
_items: Vec<ImportLibraryItem>,
|
||||
_output_path: &Path,
|
||||
) {
|
||||
unimplemented!("creating dll imports is not yet supported");
|
||||
}
|
||||
}
|
@ -58,7 +58,6 @@ extern crate rustc_driver;
|
||||
|
||||
mod abi;
|
||||
mod allocator;
|
||||
mod archive;
|
||||
mod asm;
|
||||
mod attributes;
|
||||
mod back;
|
||||
@ -103,7 +102,7 @@ use rustc_codegen_ssa::traits::{CodegenBackend, ExtraBackendMethods, WriteBacken
|
||||
use rustc_codegen_ssa::{CodegenResults, CompiledModule, ModuleCodegen};
|
||||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_data_structures::sync::IntoDynSyncSend;
|
||||
use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed};
|
||||
use rustc_errors::DiagCtxtHandle;
|
||||
use rustc_metadata::EncodedMetadata;
|
||||
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
@ -261,17 +260,6 @@ impl CodegenBackend for GccCodegenBackend {
|
||||
.join(sess)
|
||||
}
|
||||
|
||||
fn link(
|
||||
&self,
|
||||
sess: &Session,
|
||||
codegen_results: CodegenResults,
|
||||
outputs: &OutputFilenames,
|
||||
) -> Result<(), ErrorGuaranteed> {
|
||||
use rustc_codegen_ssa::back::link::link_binary;
|
||||
|
||||
link_binary(sess, &crate::archive::ArArchiveBuilderBuilder, &codegen_results, outputs)
|
||||
}
|
||||
|
||||
fn target_features(&self, sess: &Session, allow_unstable: bool) -> Vec<Symbol> {
|
||||
target_features(sess, allow_unstable, &self.target_info)
|
||||
}
|
||||
|
@ -382,7 +382,7 @@ impl CodegenBackend for LlvmCodegenBackend {
|
||||
|
||||
// Run the linker on any artifacts that resulted from the LLVM run.
|
||||
// This should produce either a finished executable or library.
|
||||
link_binary(sess, &LlvmArchiveBuilderBuilder, &codegen_results, outputs)
|
||||
link_binary(sess, &LlvmArchiveBuilderBuilder, codegen_results, outputs)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -304,6 +304,14 @@ pub trait ArchiveBuilder {
|
||||
fn build(self: Box<Self>, output: &Path) -> bool;
|
||||
}
|
||||
|
||||
pub struct ArArchiveBuilderBuilder;
|
||||
|
||||
impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder {
|
||||
fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box<dyn ArchiveBuilder + 'a> {
|
||||
Box::new(ArArchiveBuilder::new(sess, &DEFAULT_OBJECT_READER))
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use = "must call build() to finish building the archive"]
|
||||
pub struct ArArchiveBuilder<'a> {
|
||||
sess: &'a Session,
|
||||
|
@ -69,7 +69,7 @@ pub fn ensure_removed(dcx: DiagCtxtHandle<'_>, path: &Path) {
|
||||
pub fn link_binary(
|
||||
sess: &Session,
|
||||
archive_builder_builder: &dyn ArchiveBuilderBuilder,
|
||||
codegen_results: &CodegenResults,
|
||||
codegen_results: CodegenResults,
|
||||
outputs: &OutputFilenames,
|
||||
) -> Result<(), ErrorGuaranteed> {
|
||||
let _timer = sess.timer("link_binary");
|
||||
@ -116,7 +116,7 @@ pub fn link_binary(
|
||||
link_rlib(
|
||||
sess,
|
||||
archive_builder_builder,
|
||||
codegen_results,
|
||||
&codegen_results,
|
||||
RlibFlavor::Normal,
|
||||
&path,
|
||||
)?
|
||||
@ -126,7 +126,7 @@ pub fn link_binary(
|
||||
link_staticlib(
|
||||
sess,
|
||||
archive_builder_builder,
|
||||
codegen_results,
|
||||
&codegen_results,
|
||||
&out_filename,
|
||||
&path,
|
||||
)?;
|
||||
@ -137,7 +137,7 @@ pub fn link_binary(
|
||||
archive_builder_builder,
|
||||
crate_type,
|
||||
&out_filename,
|
||||
codegen_results,
|
||||
&codegen_results,
|
||||
path.as_ref(),
|
||||
)?;
|
||||
}
|
||||
|
@ -16,6 +16,8 @@ use rustc_span::symbol::Symbol;
|
||||
|
||||
use super::CodegenObject;
|
||||
use super::write::WriteBackendMethods;
|
||||
use crate::back::archive::ArArchiveBuilderBuilder;
|
||||
use crate::back::link::link_binary;
|
||||
use crate::back::write::TargetMachineFactoryFn;
|
||||
use crate::{CodegenResults, ModuleCodegen};
|
||||
|
||||
@ -87,7 +89,9 @@ pub trait CodegenBackend {
|
||||
sess: &Session,
|
||||
codegen_results: CodegenResults,
|
||||
outputs: &OutputFilenames,
|
||||
) -> Result<(), ErrorGuaranteed>;
|
||||
) -> Result<(), ErrorGuaranteed> {
|
||||
link_binary(sess, &ArArchiveBuilderBuilder, codegen_results, outputs)
|
||||
}
|
||||
|
||||
/// Returns `true` if this backend can be safely called from multiple threads.
|
||||
///
|
||||
|
@ -241,6 +241,8 @@ language_item_table! {
|
||||
DerefMut, sym::deref_mut, deref_mut_trait, Target::Trait, GenericRequirement::Exact(0);
|
||||
DerefPure, sym::deref_pure, deref_pure_trait, Target::Trait, GenericRequirement::Exact(0);
|
||||
DerefTarget, sym::deref_target, deref_target, Target::AssocTy, GenericRequirement::None;
|
||||
Receiver, sym::receiver, receiver_trait, Target::Trait, GenericRequirement::None;
|
||||
ReceiverTarget, sym::receiver_target, receiver_target, Target::AssocTy, GenericRequirement::None;
|
||||
LegacyReceiver, sym::legacy_receiver, legacy_receiver_trait, Target::Trait, GenericRequirement::None;
|
||||
|
||||
Fn, kw::Fn, fn_trait, Target::Trait, GenericRequirement::Exact(1);
|
||||
|
@ -1427,16 +1427,6 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
|
||||
let predicates = tcx.predicates_of(def_id.to_def_id());
|
||||
let generics = tcx.generics_of(def_id);
|
||||
|
||||
let is_our_default = |def: &ty::GenericParamDef| match def.kind {
|
||||
GenericParamDefKind::Type { has_default, .. }
|
||||
| GenericParamDefKind::Const { has_default, .. } => {
|
||||
has_default && def.index >= generics.parent_count as u32
|
||||
}
|
||||
GenericParamDefKind::Lifetime => {
|
||||
span_bug!(tcx.def_span(def.def_id), "lifetime params can have no default")
|
||||
}
|
||||
};
|
||||
|
||||
// Check that concrete defaults are well-formed. See test `type-check-defaults.rs`.
|
||||
// For example, this forbids the declaration:
|
||||
//
|
||||
@ -1444,40 +1434,21 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
|
||||
//
|
||||
// Here, the default `Vec<[u32]>` is not WF because `[u32]: Sized` does not hold.
|
||||
for param in &generics.own_params {
|
||||
match param.kind {
|
||||
GenericParamDefKind::Type { .. } => {
|
||||
if is_our_default(param) {
|
||||
let ty = tcx.type_of(param.def_id).instantiate_identity();
|
||||
// Ignore dependent defaults -- that is, where the default of one type
|
||||
// parameter includes another (e.g., `<T, U = T>`). In those cases, we can't
|
||||
// be sure if it will error or not as user might always specify the other.
|
||||
if !ty.has_param() {
|
||||
wfcx.register_wf_obligation(
|
||||
tcx.def_span(param.def_id),
|
||||
Some(WellFormedLoc::Ty(param.def_id.expect_local())),
|
||||
ty.into(),
|
||||
);
|
||||
}
|
||||
}
|
||||
if let Some(default) = param.default_value(tcx).map(ty::EarlyBinder::instantiate_identity) {
|
||||
// Ignore dependent defaults -- that is, where the default of one type
|
||||
// parameter includes another (e.g., `<T, U = T>`). In those cases, we can't
|
||||
// be sure if it will error or not as user might always specify the other.
|
||||
// FIXME(generic_const_exprs): This is incorrect when dealing with unused const params.
|
||||
// E.g: `struct Foo<const N: usize, const M: usize = { 1 - 2 }>;`. Here, we should
|
||||
// eagerly error but we don't as we have `ConstKind::Unevaluated(.., [N, M])`.
|
||||
if !default.has_param() {
|
||||
wfcx.register_wf_obligation(
|
||||
tcx.def_span(param.def_id),
|
||||
matches!(param.kind, GenericParamDefKind::Type { .. })
|
||||
.then(|| WellFormedLoc::Ty(param.def_id.expect_local())),
|
||||
default,
|
||||
);
|
||||
}
|
||||
GenericParamDefKind::Const { .. } => {
|
||||
if is_our_default(param) {
|
||||
// FIXME(const_generics_defaults): This
|
||||
// is incorrect when dealing with unused args, for example
|
||||
// for `struct Foo<const N: usize, const M: usize = { 1 - 2 }>`
|
||||
// we should eagerly error.
|
||||
let default_ct = tcx.const_param_default(param.def_id).instantiate_identity();
|
||||
if !default_ct.has_param() {
|
||||
wfcx.register_wf_obligation(
|
||||
tcx.def_span(param.def_id),
|
||||
None,
|
||||
default_ct.into(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Doesn't have defaults.
|
||||
GenericParamDefKind::Lifetime => {}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1490,39 +1461,16 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
|
||||
//
|
||||
// First we build the defaulted generic parameters.
|
||||
let args = GenericArgs::for_item(tcx, def_id.to_def_id(), |param, _| {
|
||||
match param.kind {
|
||||
GenericParamDefKind::Lifetime => {
|
||||
// All regions are identity.
|
||||
tcx.mk_param_from_def(param)
|
||||
}
|
||||
|
||||
GenericParamDefKind::Type { .. } => {
|
||||
// If the param has a default, ...
|
||||
if is_our_default(param) {
|
||||
let default_ty = tcx.type_of(param.def_id).instantiate_identity();
|
||||
// ... and it's not a dependent default, ...
|
||||
if !default_ty.has_param() {
|
||||
// ... then instantiate it with the default.
|
||||
return default_ty.into();
|
||||
}
|
||||
}
|
||||
|
||||
tcx.mk_param_from_def(param)
|
||||
}
|
||||
GenericParamDefKind::Const { .. } => {
|
||||
// If the param has a default, ...
|
||||
if is_our_default(param) {
|
||||
let default_ct = tcx.const_param_default(param.def_id).instantiate_identity();
|
||||
// ... and it's not a dependent default, ...
|
||||
if !default_ct.has_param() {
|
||||
// ... then instantiate it with the default.
|
||||
return default_ct.into();
|
||||
}
|
||||
}
|
||||
|
||||
tcx.mk_param_from_def(param)
|
||||
}
|
||||
if param.index >= generics.parent_count as u32
|
||||
// If the param has a default, ...
|
||||
&& let Some(default) = param.default_value(tcx).map(ty::EarlyBinder::instantiate_identity)
|
||||
// ... and it's not a dependent default, ...
|
||||
&& !default.has_param()
|
||||
{
|
||||
// ... then instantiate it with the default.
|
||||
return default;
|
||||
}
|
||||
tcx.mk_param_from_def(param)
|
||||
});
|
||||
|
||||
// Now we build the instantiated predicates.
|
||||
|
@ -15,7 +15,7 @@ use crate::{Diverges, Expectation, FnCtxt, Needs};
|
||||
|
||||
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
#[instrument(skip(self), level = "debug", ret)]
|
||||
pub(crate) fn check_match(
|
||||
pub(crate) fn check_expr_match(
|
||||
&self,
|
||||
expr: &'tcx hir::Expr<'tcx>,
|
||||
scrut: &'tcx hir::Expr<'tcx>,
|
||||
|
@ -62,7 +62,7 @@ enum CallStep<'tcx> {
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
pub(crate) fn check_call(
|
||||
pub(crate) fn check_expr_call(
|
||||
&self,
|
||||
call_expr: &'tcx hir::Expr<'tcx>,
|
||||
callee_expr: &'tcx hir::Expr<'tcx>,
|
||||
@ -74,8 +74,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
.check_expr_with_expectation_and_args(
|
||||
callee_expr,
|
||||
Expectation::NoExpectation,
|
||||
arg_exprs,
|
||||
Some(call_expr),
|
||||
Some((call_expr, arg_exprs)),
|
||||
),
|
||||
_ => self.check_expr(callee_expr),
|
||||
};
|
||||
|
@ -137,7 +137,7 @@ pub(super) fn check_fn<'a, 'tcx>(
|
||||
}
|
||||
|
||||
fcx.is_whole_body.set(true);
|
||||
fcx.check_return_expr(body.value, false);
|
||||
fcx.check_return_or_body_tail(body.value, false);
|
||||
|
||||
// Finalize the return check by taking the LUB of the return types
|
||||
// we saw and assigning it to the expected return type. This isn't
|
||||
|
@ -55,6 +55,9 @@ use crate::{
|
||||
};
|
||||
|
||||
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
/// Check an expr with an expectation type, and also demand that the expr's
|
||||
/// evaluated type is a subtype of the expectation at the end. This is a
|
||||
/// *hard* requirement.
|
||||
pub(crate) fn check_expr_has_type_or_error(
|
||||
&self,
|
||||
expr: &'tcx hir::Expr<'tcx>,
|
||||
@ -97,6 +100,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
ty
|
||||
}
|
||||
|
||||
/// Check an expr with an expectation type, and also demand that the expr's
|
||||
/// evaluated type is a coercible to the expectation at the end. This is a
|
||||
/// *hard* requirement.
|
||||
pub(super) fn check_expr_coercible_to_type(
|
||||
&self,
|
||||
expr: &'tcx hir::Expr<'tcx>,
|
||||
@ -128,6 +134,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Check an expr with an expectation type. Don't actually enforce that expectation
|
||||
/// is related to the expr's evaluated type via subtyping or coercion. This is
|
||||
/// usually called because we want to do that subtype/coerce call manually for better
|
||||
/// diagnostics.
|
||||
pub(super) fn check_expr_with_hint(
|
||||
&self,
|
||||
expr: &'tcx hir::Expr<'tcx>,
|
||||
@ -136,6 +146,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
self.check_expr_with_expectation(expr, ExpectHasType(expected))
|
||||
}
|
||||
|
||||
/// Check an expr with an expectation type, and also [`Needs`] which will
|
||||
/// prompt typeck to convert any implicit immutable derefs to mutable derefs.
|
||||
fn check_expr_with_expectation_and_needs(
|
||||
&self,
|
||||
expr: &'tcx hir::Expr<'tcx>,
|
||||
@ -153,10 +165,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
ty
|
||||
}
|
||||
|
||||
/// Check an expr with no expectations.
|
||||
pub(super) fn check_expr(&self, expr: &'tcx hir::Expr<'tcx>) -> Ty<'tcx> {
|
||||
self.check_expr_with_expectation(expr, NoExpectation)
|
||||
}
|
||||
|
||||
/// Check an expr with no expectations, but with [`Needs`] which will
|
||||
/// prompt typeck to convert any implicit immutable derefs to mutable derefs.
|
||||
pub(super) fn check_expr_with_needs(
|
||||
&self,
|
||||
expr: &'tcx hir::Expr<'tcx>,
|
||||
@ -165,33 +180,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
self.check_expr_with_expectation_and_needs(expr, NoExpectation, needs)
|
||||
}
|
||||
|
||||
/// Invariant:
|
||||
/// If an expression has any sub-expressions that result in a type error,
|
||||
/// inspecting that expression's type with `ty.references_error()` will return
|
||||
/// true. Likewise, if an expression is known to diverge, inspecting its
|
||||
/// type with `ty::type_is_bot` will return true (n.b.: since Rust is
|
||||
/// strict, _|_ can appear in the type of an expression that does not,
|
||||
/// itself, diverge: for example, fn() -> _|_.)
|
||||
/// Note that inspecting a type's structure *directly* may expose the fact
|
||||
/// that there are actually multiple representations for `Error`, so avoid
|
||||
/// that when err needs to be handled differently.
|
||||
/// Check an expr with an expectation type which may be used to eagerly
|
||||
/// guide inference when evaluating that expr.
|
||||
#[instrument(skip(self, expr), level = "debug")]
|
||||
pub(super) fn check_expr_with_expectation(
|
||||
&self,
|
||||
expr: &'tcx hir::Expr<'tcx>,
|
||||
expected: Expectation<'tcx>,
|
||||
) -> Ty<'tcx> {
|
||||
self.check_expr_with_expectation_and_args(expr, expected, &[], None)
|
||||
self.check_expr_with_expectation_and_args(expr, expected, None)
|
||||
}
|
||||
|
||||
/// Same as `check_expr_with_expectation`, but allows us to pass in the arguments of a
|
||||
/// `ExprKind::Call` when evaluating its callee when it is an `ExprKind::Path`.
|
||||
/// Same as [`Self::check_expr_with_expectation`], but allows us to pass in
|
||||
/// the arguments of a [`ExprKind::Call`] when evaluating its callee that
|
||||
/// is an [`ExprKind::Path`]. We use this to refine the spans for certain
|
||||
/// well-formedness guarantees for the path expr.
|
||||
pub(super) fn check_expr_with_expectation_and_args(
|
||||
&self,
|
||||
expr: &'tcx hir::Expr<'tcx>,
|
||||
expected: Expectation<'tcx>,
|
||||
args: &'tcx [hir::Expr<'tcx>],
|
||||
call: Option<&'tcx hir::Expr<'tcx>>,
|
||||
call_expr_and_args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>])>,
|
||||
) -> Ty<'tcx> {
|
||||
if self.tcx().sess.verbose_internals() {
|
||||
// make this code only run with -Zverbose-internals because it is probably slow
|
||||
@ -236,9 +244,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
};
|
||||
|
||||
let ty = ensure_sufficient_stack(|| match &expr.kind {
|
||||
// Intercept the callee path expr and give it better spans.
|
||||
hir::ExprKind::Path(
|
||||
qpath @ (hir::QPath::Resolved(..) | hir::QPath::TypeRelative(..)),
|
||||
) => self.check_expr_path(qpath, expr, Some(args), call),
|
||||
) => self.check_expr_path(qpath, expr, call_expr_and_args),
|
||||
_ => self.check_expr_kind(expr, expected),
|
||||
});
|
||||
let ty = self.resolve_vars_if_possible(ty);
|
||||
@ -472,28 +481,30 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
|
||||
let tcx = self.tcx;
|
||||
match expr.kind {
|
||||
ExprKind::Lit(ref lit) => self.check_lit(lit, expected),
|
||||
ExprKind::Binary(op, lhs, rhs) => self.check_binop(expr, op, lhs, rhs, expected),
|
||||
ExprKind::Lit(ref lit) => self.check_expr_lit(lit, expected),
|
||||
ExprKind::Binary(op, lhs, rhs) => self.check_expr_binop(expr, op, lhs, rhs, expected),
|
||||
ExprKind::Assign(lhs, rhs, span) => {
|
||||
self.check_expr_assign(expr, expected, lhs, rhs, span)
|
||||
}
|
||||
ExprKind::AssignOp(op, lhs, rhs) => {
|
||||
self.check_binop_assign(expr, op, lhs, rhs, expected)
|
||||
self.check_expr_binop_assign(expr, op, lhs, rhs, expected)
|
||||
}
|
||||
ExprKind::Unary(unop, oprnd) => self.check_expr_unary(unop, oprnd, expected, expr),
|
||||
ExprKind::Unary(unop, oprnd) => self.check_expr_unop(unop, oprnd, expected, expr),
|
||||
ExprKind::AddrOf(kind, mutbl, oprnd) => {
|
||||
self.check_expr_addr_of(kind, mutbl, oprnd, expected, expr)
|
||||
}
|
||||
ExprKind::Path(QPath::LangItem(lang_item, _)) => {
|
||||
self.check_lang_item_path(lang_item, expr)
|
||||
}
|
||||
ExprKind::Path(ref qpath) => self.check_expr_path(qpath, expr, None, None),
|
||||
ExprKind::Path(ref qpath) => self.check_expr_path(qpath, expr, None),
|
||||
ExprKind::InlineAsm(asm) => {
|
||||
// We defer some asm checks as we may not have resolved the input and output types yet (they may still be infer vars).
|
||||
self.deferred_asm_checks.borrow_mut().push((asm, expr.hir_id));
|
||||
self.check_expr_asm(asm)
|
||||
}
|
||||
ExprKind::OffsetOf(container, fields) => self.check_offset_of(container, fields, expr),
|
||||
ExprKind::OffsetOf(container, fields) => {
|
||||
self.check_expr_offset_of(container, fields, expr)
|
||||
}
|
||||
ExprKind::Break(destination, ref expr_opt) => {
|
||||
self.check_expr_break(destination, expr_opt.as_deref(), expr)
|
||||
}
|
||||
@ -512,13 +523,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
self.check_expr_loop(body, source, expected, expr)
|
||||
}
|
||||
ExprKind::Match(discrim, arms, match_src) => {
|
||||
self.check_match(expr, discrim, arms, expected, match_src)
|
||||
self.check_expr_match(expr, discrim, arms, expected, match_src)
|
||||
}
|
||||
ExprKind::Closure(closure) => self.check_expr_closure(closure, expr.span, expected),
|
||||
ExprKind::Block(body, _) => self.check_block_with_expected(body, expected),
|
||||
ExprKind::Call(callee, args) => self.check_call(expr, callee, args, expected),
|
||||
ExprKind::Block(body, _) => self.check_expr_block(body, expected),
|
||||
ExprKind::Call(callee, args) => self.check_expr_call(expr, callee, args, expected),
|
||||
ExprKind::MethodCall(segment, receiver, args, _) => {
|
||||
self.check_method_call(expr, segment, receiver, args, expected)
|
||||
self.check_expr_method_call(expr, segment, receiver, args, expected)
|
||||
}
|
||||
ExprKind::Cast(e, t) => self.check_expr_cast(e, t, expr),
|
||||
ExprKind::Type(e, t) => {
|
||||
@ -528,7 +539,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
ascribed_ty
|
||||
}
|
||||
ExprKind::If(cond, then_expr, opt_else_expr) => {
|
||||
self.check_then_else(cond, then_expr, opt_else_expr, expr.span, expected)
|
||||
self.check_expr_if(cond, then_expr, opt_else_expr, expr.span, expected)
|
||||
}
|
||||
ExprKind::DropTemps(e) => self.check_expr_with_expectation(e, expected),
|
||||
ExprKind::Array(args) => self.check_expr_array(args, expected, expr),
|
||||
@ -540,7 +551,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
ExprKind::Struct(qpath, fields, ref base_expr) => {
|
||||
self.check_expr_struct(expr, expected, qpath, fields, base_expr)
|
||||
}
|
||||
ExprKind::Field(base, field) => self.check_field(expr, base, field, expected),
|
||||
ExprKind::Field(base, field) => self.check_expr_field(expr, base, field, expected),
|
||||
ExprKind::Index(base, idx, brackets_span) => {
|
||||
self.check_expr_index(base, idx, expr, brackets_span)
|
||||
}
|
||||
@ -549,7 +560,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn check_expr_unary(
|
||||
fn check_expr_unop(
|
||||
&self,
|
||||
unop: hir::UnOp,
|
||||
oprnd: &'tcx hir::Expr<'tcx>,
|
||||
@ -699,8 +710,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
&self,
|
||||
qpath: &'tcx hir::QPath<'tcx>,
|
||||
expr: &'tcx hir::Expr<'tcx>,
|
||||
args: Option<&'tcx [hir::Expr<'tcx>]>,
|
||||
call: Option<&'tcx hir::Expr<'tcx>>,
|
||||
call_expr_and_args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>])>,
|
||||
) -> Ty<'tcx> {
|
||||
let tcx = self.tcx;
|
||||
let (res, opt_ty, segs) =
|
||||
@ -730,7 +740,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
segs,
|
||||
opt_ty,
|
||||
res,
|
||||
call.map_or(expr.span, |e| e.span),
|
||||
call_expr_and_args.map_or(expr.span, |(e, _)| e.span),
|
||||
expr.span,
|
||||
expr.hir_id,
|
||||
)
|
||||
@ -769,7 +779,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
// We just want to check sizedness, so instead of introducing
|
||||
// placeholder lifetimes with probing, we just replace higher lifetimes
|
||||
// with fresh vars.
|
||||
let span = args.and_then(|args| args.get(i)).map_or(expr.span, |arg| arg.span);
|
||||
let span = call_expr_and_args
|
||||
.and_then(|(_, args)| args.get(i))
|
||||
.map_or(expr.span, |arg| arg.span);
|
||||
let input = self.instantiate_binder_with_fresh_vars(
|
||||
span,
|
||||
infer::BoundRegionConversionTime::FnCall,
|
||||
@ -795,7 +807,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
);
|
||||
self.require_type_is_sized_deferred(
|
||||
output,
|
||||
call.map_or(expr.span, |e| e.span),
|
||||
call_expr_and_args.map_or(expr.span, |(e, _)| e.span),
|
||||
ObligationCauseCode::SizedCallReturnType,
|
||||
);
|
||||
}
|
||||
@ -972,7 +984,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
if self.ret_coercion_span.get().is_none() {
|
||||
self.ret_coercion_span.set(Some(e.span));
|
||||
}
|
||||
self.check_return_expr(e, true);
|
||||
self.check_return_or_body_tail(e, true);
|
||||
} else {
|
||||
let mut coercion = self.ret_coercion.as_ref().unwrap().borrow_mut();
|
||||
if self.ret_coercion_span.get().is_none() {
|
||||
@ -1035,7 +1047,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
///
|
||||
/// `explicit_return` is `true` if we're checking an explicit `return expr`,
|
||||
/// and `false` if we're checking a trailing expression.
|
||||
pub(super) fn check_return_expr(
|
||||
pub(super) fn check_return_or_body_tail(
|
||||
&self,
|
||||
return_expr: &'tcx hir::Expr<'tcx>,
|
||||
explicit_return: bool,
|
||||
@ -1259,7 +1271,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
|
||||
// A generic function for checking the 'then' and 'else' clauses in an 'if'
|
||||
// or 'if-else' expression.
|
||||
fn check_then_else(
|
||||
fn check_expr_if(
|
||||
&self,
|
||||
cond_expr: &'tcx hir::Expr<'tcx>,
|
||||
then_expr: &'tcx hir::Expr<'tcx>,
|
||||
@ -1542,7 +1554,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
}
|
||||
|
||||
/// Checks a method call.
|
||||
fn check_method_call(
|
||||
fn check_expr_method_call(
|
||||
&self,
|
||||
expr: &'tcx hir::Expr<'tcx>,
|
||||
segment: &'tcx hir::PathSegment<'tcx>,
|
||||
@ -2594,7 +2606,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
}
|
||||
|
||||
// Check field access expressions
|
||||
fn check_field(
|
||||
fn check_expr_field(
|
||||
&self,
|
||||
expr: &'tcx hir::Expr<'tcx>,
|
||||
base: &'tcx hir::Expr<'tcx>,
|
||||
@ -3535,8 +3547,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
let previous_diverges = self.diverges.get();
|
||||
|
||||
// The label blocks should have unit return value or diverge.
|
||||
let ty =
|
||||
self.check_block_with_expected(block, ExpectHasType(self.tcx.types.unit));
|
||||
let ty = self.check_expr_block(block, ExpectHasType(self.tcx.types.unit));
|
||||
if !ty.is_never() {
|
||||
self.demand_suptype(block.span, self.tcx.types.unit, ty);
|
||||
diverge = false;
|
||||
@ -3551,7 +3562,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
if diverge { self.tcx.types.never } else { self.tcx.types.unit }
|
||||
}
|
||||
|
||||
fn check_offset_of(
|
||||
fn check_expr_offset_of(
|
||||
&self,
|
||||
container: &'tcx hir::Ty<'tcx>,
|
||||
fields: &[Ident],
|
||||
|
@ -1306,30 +1306,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
rustc_hir_analysis::hir_ty_lowering::RegionInferReason::Param(param),
|
||||
)
|
||||
.into(),
|
||||
GenericParamDefKind::Type { has_default, .. } => {
|
||||
if !infer_args && has_default {
|
||||
// If we have a default, then it doesn't matter that we're not
|
||||
// inferring the type arguments: we provide the default where any
|
||||
// is missing.
|
||||
tcx.type_of(param.def_id).instantiate(tcx, preceding_args).into()
|
||||
} else {
|
||||
// If no type arguments were provided, we have to infer them.
|
||||
// This case also occurs as a result of some malformed input, e.g.
|
||||
// a lifetime argument being given instead of a type parameter.
|
||||
// Using inference instead of `Error` gives better error messages.
|
||||
self.fcx.var_for_def(self.span, param)
|
||||
GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => {
|
||||
if !infer_args && let Some(default) = param.default_value(tcx) {
|
||||
// If we have a default, then it doesn't matter that we're not inferring
|
||||
// the type/const arguments: We provide the default where any is missing.
|
||||
return default.instantiate(tcx, preceding_args);
|
||||
}
|
||||
}
|
||||
GenericParamDefKind::Const { has_default, .. } => {
|
||||
if has_default {
|
||||
if !infer_args {
|
||||
return tcx
|
||||
.const_param_default(param.def_id)
|
||||
.instantiate(tcx, preceding_args)
|
||||
.into();
|
||||
}
|
||||
}
|
||||
|
||||
// If no type/const arguments were provided, we have to infer them.
|
||||
// This case also occurs as a result of some malformed input, e.g.,
|
||||
// a lifetime argument being given instead of a type/const parameter.
|
||||
// Using inference instead of `Error` gives better error messages.
|
||||
self.fcx.var_for_def(self.span, param)
|
||||
}
|
||||
}
|
||||
|
@ -1565,7 +1565,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
}
|
||||
|
||||
// AST fragment checking
|
||||
pub(in super::super) fn check_lit(
|
||||
pub(in super::super) fn check_expr_lit(
|
||||
&self,
|
||||
lit: &hir::Lit,
|
||||
expected: Expectation<'tcx>,
|
||||
@ -1747,7 +1747,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
|
||||
if let Some(blk) = decl.origin.try_get_else() {
|
||||
let previous_diverges = self.diverges.get();
|
||||
let else_ty = self.check_block_with_expected(blk, NoExpectation);
|
||||
let else_ty = self.check_expr_block(blk, NoExpectation);
|
||||
let cause = self.cause(blk.span, ObligationCauseCode::LetElse);
|
||||
if let Err(err) = self.demand_eqtype_with_origin(&cause, self.tcx.types.never, else_ty)
|
||||
{
|
||||
@ -1805,7 +1805,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
|
||||
pub(crate) fn check_block_no_value(&self, blk: &'tcx hir::Block<'tcx>) {
|
||||
let unit = self.tcx.types.unit;
|
||||
let ty = self.check_block_with_expected(blk, ExpectHasType(unit));
|
||||
let ty = self.check_expr_block(blk, ExpectHasType(unit));
|
||||
|
||||
// if the block produces a `!` value, that can always be
|
||||
// (effectively) coerced to unit.
|
||||
@ -1814,7 +1814,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
pub(in super::super) fn check_block_with_expected(
|
||||
pub(in super::super) fn check_expr_block(
|
||||
&self,
|
||||
blk: &'tcx hir::Block<'tcx>,
|
||||
expected: Expectation<'tcx>,
|
||||
|
@ -26,7 +26,7 @@ use crate::Expectation;
|
||||
|
||||
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
/// Checks a `a <op>= b`
|
||||
pub(crate) fn check_binop_assign(
|
||||
pub(crate) fn check_expr_binop_assign(
|
||||
&self,
|
||||
expr: &'tcx hir::Expr<'tcx>,
|
||||
op: hir::BinOp,
|
||||
@ -85,7 +85,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
}
|
||||
|
||||
/// Checks a potentially overloaded binary operator.
|
||||
pub(crate) fn check_binop(
|
||||
pub(crate) fn check_expr_binop(
|
||||
&self,
|
||||
expr: &'tcx hir::Expr<'tcx>,
|
||||
op: hir::BinOp,
|
||||
|
@ -86,10 +86,10 @@ impl GenericParamDef {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
) -> Option<EarlyBinder<'tcx, ty::GenericArg<'tcx>>> {
|
||||
match self.kind {
|
||||
GenericParamDefKind::Type { has_default, .. } if has_default => {
|
||||
GenericParamDefKind::Type { has_default: true, .. } => {
|
||||
Some(tcx.type_of(self.def_id).map_bound(|t| t.into()))
|
||||
}
|
||||
GenericParamDefKind::Const { has_default, .. } if has_default => {
|
||||
GenericParamDefKind::Const { has_default: true, .. } => {
|
||||
Some(tcx.const_param_default(self.def_id).map_bound(|c| c.into()))
|
||||
}
|
||||
_ => None,
|
||||
|
@ -782,21 +782,11 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
|
||||
impl ReachEverythingInTheInterfaceVisitor<'_, '_> {
|
||||
fn generics(&mut self) -> &mut Self {
|
||||
for param in &self.ev.tcx.generics_of(self.item_def_id).own_params {
|
||||
match param.kind {
|
||||
GenericParamDefKind::Lifetime => {}
|
||||
GenericParamDefKind::Type { has_default, .. } => {
|
||||
if has_default {
|
||||
self.visit(self.ev.tcx.type_of(param.def_id).instantiate_identity());
|
||||
}
|
||||
}
|
||||
GenericParamDefKind::Const { has_default, .. } => {
|
||||
self.visit(self.ev.tcx.type_of(param.def_id).instantiate_identity());
|
||||
if has_default {
|
||||
self.visit(
|
||||
self.ev.tcx.const_param_default(param.def_id).instantiate_identity(),
|
||||
);
|
||||
}
|
||||
}
|
||||
if let GenericParamDefKind::Const { .. } = param.kind {
|
||||
self.visit(self.ev.tcx.type_of(param.def_id).instantiate_identity());
|
||||
}
|
||||
if let Some(default) = param.default_value(self.ev.tcx) {
|
||||
self.visit(default.instantiate_identity());
|
||||
}
|
||||
}
|
||||
self
|
||||
|
@ -130,7 +130,7 @@ top_level_options!(
|
||||
pub struct Options {
|
||||
/// The crate config requested for the session, which may be combined
|
||||
/// with additional crate configurations during the compile process.
|
||||
#[rustc_lint_opt_deny_field_access("use `Session::crate_types` instead of this field")]
|
||||
#[rustc_lint_opt_deny_field_access("use `TyCtxt::crate_types` instead of this field")]
|
||||
crate_types: Vec<CrateType> [TRACKED],
|
||||
optimize: OptLevel [TRACKED],
|
||||
/// Include the `debug_assertions` flag in dependency tracking, since it
|
||||
|
@ -1568,6 +1568,8 @@ symbols! {
|
||||
readonly,
|
||||
realloc,
|
||||
reason,
|
||||
receiver,
|
||||
receiver_target,
|
||||
recursion_limit,
|
||||
reexport_test_harness_main,
|
||||
ref_pat_eat_one_layer_2024,
|
||||
|
@ -294,14 +294,98 @@ unsafe impl<T: ?Sized> DerefPure for &T {}
|
||||
#[unstable(feature = "deref_pure_trait", issue = "87121")]
|
||||
unsafe impl<T: ?Sized> DerefPure for &mut T {}
|
||||
|
||||
/// Indicates that a struct can be used as a method receiver.
|
||||
/// That is, a type can use this type as a type of `self`, like this:
|
||||
/// ```compile_fail
|
||||
/// # // This is currently compile_fail because the compiler-side parts
|
||||
/// # // of arbitrary_self_types are not implemented
|
||||
/// use std::ops::Receiver;
|
||||
///
|
||||
/// struct SmartPointer<T>(T);
|
||||
///
|
||||
/// impl<T> Receiver for SmartPointer<T> {
|
||||
/// type Target = T;
|
||||
/// }
|
||||
///
|
||||
/// struct MyContainedType;
|
||||
///
|
||||
/// impl MyContainedType {
|
||||
/// fn method(self: SmartPointer<Self>) {
|
||||
/// // ...
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// fn main() {
|
||||
/// let ptr = SmartPointer(MyContainedType);
|
||||
/// ptr.method();
|
||||
/// }
|
||||
/// ```
|
||||
/// This trait is blanket implemented for any type which implements
|
||||
/// [`Deref`], which includes stdlib pointer types like `Box<T>`,`Rc<T>`, `&T`,
|
||||
/// and `Pin<P>`. For that reason, it's relatively rare to need to
|
||||
/// implement this directly. You'll typically do this only if you need
|
||||
/// to implement a smart pointer type which can't implement [`Deref`]; perhaps
|
||||
/// because you're interfacing with another programming language and can't
|
||||
/// guarantee that references comply with Rust's aliasing rules.
|
||||
///
|
||||
/// When looking for method candidates, Rust will explore a chain of possible
|
||||
/// `Receiver`s, so for example each of the following methods work:
|
||||
/// ```
|
||||
/// use std::boxed::Box;
|
||||
/// use std::rc::Rc;
|
||||
///
|
||||
/// // Both `Box` and `Rc` (indirectly) implement Receiver
|
||||
///
|
||||
/// struct MyContainedType;
|
||||
///
|
||||
/// fn main() {
|
||||
/// let t = Rc::new(Box::new(MyContainedType));
|
||||
/// t.method_a();
|
||||
/// t.method_b();
|
||||
/// t.method_c();
|
||||
/// }
|
||||
///
|
||||
/// impl MyContainedType {
|
||||
/// fn method_a(&self) {
|
||||
///
|
||||
/// }
|
||||
/// fn method_b(self: &Box<Self>) {
|
||||
///
|
||||
/// }
|
||||
/// fn method_c(self: &Rc<Box<Self>>) {
|
||||
///
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
#[lang = "receiver"]
|
||||
#[cfg(not(bootstrap))]
|
||||
#[unstable(feature = "arbitrary_self_types", issue = "44874")]
|
||||
pub trait Receiver {
|
||||
/// The target type on which the method may be called.
|
||||
#[cfg(not(bootstrap))]
|
||||
#[rustc_diagnostic_item = "receiver_target"]
|
||||
#[lang = "receiver_target"]
|
||||
#[unstable(feature = "arbitrary_self_types", issue = "44874")]
|
||||
type Target: ?Sized;
|
||||
}
|
||||
|
||||
#[cfg(not(bootstrap))]
|
||||
#[unstable(feature = "arbitrary_self_types", issue = "44874")]
|
||||
impl<P: ?Sized, T: ?Sized> Receiver for P
|
||||
where
|
||||
P: Deref<Target = T>,
|
||||
{
|
||||
type Target = T;
|
||||
}
|
||||
|
||||
/// Indicates that a struct can be used as a method receiver, without the
|
||||
/// `arbitrary_self_types` feature. This is implemented by stdlib pointer types like `Box<T>`,
|
||||
/// `Rc<T>`, `&T`, and `Pin<P>`.
|
||||
///
|
||||
/// This trait will shortly be removed and replaced with a more generic
|
||||
/// facility based around the current "arbitrary self types" unstable feature.
|
||||
/// That new facility will use a replacement trait called `Receiver` which is
|
||||
/// why this is now named `LegacyReceiver`.
|
||||
/// That new facility will use the replacement trait above called `Receiver`
|
||||
/// which is why this is now named `LegacyReceiver`.
|
||||
#[cfg_attr(bootstrap, lang = "receiver")]
|
||||
#[cfg_attr(not(bootstrap), lang = "legacy_receiver")]
|
||||
#[unstable(feature = "legacy_receiver_trait", issue = "none")]
|
||||
|
@ -170,6 +170,9 @@ pub use self::coroutine::{Coroutine, CoroutineState};
|
||||
pub use self::deref::DerefPure;
|
||||
#[unstable(feature = "legacy_receiver_trait", issue = "none")]
|
||||
pub use self::deref::LegacyReceiver;
|
||||
#[unstable(feature = "arbitrary_self_types", issue = "44874")]
|
||||
#[cfg(not(bootstrap))]
|
||||
pub use self::deref::Receiver;
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub use self::deref::{Deref, DerefMut};
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
@ -757,6 +757,47 @@ where
|
||||
self.base.get_or_insert_with(value, f)
|
||||
}
|
||||
|
||||
/// Gets the given value's corresponding entry in the set for in-place manipulation.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(hash_set_entry)]
|
||||
///
|
||||
/// use std::collections::HashSet;
|
||||
/// use std::collections::hash_set::Entry::*;
|
||||
///
|
||||
/// let mut singles = HashSet::new();
|
||||
/// let mut dupes = HashSet::new();
|
||||
///
|
||||
/// for ch in "a short treatise on fungi".chars() {
|
||||
/// if let Vacant(dupe_entry) = dupes.entry(ch) {
|
||||
/// // We haven't already seen a duplicate, so
|
||||
/// // check if we've at least seen it once.
|
||||
/// match singles.entry(ch) {
|
||||
/// Vacant(single_entry) => {
|
||||
/// // We found a new character for the first time.
|
||||
/// single_entry.insert()
|
||||
/// }
|
||||
/// Occupied(single_entry) => {
|
||||
/// // We've already seen this once, "move" it to dupes.
|
||||
/// single_entry.remove();
|
||||
/// dupe_entry.insert();
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// assert!(!singles.contains(&'t') && dupes.contains(&'t'));
|
||||
/// assert!(singles.contains(&'u') && !dupes.contains(&'u'));
|
||||
/// assert!(!singles.contains(&'v') && !dupes.contains(&'v'));
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "hash_set_entry", issue = "60896")]
|
||||
pub fn entry(&mut self, value: T) -> Entry<'_, T, S> {
|
||||
map_entry(self.base.entry(value))
|
||||
}
|
||||
|
||||
/// Returns `true` if `self` has no elements in common with `other`.
|
||||
/// This is equivalent to checking for an empty intersection.
|
||||
///
|
||||
@ -935,6 +976,14 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn map_entry<'a, K: 'a, V: 'a>(raw: base::Entry<'a, K, V>) -> Entry<'a, K, V> {
|
||||
match raw {
|
||||
base::Entry::Occupied(base) => Entry::Occupied(OccupiedEntry { base }),
|
||||
base::Entry::Vacant(base) => Entry::Vacant(VacantEntry { base }),
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T, S> Clone for HashSet<T, S>
|
||||
where
|
||||
@ -1865,6 +1914,406 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// A view into a single entry in a set, which may either be vacant or occupied.
|
||||
///
|
||||
/// This `enum` is constructed from the [`entry`] method on [`HashSet`].
|
||||
///
|
||||
/// [`HashSet`]: struct.HashSet.html
|
||||
/// [`entry`]: struct.HashSet.html#method.entry
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(hash_set_entry)]
|
||||
///
|
||||
/// use std::collections::hash_set::HashSet;
|
||||
///
|
||||
/// let mut set = HashSet::new();
|
||||
/// set.extend(["a", "b", "c"]);
|
||||
/// assert_eq!(set.len(), 3);
|
||||
///
|
||||
/// // Existing value (insert)
|
||||
/// let entry = set.entry("a");
|
||||
/// let _raw_o = entry.insert();
|
||||
/// assert_eq!(set.len(), 3);
|
||||
/// // Nonexistent value (insert)
|
||||
/// set.entry("d").insert();
|
||||
///
|
||||
/// // Existing value (or_insert)
|
||||
/// set.entry("b").or_insert();
|
||||
/// // Nonexistent value (or_insert)
|
||||
/// set.entry("e").or_insert();
|
||||
///
|
||||
/// println!("Our HashSet: {:?}", set);
|
||||
///
|
||||
/// let mut vec: Vec<_> = set.iter().copied().collect();
|
||||
/// // The `Iter` iterator produces items in arbitrary order, so the
|
||||
/// // items must be sorted to test them against a sorted array.
|
||||
/// vec.sort_unstable();
|
||||
/// assert_eq!(vec, ["a", "b", "c", "d", "e"]);
|
||||
/// ```
|
||||
#[unstable(feature = "hash_set_entry", issue = "60896")]
|
||||
pub enum Entry<'a, T, S> {
|
||||
/// An occupied entry.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(hash_set_entry)]
|
||||
///
|
||||
/// use std::collections::hash_set::{Entry, HashSet};
|
||||
///
|
||||
/// let mut set = HashSet::from(["a", "b"]);
|
||||
///
|
||||
/// match set.entry("a") {
|
||||
/// Entry::Vacant(_) => unreachable!(),
|
||||
/// Entry::Occupied(_) => { }
|
||||
/// }
|
||||
/// ```
|
||||
Occupied(OccupiedEntry<'a, T, S>),
|
||||
|
||||
/// A vacant entry.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(hash_set_entry)]
|
||||
///
|
||||
/// use std::collections::hash_set::{Entry, HashSet};
|
||||
///
|
||||
/// let mut set = HashSet::new();
|
||||
///
|
||||
/// match set.entry("a") {
|
||||
/// Entry::Occupied(_) => unreachable!(),
|
||||
/// Entry::Vacant(_) => { }
|
||||
/// }
|
||||
/// ```
|
||||
Vacant(VacantEntry<'a, T, S>),
|
||||
}
|
||||
|
||||
#[unstable(feature = "hash_set_entry", issue = "60896")]
|
||||
impl<T: fmt::Debug, S> fmt::Debug for Entry<'_, T, S> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match *self {
|
||||
Entry::Vacant(ref v) => f.debug_tuple("Entry").field(v).finish(),
|
||||
Entry::Occupied(ref o) => f.debug_tuple("Entry").field(o).finish(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A view into an occupied entry in a `HashSet`.
|
||||
/// It is part of the [`Entry`] enum.
|
||||
///
|
||||
/// [`Entry`]: enum.Entry.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(hash_set_entry)]
|
||||
///
|
||||
/// use std::collections::hash_set::{Entry, HashSet};
|
||||
///
|
||||
/// let mut set = HashSet::new();
|
||||
/// set.extend(["a", "b", "c"]);
|
||||
///
|
||||
/// let _entry_o = set.entry("a").insert();
|
||||
/// assert_eq!(set.len(), 3);
|
||||
///
|
||||
/// // Existing key
|
||||
/// match set.entry("a") {
|
||||
/// Entry::Vacant(_) => unreachable!(),
|
||||
/// Entry::Occupied(view) => {
|
||||
/// assert_eq!(view.get(), &"a");
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// assert_eq!(set.len(), 3);
|
||||
///
|
||||
/// // Existing key (take)
|
||||
/// match set.entry("c") {
|
||||
/// Entry::Vacant(_) => unreachable!(),
|
||||
/// Entry::Occupied(view) => {
|
||||
/// assert_eq!(view.remove(), "c");
|
||||
/// }
|
||||
/// }
|
||||
/// assert_eq!(set.get(&"c"), None);
|
||||
/// assert_eq!(set.len(), 2);
|
||||
/// ```
|
||||
#[unstable(feature = "hash_set_entry", issue = "60896")]
|
||||
pub struct OccupiedEntry<'a, T, S> {
|
||||
base: base::OccupiedEntry<'a, T, S>,
|
||||
}
|
||||
|
||||
#[unstable(feature = "hash_set_entry", issue = "60896")]
|
||||
impl<T: fmt::Debug, S> fmt::Debug for OccupiedEntry<'_, T, S> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("OccupiedEntry").field("value", self.get()).finish()
|
||||
}
|
||||
}
|
||||
|
||||
/// A view into a vacant entry in a `HashSet`.
|
||||
/// It is part of the [`Entry`] enum.
|
||||
///
|
||||
/// [`Entry`]: enum.Entry.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(hash_set_entry)]
|
||||
///
|
||||
/// use std::collections::hash_set::{Entry, HashSet};
|
||||
///
|
||||
/// let mut set = HashSet::<&str>::new();
|
||||
///
|
||||
/// let entry_v = match set.entry("a") {
|
||||
/// Entry::Vacant(view) => view,
|
||||
/// Entry::Occupied(_) => unreachable!(),
|
||||
/// };
|
||||
/// entry_v.insert();
|
||||
/// assert!(set.contains("a") && set.len() == 1);
|
||||
///
|
||||
/// // Nonexistent key (insert)
|
||||
/// match set.entry("b") {
|
||||
/// Entry::Vacant(view) => view.insert(),
|
||||
/// Entry::Occupied(_) => unreachable!(),
|
||||
/// }
|
||||
/// assert!(set.contains("b") && set.len() == 2);
|
||||
/// ```
|
||||
#[unstable(feature = "hash_set_entry", issue = "60896")]
|
||||
pub struct VacantEntry<'a, T, S> {
|
||||
base: base::VacantEntry<'a, T, S>,
|
||||
}
|
||||
|
||||
#[unstable(feature = "hash_set_entry", issue = "60896")]
|
||||
impl<T: fmt::Debug, S> fmt::Debug for VacantEntry<'_, T, S> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_tuple("VacantEntry").field(self.get()).finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T, S> Entry<'a, T, S> {
|
||||
/// Sets the value of the entry, and returns an OccupiedEntry.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(hash_set_entry)]
|
||||
///
|
||||
/// use std::collections::HashSet;
|
||||
///
|
||||
/// let mut set = HashSet::new();
|
||||
/// let entry = set.entry("horseyland").insert();
|
||||
///
|
||||
/// assert_eq!(entry.get(), &"horseyland");
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "hash_set_entry", issue = "60896")]
|
||||
pub fn insert(self) -> OccupiedEntry<'a, T, S>
|
||||
where
|
||||
T: Hash,
|
||||
S: BuildHasher,
|
||||
{
|
||||
match self {
|
||||
Entry::Occupied(entry) => entry,
|
||||
Entry::Vacant(entry) => entry.insert_entry(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Ensures a value is in the entry by inserting if it was vacant.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(hash_set_entry)]
|
||||
///
|
||||
/// use std::collections::HashSet;
|
||||
///
|
||||
/// let mut set = HashSet::new();
|
||||
///
|
||||
/// // nonexistent key
|
||||
/// set.entry("poneyland").or_insert();
|
||||
/// assert!(set.contains("poneyland"));
|
||||
///
|
||||
/// // existing key
|
||||
/// set.entry("poneyland").or_insert();
|
||||
/// assert!(set.contains("poneyland"));
|
||||
/// assert_eq!(set.len(), 1);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "hash_set_entry", issue = "60896")]
|
||||
pub fn or_insert(self)
|
||||
where
|
||||
T: Hash,
|
||||
S: BuildHasher,
|
||||
{
|
||||
if let Entry::Vacant(entry) = self {
|
||||
entry.insert();
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a reference to this entry's value.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(hash_set_entry)]
|
||||
///
|
||||
/// use std::collections::HashSet;
|
||||
///
|
||||
/// let mut set = HashSet::new();
|
||||
/// set.entry("poneyland").or_insert();
|
||||
///
|
||||
/// // existing key
|
||||
/// assert_eq!(set.entry("poneyland").get(), &"poneyland");
|
||||
/// // nonexistent key
|
||||
/// assert_eq!(set.entry("horseland").get(), &"horseland");
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "hash_set_entry", issue = "60896")]
|
||||
pub fn get(&self) -> &T {
|
||||
match *self {
|
||||
Entry::Occupied(ref entry) => entry.get(),
|
||||
Entry::Vacant(ref entry) => entry.get(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, S> OccupiedEntry<'_, T, S> {
|
||||
/// Gets a reference to the value in the entry.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(hash_set_entry)]
|
||||
///
|
||||
/// use std::collections::hash_set::{Entry, HashSet};
|
||||
///
|
||||
/// let mut set = HashSet::new();
|
||||
/// set.entry("poneyland").or_insert();
|
||||
///
|
||||
/// match set.entry("poneyland") {
|
||||
/// Entry::Vacant(_) => panic!(),
|
||||
/// Entry::Occupied(entry) => assert_eq!(entry.get(), &"poneyland"),
|
||||
/// }
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "hash_set_entry", issue = "60896")]
|
||||
pub fn get(&self) -> &T {
|
||||
self.base.get()
|
||||
}
|
||||
|
||||
/// Takes the value out of the entry, and returns it.
|
||||
/// Keeps the allocated memory for reuse.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(hash_set_entry)]
|
||||
///
|
||||
/// use std::collections::HashSet;
|
||||
/// use std::collections::hash_set::Entry;
|
||||
///
|
||||
/// let mut set = HashSet::new();
|
||||
/// // The set is empty
|
||||
/// assert!(set.is_empty() && set.capacity() == 0);
|
||||
///
|
||||
/// set.entry("poneyland").or_insert();
|
||||
/// let capacity_before_remove = set.capacity();
|
||||
///
|
||||
/// if let Entry::Occupied(o) = set.entry("poneyland") {
|
||||
/// assert_eq!(o.remove(), "poneyland");
|
||||
/// }
|
||||
///
|
||||
/// assert_eq!(set.contains("poneyland"), false);
|
||||
/// // Now set hold none elements but capacity is equal to the old one
|
||||
/// assert!(set.len() == 0 && set.capacity() == capacity_before_remove);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "hash_set_entry", issue = "60896")]
|
||||
pub fn remove(self) -> T {
|
||||
self.base.remove()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T, S> VacantEntry<'a, T, S> {
|
||||
/// Gets a reference to the value that would be used when inserting
|
||||
/// through the `VacantEntry`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(hash_set_entry)]
|
||||
///
|
||||
/// use std::collections::HashSet;
|
||||
///
|
||||
/// let mut set = HashSet::new();
|
||||
/// assert_eq!(set.entry("poneyland").get(), &"poneyland");
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "hash_set_entry", issue = "60896")]
|
||||
pub fn get(&self) -> &T {
|
||||
self.base.get()
|
||||
}
|
||||
|
||||
/// Take ownership of the value.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(hash_set_entry)]
|
||||
///
|
||||
/// use std::collections::hash_set::{Entry, HashSet};
|
||||
///
|
||||
/// let mut set = HashSet::new();
|
||||
///
|
||||
/// match set.entry("poneyland") {
|
||||
/// Entry::Occupied(_) => panic!(),
|
||||
/// Entry::Vacant(v) => assert_eq!(v.into_value(), "poneyland"),
|
||||
/// }
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "hash_set_entry", issue = "60896")]
|
||||
pub fn into_value(self) -> T {
|
||||
self.base.into_value()
|
||||
}
|
||||
|
||||
/// Sets the value of the entry with the VacantEntry's value.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(hash_set_entry)]
|
||||
///
|
||||
/// use std::collections::HashSet;
|
||||
/// use std::collections::hash_set::Entry;
|
||||
///
|
||||
/// let mut set = HashSet::new();
|
||||
///
|
||||
/// if let Entry::Vacant(o) = set.entry("poneyland") {
|
||||
/// o.insert();
|
||||
/// }
|
||||
/// assert!(set.contains("poneyland"));
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "hash_set_entry", issue = "60896")]
|
||||
pub fn insert(self)
|
||||
where
|
||||
T: Hash,
|
||||
S: BuildHasher,
|
||||
{
|
||||
self.base.insert();
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn insert_entry(self) -> OccupiedEntry<'a, T, S>
|
||||
where
|
||||
T: Hash,
|
||||
S: BuildHasher,
|
||||
{
|
||||
OccupiedEntry { base: self.base.insert() }
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn assert_covariance() {
|
||||
fn set<'new>(v: HashSet<&'static str>) -> HashSet<&'new str> {
|
||||
|
@ -15,7 +15,7 @@ pub fn access_bad_option(sess: Session) {
|
||||
//~^ ERROR use `Session::split_debuginfo` instead of this field
|
||||
|
||||
let _ = sess.opts.crate_types;
|
||||
//~^ ERROR use `Session::crate_types` instead of this field
|
||||
//~^ ERROR use `TyCtxt::crate_types` instead of this field
|
||||
|
||||
let _ = sess.opts.crate_name;
|
||||
// okay!
|
||||
|
@ -10,7 +10,7 @@ note: the lint level is defined here
|
||||
LL | #![deny(rustc::bad_opt_access)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: use `Session::crate_types` instead of this field
|
||||
error: use `TyCtxt::crate_types` instead of this field
|
||||
--> $DIR/bad_opt_access.rs:17:13
|
||||
|
|
||||
LL | let _ = sess.opts.crate_types;
|
||||
|
@ -212,6 +212,10 @@ trigger_files = [
|
||||
"src/tools/rustdoc-gui",
|
||||
"src/tools/rustdoc-js",
|
||||
"src/tools/rustdoc-themes",
|
||||
|
||||
# Docs
|
||||
"src/doc/rustdoc.md",
|
||||
"src/doc/rustdoc/",
|
||||
]
|
||||
exclude_labels = [
|
||||
"T-*",
|
||||
@ -971,7 +975,6 @@ cc = ["@kobzol"]
|
||||
warn_non_default_branch = true
|
||||
contributing_url = "https://rustc-dev-guide.rust-lang.org/getting-started.html"
|
||||
users_on_vacation = [
|
||||
"fmease",
|
||||
"jieyouxu",
|
||||
"jyn514",
|
||||
"oli-obk",
|
||||
|
Loading…
Reference in New Issue
Block a user