diff --git a/compiler/rustc_codegen_cranelift/src/archive.rs b/compiler/rustc_codegen_cranelift/src/archive.rs deleted file mode 100644 index c7725e49c9442..0000000000000 --- a/compiler/rustc_codegen_cranelift/src/archive.rs +++ /dev/null @@ -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 { - Box::new(ArArchiveBuilder::new(sess, &DEFAULT_OBJECT_READER)) - } -} diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs index 19a1de53d1dd3..b506b1f57315a 100644 --- a/compiler/rustc_codegen_cranelift/src/lib.rs +++ b/compiler/rustc_codegen_cranelift/src/lib.rs @@ -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 { diff --git a/compiler/rustc_codegen_gcc/src/archive.rs b/compiler/rustc_codegen_gcc/src/archive.rs deleted file mode 100644 index 82e98370b376b..0000000000000 --- a/compiler/rustc_codegen_gcc/src/archive.rs +++ /dev/null @@ -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 { - Box::new(ArArchiveBuilder::new(sess, &DEFAULT_OBJECT_READER)) - } - - fn create_dll_import_lib( - &self, - _sess: &Session, - _lib_name: &str, - _items: Vec, - _output_path: &Path, - ) { - unimplemented!("creating dll imports is not yet supported"); - } -} diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index f70dc94b26741..452e92bffa235 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -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 { target_features(sess, allow_unstable, &self.target_info) } diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 49e616b53713e..3dfb86d422dd2 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -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) } } diff --git a/compiler/rustc_codegen_ssa/src/back/archive.rs b/compiler/rustc_codegen_ssa/src/back/archive.rs index e83bfa7b70d93..d4836eb7a1de6 100644 --- a/compiler/rustc_codegen_ssa/src/back/archive.rs +++ b/compiler/rustc_codegen_ssa/src/back/archive.rs @@ -304,6 +304,14 @@ pub trait ArchiveBuilder { fn build(self: Box, output: &Path) -> bool; } +pub struct ArArchiveBuilderBuilder; + +impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder { + fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box { + 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, diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 3120b5bf0af67..fc1f96481cf79 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -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(), )?; } diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs index 676fb181d67cc..cbf214763b425 100644 --- a/compiler/rustc_codegen_ssa/src/traits/backend.rs +++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs @@ -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. /// diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index c952d5f6d77cf..15cb331d07a5f 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -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); diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 3a6ea545741be..1802f00bc1f1c 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -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., ``). 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(), - ); - } - } - } - GenericParamDefKind::Const { .. } => { - if is_our_default(param) { - // FIXME(const_generics_defaults): This - // is incorrect when dealing with unused args, for example - // for `struct Foo` - // 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(), - ); - } - } + 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., ``). 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;`. 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, + ); } - // 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. diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs index 1774772b50b4c..bfdf764d299b4 100644 --- a/compiler/rustc_hir_typeck/src/_match.rs +++ b/compiler/rustc_hir_typeck/src/_match.rs @@ -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>, diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index 20502de38a2a2..e6e0f62b54d2f 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -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), }; diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs index 2026fd9a614fc..51d7864637346 100644 --- a/compiler/rustc_hir_typeck/src/check.rs +++ b/compiler/rustc_hir_typeck/src/check.rs @@ -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 diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index b05731c6d52e0..354993513dacd 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -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], diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index ce0ab8a913b0a..c18b847d7b79e 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -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) } } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index a6c249da103f3..50d1322eba649 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -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>, diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs index 9a3492abc9f8c..72b930ee84df6 100644 --- a/compiler/rustc_hir_typeck/src/op.rs +++ b/compiler/rustc_hir_typeck/src/op.rs @@ -26,7 +26,7 @@ use crate::Expectation; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Checks a `a = 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, diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs index 19779740227ba..ce40ab182613c 100644 --- a/compiler/rustc_middle/src/ty/generics.rs +++ b/compiler/rustc_middle/src/ty/generics.rs @@ -86,10 +86,10 @@ impl GenericParamDef { tcx: TyCtxt<'tcx>, ) -> Option>> { 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, diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 1a5c29afdc939..c845d60ac0715 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -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 diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 087ba0522ebe2..f485e8cace54d 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -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 [TRACKED], optimize: OptLevel [TRACKED], /// Include the `debug_assertions` flag in dependency tracking, since it diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index f89fd0f7f2ae5..42c6221dc573e 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1568,6 +1568,8 @@ symbols! { readonly, realloc, reason, + receiver, + receiver_target, recursion_limit, reexport_test_harness_main, ref_pat_eat_one_layer_2024, diff --git a/library/core/src/ops/deref.rs b/library/core/src/ops/deref.rs index 1ef9990c00af8..45688727c9b36 100644 --- a/library/core/src/ops/deref.rs +++ b/library/core/src/ops/deref.rs @@ -294,14 +294,98 @@ unsafe impl DerefPure for &T {} #[unstable(feature = "deref_pure_trait", issue = "87121")] unsafe impl 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); +/// +/// impl Receiver for SmartPointer { +/// type Target = T; +/// } +/// +/// struct MyContainedType; +/// +/// impl MyContainedType { +/// fn method(self: SmartPointer) { +/// // ... +/// } +/// } +/// +/// 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`,`Rc`, `&T`, +/// and `Pin

`. 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) { +/// +/// } +/// fn method_c(self: &Rc>) { +/// +/// } +/// } +/// ``` +#[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 Receiver for P +where + P: Deref, +{ + 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`, /// `Rc`, `&T`, and `Pin

`. /// /// 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")] diff --git a/library/core/src/ops/mod.rs b/library/core/src/ops/mod.rs index c9f47e5daadd6..cea1f84f3fd60 100644 --- a/library/core/src/ops/mod.rs +++ b/library/core/src/ops/mod.rs @@ -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")] diff --git a/library/std/src/collections/hash/set.rs b/library/std/src/collections/hash/set.rs index e1e0eb36d23f0..f86bcdb4796ec 100644 --- a/library/std/src/collections/hash/set.rs +++ b/library/std/src/collections/hash/set.rs @@ -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 Clone for HashSet 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 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 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 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 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> { diff --git a/tests/ui-fulldeps/internal-lints/bad_opt_access.rs b/tests/ui-fulldeps/internal-lints/bad_opt_access.rs index 708c3651b87be..a2a94db919d8b 100644 --- a/tests/ui-fulldeps/internal-lints/bad_opt_access.rs +++ b/tests/ui-fulldeps/internal-lints/bad_opt_access.rs @@ -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! diff --git a/tests/ui-fulldeps/internal-lints/bad_opt_access.stderr b/tests/ui-fulldeps/internal-lints/bad_opt_access.stderr index e4145bff8bee9..35b179f2a3ab0 100644 --- a/tests/ui-fulldeps/internal-lints/bad_opt_access.stderr +++ b/tests/ui-fulldeps/internal-lints/bad_opt_access.stderr @@ -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; diff --git a/triagebot.toml b/triagebot.toml index 4eb80f2058de4..f31dd5cd3d888 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -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",