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:
bors 2024-11-12 02:51:21 +00:00
commit 67f21277cd
27 changed files with 670 additions and 243 deletions

View File

@ -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))
}
}

View File

@ -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 {

View File

@ -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");
}
}

View File

@ -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)
}

View File

@ -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)
}
}

View File

@ -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,

View File

@ -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(),
)?;
}

View File

@ -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.
///

View File

@ -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);

View File

@ -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.

View File

@ -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>,

View File

@ -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),
};

View File

@ -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

View File

@ -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],

View File

@ -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)
}
}

View File

@ -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>,

View File

@ -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,

View File

@ -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,

View File

@ -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

View File

@ -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

View File

@ -1568,6 +1568,8 @@ symbols! {
readonly,
realloc,
reason,
receiver,
receiver_target,
recursion_limit,
reexport_test_harness_main,
ref_pat_eat_one_layer_2024,

View File

@ -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")]

View File

@ -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")]

View File

@ -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> {

View File

@ -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!

View File

@ -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;

View File

@ -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",