mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 00:03:43 +00:00
Auto merge of #132919 - matthiaskrgr:rollup-ogghyvp, r=matthiaskrgr
Rollup of 7 pull requests Successful merges: - #120077 (Add Set entry API ) - #132144 (Arbitrary self types v2: (unused) Receiver trait) - #132297 (Document some `check_expr` methods, and other misc `hir_typeck` tweaks) - #132820 (Add a default implementation for CodegenBackend::link) - #132881 (triagebot: Autolabel rustdoc book) - #132912 (Simplify some places that deal with generic parameter defaults) - #132916 (Unvacation fmease) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
67f21277cd
@ -1,12 +0,0 @@
|
|||||||
use rustc_codegen_ssa::back::archive::{
|
|
||||||
ArArchiveBuilder, ArchiveBuilder, ArchiveBuilderBuilder, DEFAULT_OBJECT_READER,
|
|
||||||
};
|
|
||||||
use rustc_session::Session;
|
|
||||||
|
|
||||||
pub(crate) struct ArArchiveBuilderBuilder;
|
|
||||||
|
|
||||||
impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder {
|
|
||||||
fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box<dyn ArchiveBuilder + 'a> {
|
|
||||||
Box::new(ArArchiveBuilder::new(sess, &DEFAULT_OBJECT_READER))
|
|
||||||
}
|
|
||||||
}
|
|
@ -43,7 +43,6 @@ use rustc_codegen_ssa::CodegenResults;
|
|||||||
use rustc_codegen_ssa::back::versioned_llvm_target;
|
use rustc_codegen_ssa::back::versioned_llvm_target;
|
||||||
use rustc_codegen_ssa::traits::CodegenBackend;
|
use rustc_codegen_ssa::traits::CodegenBackend;
|
||||||
use rustc_data_structures::profiling::SelfProfilerRef;
|
use rustc_data_structures::profiling::SelfProfilerRef;
|
||||||
use rustc_errors::ErrorGuaranteed;
|
|
||||||
use rustc_metadata::EncodedMetadata;
|
use rustc_metadata::EncodedMetadata;
|
||||||
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
|
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
|
||||||
use rustc_session::Session;
|
use rustc_session::Session;
|
||||||
@ -56,7 +55,6 @@ use crate::prelude::*;
|
|||||||
mod abi;
|
mod abi;
|
||||||
mod allocator;
|
mod allocator;
|
||||||
mod analyze;
|
mod analyze;
|
||||||
mod archive;
|
|
||||||
mod base;
|
mod base;
|
||||||
mod cast;
|
mod cast;
|
||||||
mod codegen_i128;
|
mod codegen_i128;
|
||||||
@ -249,17 +247,6 @@ impl CodegenBackend for CraneliftCodegenBackend {
|
|||||||
self.config.borrow().as_ref().unwrap(),
|
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 {
|
fn target_triple(sess: &Session) -> target_lexicon::Triple {
|
||||||
|
@ -1,25 +0,0 @@
|
|||||||
use std::path::Path;
|
|
||||||
|
|
||||||
use rustc_codegen_ssa::back::archive::{
|
|
||||||
ArArchiveBuilder, ArchiveBuilder, ArchiveBuilderBuilder, DEFAULT_OBJECT_READER,
|
|
||||||
ImportLibraryItem,
|
|
||||||
};
|
|
||||||
use rustc_session::Session;
|
|
||||||
|
|
||||||
pub(crate) struct ArArchiveBuilderBuilder;
|
|
||||||
|
|
||||||
impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder {
|
|
||||||
fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box<dyn ArchiveBuilder + 'a> {
|
|
||||||
Box::new(ArArchiveBuilder::new(sess, &DEFAULT_OBJECT_READER))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create_dll_import_lib(
|
|
||||||
&self,
|
|
||||||
_sess: &Session,
|
|
||||||
_lib_name: &str,
|
|
||||||
_items: Vec<ImportLibraryItem>,
|
|
||||||
_output_path: &Path,
|
|
||||||
) {
|
|
||||||
unimplemented!("creating dll imports is not yet supported");
|
|
||||||
}
|
|
||||||
}
|
|
@ -58,7 +58,6 @@ extern crate rustc_driver;
|
|||||||
|
|
||||||
mod abi;
|
mod abi;
|
||||||
mod allocator;
|
mod allocator;
|
||||||
mod archive;
|
|
||||||
mod asm;
|
mod asm;
|
||||||
mod attributes;
|
mod attributes;
|
||||||
mod back;
|
mod back;
|
||||||
@ -103,7 +102,7 @@ use rustc_codegen_ssa::traits::{CodegenBackend, ExtraBackendMethods, WriteBacken
|
|||||||
use rustc_codegen_ssa::{CodegenResults, CompiledModule, ModuleCodegen};
|
use rustc_codegen_ssa::{CodegenResults, CompiledModule, ModuleCodegen};
|
||||||
use rustc_data_structures::fx::FxIndexMap;
|
use rustc_data_structures::fx::FxIndexMap;
|
||||||
use rustc_data_structures::sync::IntoDynSyncSend;
|
use rustc_data_structures::sync::IntoDynSyncSend;
|
||||||
use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed};
|
use rustc_errors::DiagCtxtHandle;
|
||||||
use rustc_metadata::EncodedMetadata;
|
use rustc_metadata::EncodedMetadata;
|
||||||
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
|
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
|
||||||
use rustc_middle::ty::TyCtxt;
|
use rustc_middle::ty::TyCtxt;
|
||||||
@ -261,17 +260,6 @@ impl CodegenBackend for GccCodegenBackend {
|
|||||||
.join(sess)
|
.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> {
|
fn target_features(&self, sess: &Session, allow_unstable: bool) -> Vec<Symbol> {
|
||||||
target_features(sess, allow_unstable, &self.target_info)
|
target_features(sess, allow_unstable, &self.target_info)
|
||||||
}
|
}
|
||||||
|
@ -382,7 +382,7 @@ impl CodegenBackend for LlvmCodegenBackend {
|
|||||||
|
|
||||||
// Run the linker on any artifacts that resulted from the LLVM run.
|
// Run the linker on any artifacts that resulted from the LLVM run.
|
||||||
// This should produce either a finished executable or library.
|
// This should produce either a finished executable or library.
|
||||||
link_binary(sess, &LlvmArchiveBuilderBuilder, &codegen_results, outputs)
|
link_binary(sess, &LlvmArchiveBuilderBuilder, codegen_results, outputs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -304,6 +304,14 @@ pub trait ArchiveBuilder {
|
|||||||
fn build(self: Box<Self>, output: &Path) -> bool;
|
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"]
|
#[must_use = "must call build() to finish building the archive"]
|
||||||
pub struct ArArchiveBuilder<'a> {
|
pub struct ArArchiveBuilder<'a> {
|
||||||
sess: &'a Session,
|
sess: &'a Session,
|
||||||
|
@ -69,7 +69,7 @@ pub fn ensure_removed(dcx: DiagCtxtHandle<'_>, path: &Path) {
|
|||||||
pub fn link_binary(
|
pub fn link_binary(
|
||||||
sess: &Session,
|
sess: &Session,
|
||||||
archive_builder_builder: &dyn ArchiveBuilderBuilder,
|
archive_builder_builder: &dyn ArchiveBuilderBuilder,
|
||||||
codegen_results: &CodegenResults,
|
codegen_results: CodegenResults,
|
||||||
outputs: &OutputFilenames,
|
outputs: &OutputFilenames,
|
||||||
) -> Result<(), ErrorGuaranteed> {
|
) -> Result<(), ErrorGuaranteed> {
|
||||||
let _timer = sess.timer("link_binary");
|
let _timer = sess.timer("link_binary");
|
||||||
@ -116,7 +116,7 @@ pub fn link_binary(
|
|||||||
link_rlib(
|
link_rlib(
|
||||||
sess,
|
sess,
|
||||||
archive_builder_builder,
|
archive_builder_builder,
|
||||||
codegen_results,
|
&codegen_results,
|
||||||
RlibFlavor::Normal,
|
RlibFlavor::Normal,
|
||||||
&path,
|
&path,
|
||||||
)?
|
)?
|
||||||
@ -126,7 +126,7 @@ pub fn link_binary(
|
|||||||
link_staticlib(
|
link_staticlib(
|
||||||
sess,
|
sess,
|
||||||
archive_builder_builder,
|
archive_builder_builder,
|
||||||
codegen_results,
|
&codegen_results,
|
||||||
&out_filename,
|
&out_filename,
|
||||||
&path,
|
&path,
|
||||||
)?;
|
)?;
|
||||||
@ -137,7 +137,7 @@ pub fn link_binary(
|
|||||||
archive_builder_builder,
|
archive_builder_builder,
|
||||||
crate_type,
|
crate_type,
|
||||||
&out_filename,
|
&out_filename,
|
||||||
codegen_results,
|
&codegen_results,
|
||||||
path.as_ref(),
|
path.as_ref(),
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,8 @@ use rustc_span::symbol::Symbol;
|
|||||||
|
|
||||||
use super::CodegenObject;
|
use super::CodegenObject;
|
||||||
use super::write::WriteBackendMethods;
|
use super::write::WriteBackendMethods;
|
||||||
|
use crate::back::archive::ArArchiveBuilderBuilder;
|
||||||
|
use crate::back::link::link_binary;
|
||||||
use crate::back::write::TargetMachineFactoryFn;
|
use crate::back::write::TargetMachineFactoryFn;
|
||||||
use crate::{CodegenResults, ModuleCodegen};
|
use crate::{CodegenResults, ModuleCodegen};
|
||||||
|
|
||||||
@ -87,7 +89,9 @@ pub trait CodegenBackend {
|
|||||||
sess: &Session,
|
sess: &Session,
|
||||||
codegen_results: CodegenResults,
|
codegen_results: CodegenResults,
|
||||||
outputs: &OutputFilenames,
|
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.
|
/// Returns `true` if this backend can be safely called from multiple threads.
|
||||||
///
|
///
|
||||||
|
@ -241,6 +241,8 @@ language_item_table! {
|
|||||||
DerefMut, sym::deref_mut, deref_mut_trait, Target::Trait, GenericRequirement::Exact(0);
|
DerefMut, sym::deref_mut, deref_mut_trait, Target::Trait, GenericRequirement::Exact(0);
|
||||||
DerefPure, sym::deref_pure, deref_pure_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;
|
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;
|
LegacyReceiver, sym::legacy_receiver, legacy_receiver_trait, Target::Trait, GenericRequirement::None;
|
||||||
|
|
||||||
Fn, kw::Fn, fn_trait, Target::Trait, GenericRequirement::Exact(1);
|
Fn, kw::Fn, fn_trait, Target::Trait, GenericRequirement::Exact(1);
|
||||||
|
@ -1427,16 +1427,6 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
|
|||||||
let predicates = tcx.predicates_of(def_id.to_def_id());
|
let predicates = tcx.predicates_of(def_id.to_def_id());
|
||||||
let generics = tcx.generics_of(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`.
|
// Check that concrete defaults are well-formed. See test `type-check-defaults.rs`.
|
||||||
// For example, this forbids the declaration:
|
// 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.
|
// Here, the default `Vec<[u32]>` is not WF because `[u32]: Sized` does not hold.
|
||||||
for param in &generics.own_params {
|
for param in &generics.own_params {
|
||||||
match param.kind {
|
if let Some(default) = param.default_value(tcx).map(ty::EarlyBinder::instantiate_identity) {
|
||||||
GenericParamDefKind::Type { .. } => {
|
// Ignore dependent defaults -- that is, where the default of one type
|
||||||
if is_our_default(param) {
|
// parameter includes another (e.g., `<T, U = T>`). In those cases, we can't
|
||||||
let ty = tcx.type_of(param.def_id).instantiate_identity();
|
// be sure if it will error or not as user might always specify the other.
|
||||||
// Ignore dependent defaults -- that is, where the default of one type
|
// FIXME(generic_const_exprs): This is incorrect when dealing with unused const params.
|
||||||
// parameter includes another (e.g., `<T, U = T>`). In those cases, we can't
|
// E.g: `struct Foo<const N: usize, const M: usize = { 1 - 2 }>;`. Here, we should
|
||||||
// be sure if it will error or not as user might always specify the other.
|
// eagerly error but we don't as we have `ConstKind::Unevaluated(.., [N, M])`.
|
||||||
if !ty.has_param() {
|
if !default.has_param() {
|
||||||
wfcx.register_wf_obligation(
|
wfcx.register_wf_obligation(
|
||||||
tcx.def_span(param.def_id),
|
tcx.def_span(param.def_id),
|
||||||
Some(WellFormedLoc::Ty(param.def_id.expect_local())),
|
matches!(param.kind, GenericParamDefKind::Type { .. })
|
||||||
ty.into(),
|
.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.
|
// First we build the defaulted generic parameters.
|
||||||
let args = GenericArgs::for_item(tcx, def_id.to_def_id(), |param, _| {
|
let args = GenericArgs::for_item(tcx, def_id.to_def_id(), |param, _| {
|
||||||
match param.kind {
|
if param.index >= generics.parent_count as u32
|
||||||
GenericParamDefKind::Lifetime => {
|
// If the param has a default, ...
|
||||||
// All regions are identity.
|
&& let Some(default) = param.default_value(tcx).map(ty::EarlyBinder::instantiate_identity)
|
||||||
tcx.mk_param_from_def(param)
|
// ... and it's not a dependent default, ...
|
||||||
}
|
&& !default.has_param()
|
||||||
|
{
|
||||||
GenericParamDefKind::Type { .. } => {
|
// ... then instantiate it with the default.
|
||||||
// If the param has a default, ...
|
return 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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
tcx.mk_param_from_def(param)
|
||||||
});
|
});
|
||||||
|
|
||||||
// Now we build the instantiated predicates.
|
// Now we build the instantiated predicates.
|
||||||
|
@ -15,7 +15,7 @@ use crate::{Diverges, Expectation, FnCtxt, Needs};
|
|||||||
|
|
||||||
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
#[instrument(skip(self), level = "debug", ret)]
|
#[instrument(skip(self), level = "debug", ret)]
|
||||||
pub(crate) fn check_match(
|
pub(crate) fn check_expr_match(
|
||||||
&self,
|
&self,
|
||||||
expr: &'tcx hir::Expr<'tcx>,
|
expr: &'tcx hir::Expr<'tcx>,
|
||||||
scrut: &'tcx hir::Expr<'tcx>,
|
scrut: &'tcx hir::Expr<'tcx>,
|
||||||
|
@ -62,7 +62,7 @@ enum CallStep<'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
pub(crate) fn check_call(
|
pub(crate) fn check_expr_call(
|
||||||
&self,
|
&self,
|
||||||
call_expr: &'tcx hir::Expr<'tcx>,
|
call_expr: &'tcx hir::Expr<'tcx>,
|
||||||
callee_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(
|
.check_expr_with_expectation_and_args(
|
||||||
callee_expr,
|
callee_expr,
|
||||||
Expectation::NoExpectation,
|
Expectation::NoExpectation,
|
||||||
arg_exprs,
|
Some((call_expr, arg_exprs)),
|
||||||
Some(call_expr),
|
|
||||||
),
|
),
|
||||||
_ => self.check_expr(callee_expr),
|
_ => self.check_expr(callee_expr),
|
||||||
};
|
};
|
||||||
|
@ -137,7 +137,7 @@ pub(super) fn check_fn<'a, 'tcx>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fcx.is_whole_body.set(true);
|
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
|
// 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
|
// we saw and assigning it to the expected return type. This isn't
|
||||||
|
@ -55,6 +55,9 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
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(
|
pub(crate) fn check_expr_has_type_or_error(
|
||||||
&self,
|
&self,
|
||||||
expr: &'tcx hir::Expr<'tcx>,
|
expr: &'tcx hir::Expr<'tcx>,
|
||||||
@ -97,6 +100,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
ty
|
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(
|
pub(super) fn check_expr_coercible_to_type(
|
||||||
&self,
|
&self,
|
||||||
expr: &'tcx hir::Expr<'tcx>,
|
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(
|
pub(super) fn check_expr_with_hint(
|
||||||
&self,
|
&self,
|
||||||
expr: &'tcx hir::Expr<'tcx>,
|
expr: &'tcx hir::Expr<'tcx>,
|
||||||
@ -136,6 +146,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
self.check_expr_with_expectation(expr, ExpectHasType(expected))
|
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(
|
fn check_expr_with_expectation_and_needs(
|
||||||
&self,
|
&self,
|
||||||
expr: &'tcx hir::Expr<'tcx>,
|
expr: &'tcx hir::Expr<'tcx>,
|
||||||
@ -153,10 +165,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
ty
|
ty
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check an expr with no expectations.
|
||||||
pub(super) fn check_expr(&self, expr: &'tcx hir::Expr<'tcx>) -> Ty<'tcx> {
|
pub(super) fn check_expr(&self, expr: &'tcx hir::Expr<'tcx>) -> Ty<'tcx> {
|
||||||
self.check_expr_with_expectation(expr, NoExpectation)
|
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(
|
pub(super) fn check_expr_with_needs(
|
||||||
&self,
|
&self,
|
||||||
expr: &'tcx hir::Expr<'tcx>,
|
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)
|
self.check_expr_with_expectation_and_needs(expr, NoExpectation, needs)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Invariant:
|
/// Check an expr with an expectation type which may be used to eagerly
|
||||||
/// If an expression has any sub-expressions that result in a type error,
|
/// guide inference when evaluating that expr.
|
||||||
/// 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.
|
|
||||||
#[instrument(skip(self, expr), level = "debug")]
|
#[instrument(skip(self, expr), level = "debug")]
|
||||||
pub(super) fn check_expr_with_expectation(
|
pub(super) fn check_expr_with_expectation(
|
||||||
&self,
|
&self,
|
||||||
expr: &'tcx hir::Expr<'tcx>,
|
expr: &'tcx hir::Expr<'tcx>,
|
||||||
expected: Expectation<'tcx>,
|
expected: Expectation<'tcx>,
|
||||||
) -> Ty<'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
|
/// Same as [`Self::check_expr_with_expectation`], but allows us to pass in
|
||||||
/// `ExprKind::Call` when evaluating its callee when it is an `ExprKind::Path`.
|
/// 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(
|
pub(super) fn check_expr_with_expectation_and_args(
|
||||||
&self,
|
&self,
|
||||||
expr: &'tcx hir::Expr<'tcx>,
|
expr: &'tcx hir::Expr<'tcx>,
|
||||||
expected: Expectation<'tcx>,
|
expected: Expectation<'tcx>,
|
||||||
args: &'tcx [hir::Expr<'tcx>],
|
call_expr_and_args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>])>,
|
||||||
call: Option<&'tcx hir::Expr<'tcx>>,
|
|
||||||
) -> Ty<'tcx> {
|
) -> Ty<'tcx> {
|
||||||
if self.tcx().sess.verbose_internals() {
|
if self.tcx().sess.verbose_internals() {
|
||||||
// make this code only run with -Zverbose-internals because it is probably slow
|
// 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 {
|
let ty = ensure_sufficient_stack(|| match &expr.kind {
|
||||||
|
// Intercept the callee path expr and give it better spans.
|
||||||
hir::ExprKind::Path(
|
hir::ExprKind::Path(
|
||||||
qpath @ (hir::QPath::Resolved(..) | hir::QPath::TypeRelative(..)),
|
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),
|
_ => self.check_expr_kind(expr, expected),
|
||||||
});
|
});
|
||||||
let ty = self.resolve_vars_if_possible(ty);
|
let ty = self.resolve_vars_if_possible(ty);
|
||||||
@ -472,28 +481,30 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
|
|
||||||
let tcx = self.tcx;
|
let tcx = self.tcx;
|
||||||
match expr.kind {
|
match expr.kind {
|
||||||
ExprKind::Lit(ref lit) => self.check_lit(lit, expected),
|
ExprKind::Lit(ref lit) => self.check_expr_lit(lit, expected),
|
||||||
ExprKind::Binary(op, lhs, rhs) => self.check_binop(expr, op, lhs, rhs, expected),
|
ExprKind::Binary(op, lhs, rhs) => self.check_expr_binop(expr, op, lhs, rhs, expected),
|
||||||
ExprKind::Assign(lhs, rhs, span) => {
|
ExprKind::Assign(lhs, rhs, span) => {
|
||||||
self.check_expr_assign(expr, expected, lhs, rhs, span)
|
self.check_expr_assign(expr, expected, lhs, rhs, span)
|
||||||
}
|
}
|
||||||
ExprKind::AssignOp(op, lhs, rhs) => {
|
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) => {
|
ExprKind::AddrOf(kind, mutbl, oprnd) => {
|
||||||
self.check_expr_addr_of(kind, mutbl, oprnd, expected, expr)
|
self.check_expr_addr_of(kind, mutbl, oprnd, expected, expr)
|
||||||
}
|
}
|
||||||
ExprKind::Path(QPath::LangItem(lang_item, _)) => {
|
ExprKind::Path(QPath::LangItem(lang_item, _)) => {
|
||||||
self.check_lang_item_path(lang_item, expr)
|
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) => {
|
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).
|
// 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.deferred_asm_checks.borrow_mut().push((asm, expr.hir_id));
|
||||||
self.check_expr_asm(asm)
|
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) => {
|
ExprKind::Break(destination, ref expr_opt) => {
|
||||||
self.check_expr_break(destination, expr_opt.as_deref(), expr)
|
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)
|
self.check_expr_loop(body, source, expected, expr)
|
||||||
}
|
}
|
||||||
ExprKind::Match(discrim, arms, match_src) => {
|
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::Closure(closure) => self.check_expr_closure(closure, expr.span, expected),
|
||||||
ExprKind::Block(body, _) => self.check_block_with_expected(body, expected),
|
ExprKind::Block(body, _) => self.check_expr_block(body, expected),
|
||||||
ExprKind::Call(callee, args) => self.check_call(expr, callee, args, expected),
|
ExprKind::Call(callee, args) => self.check_expr_call(expr, callee, args, expected),
|
||||||
ExprKind::MethodCall(segment, receiver, args, _) => {
|
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::Cast(e, t) => self.check_expr_cast(e, t, expr),
|
||||||
ExprKind::Type(e, t) => {
|
ExprKind::Type(e, t) => {
|
||||||
@ -528,7 +539,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
ascribed_ty
|
ascribed_ty
|
||||||
}
|
}
|
||||||
ExprKind::If(cond, then_expr, opt_else_expr) => {
|
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::DropTemps(e) => self.check_expr_with_expectation(e, expected),
|
||||||
ExprKind::Array(args) => self.check_expr_array(args, expected, expr),
|
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) => {
|
ExprKind::Struct(qpath, fields, ref base_expr) => {
|
||||||
self.check_expr_struct(expr, expected, qpath, fields, 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) => {
|
ExprKind::Index(base, idx, brackets_span) => {
|
||||||
self.check_expr_index(base, idx, expr, 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,
|
&self,
|
||||||
unop: hir::UnOp,
|
unop: hir::UnOp,
|
||||||
oprnd: &'tcx hir::Expr<'tcx>,
|
oprnd: &'tcx hir::Expr<'tcx>,
|
||||||
@ -699,8 +710,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
&self,
|
&self,
|
||||||
qpath: &'tcx hir::QPath<'tcx>,
|
qpath: &'tcx hir::QPath<'tcx>,
|
||||||
expr: &'tcx hir::Expr<'tcx>,
|
expr: &'tcx hir::Expr<'tcx>,
|
||||||
args: Option<&'tcx [hir::Expr<'tcx>]>,
|
call_expr_and_args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>])>,
|
||||||
call: Option<&'tcx hir::Expr<'tcx>>,
|
|
||||||
) -> Ty<'tcx> {
|
) -> Ty<'tcx> {
|
||||||
let tcx = self.tcx;
|
let tcx = self.tcx;
|
||||||
let (res, opt_ty, segs) =
|
let (res, opt_ty, segs) =
|
||||||
@ -730,7 +740,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
segs,
|
segs,
|
||||||
opt_ty,
|
opt_ty,
|
||||||
res,
|
res,
|
||||||
call.map_or(expr.span, |e| e.span),
|
call_expr_and_args.map_or(expr.span, |(e, _)| e.span),
|
||||||
expr.span,
|
expr.span,
|
||||||
expr.hir_id,
|
expr.hir_id,
|
||||||
)
|
)
|
||||||
@ -769,7 +779,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
// We just want to check sizedness, so instead of introducing
|
// We just want to check sizedness, so instead of introducing
|
||||||
// placeholder lifetimes with probing, we just replace higher lifetimes
|
// placeholder lifetimes with probing, we just replace higher lifetimes
|
||||||
// with fresh vars.
|
// 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(
|
let input = self.instantiate_binder_with_fresh_vars(
|
||||||
span,
|
span,
|
||||||
infer::BoundRegionConversionTime::FnCall,
|
infer::BoundRegionConversionTime::FnCall,
|
||||||
@ -795,7 +807,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
);
|
);
|
||||||
self.require_type_is_sized_deferred(
|
self.require_type_is_sized_deferred(
|
||||||
output,
|
output,
|
||||||
call.map_or(expr.span, |e| e.span),
|
call_expr_and_args.map_or(expr.span, |(e, _)| e.span),
|
||||||
ObligationCauseCode::SizedCallReturnType,
|
ObligationCauseCode::SizedCallReturnType,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -972,7 +984,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
if self.ret_coercion_span.get().is_none() {
|
if self.ret_coercion_span.get().is_none() {
|
||||||
self.ret_coercion_span.set(Some(e.span));
|
self.ret_coercion_span.set(Some(e.span));
|
||||||
}
|
}
|
||||||
self.check_return_expr(e, true);
|
self.check_return_or_body_tail(e, true);
|
||||||
} else {
|
} else {
|
||||||
let mut coercion = self.ret_coercion.as_ref().unwrap().borrow_mut();
|
let mut coercion = self.ret_coercion.as_ref().unwrap().borrow_mut();
|
||||||
if self.ret_coercion_span.get().is_none() {
|
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`,
|
/// `explicit_return` is `true` if we're checking an explicit `return expr`,
|
||||||
/// and `false` if we're checking a trailing expression.
|
/// and `false` if we're checking a trailing expression.
|
||||||
pub(super) fn check_return_expr(
|
pub(super) fn check_return_or_body_tail(
|
||||||
&self,
|
&self,
|
||||||
return_expr: &'tcx hir::Expr<'tcx>,
|
return_expr: &'tcx hir::Expr<'tcx>,
|
||||||
explicit_return: bool,
|
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'
|
// A generic function for checking the 'then' and 'else' clauses in an 'if'
|
||||||
// or 'if-else' expression.
|
// or 'if-else' expression.
|
||||||
fn check_then_else(
|
fn check_expr_if(
|
||||||
&self,
|
&self,
|
||||||
cond_expr: &'tcx hir::Expr<'tcx>,
|
cond_expr: &'tcx hir::Expr<'tcx>,
|
||||||
then_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.
|
/// Checks a method call.
|
||||||
fn check_method_call(
|
fn check_expr_method_call(
|
||||||
&self,
|
&self,
|
||||||
expr: &'tcx hir::Expr<'tcx>,
|
expr: &'tcx hir::Expr<'tcx>,
|
||||||
segment: &'tcx hir::PathSegment<'tcx>,
|
segment: &'tcx hir::PathSegment<'tcx>,
|
||||||
@ -2594,7 +2606,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check field access expressions
|
// Check field access expressions
|
||||||
fn check_field(
|
fn check_expr_field(
|
||||||
&self,
|
&self,
|
||||||
expr: &'tcx hir::Expr<'tcx>,
|
expr: &'tcx hir::Expr<'tcx>,
|
||||||
base: &'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();
|
let previous_diverges = self.diverges.get();
|
||||||
|
|
||||||
// The label blocks should have unit return value or diverge.
|
// The label blocks should have unit return value or diverge.
|
||||||
let ty =
|
let ty = self.check_expr_block(block, ExpectHasType(self.tcx.types.unit));
|
||||||
self.check_block_with_expected(block, ExpectHasType(self.tcx.types.unit));
|
|
||||||
if !ty.is_never() {
|
if !ty.is_never() {
|
||||||
self.demand_suptype(block.span, self.tcx.types.unit, ty);
|
self.demand_suptype(block.span, self.tcx.types.unit, ty);
|
||||||
diverge = false;
|
diverge = false;
|
||||||
@ -3551,7 +3562,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
if diverge { self.tcx.types.never } else { self.tcx.types.unit }
|
if diverge { self.tcx.types.never } else { self.tcx.types.unit }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_offset_of(
|
fn check_expr_offset_of(
|
||||||
&self,
|
&self,
|
||||||
container: &'tcx hir::Ty<'tcx>,
|
container: &'tcx hir::Ty<'tcx>,
|
||||||
fields: &[Ident],
|
fields: &[Ident],
|
||||||
|
@ -1306,30 +1306,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
rustc_hir_analysis::hir_ty_lowering::RegionInferReason::Param(param),
|
rustc_hir_analysis::hir_ty_lowering::RegionInferReason::Param(param),
|
||||||
)
|
)
|
||||||
.into(),
|
.into(),
|
||||||
GenericParamDefKind::Type { has_default, .. } => {
|
GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => {
|
||||||
if !infer_args && has_default {
|
if !infer_args && let Some(default) = param.default_value(tcx) {
|
||||||
// If we have a default, then it doesn't matter that we're not
|
// If we have a default, then it doesn't matter that we're not inferring
|
||||||
// inferring the type arguments: we provide the default where any
|
// the type/const arguments: We provide the default where any is missing.
|
||||||
// is missing.
|
return default.instantiate(tcx, preceding_args);
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
}
|
// If no type/const arguments were provided, we have to infer them.
|
||||||
GenericParamDefKind::Const { has_default, .. } => {
|
// This case also occurs as a result of some malformed input, e.g.,
|
||||||
if has_default {
|
// a lifetime argument being given instead of a type/const parameter.
|
||||||
if !infer_args {
|
// Using inference instead of `Error` gives better error messages.
|
||||||
return tcx
|
|
||||||
.const_param_default(param.def_id)
|
|
||||||
.instantiate(tcx, preceding_args)
|
|
||||||
.into();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.fcx.var_for_def(self.span, param)
|
self.fcx.var_for_def(self.span, param)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1565,7 +1565,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// AST fragment checking
|
// AST fragment checking
|
||||||
pub(in super::super) fn check_lit(
|
pub(in super::super) fn check_expr_lit(
|
||||||
&self,
|
&self,
|
||||||
lit: &hir::Lit,
|
lit: &hir::Lit,
|
||||||
expected: Expectation<'tcx>,
|
expected: Expectation<'tcx>,
|
||||||
@ -1747,7 +1747,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
|
|
||||||
if let Some(blk) = decl.origin.try_get_else() {
|
if let Some(blk) = decl.origin.try_get_else() {
|
||||||
let previous_diverges = self.diverges.get();
|
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);
|
let cause = self.cause(blk.span, ObligationCauseCode::LetElse);
|
||||||
if let Err(err) = self.demand_eqtype_with_origin(&cause, self.tcx.types.never, else_ty)
|
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>) {
|
pub(crate) fn check_block_no_value(&self, blk: &'tcx hir::Block<'tcx>) {
|
||||||
let unit = self.tcx.types.unit;
|
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
|
// if the block produces a `!` value, that can always be
|
||||||
// (effectively) coerced to unit.
|
// (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,
|
&self,
|
||||||
blk: &'tcx hir::Block<'tcx>,
|
blk: &'tcx hir::Block<'tcx>,
|
||||||
expected: Expectation<'tcx>,
|
expected: Expectation<'tcx>,
|
||||||
|
@ -26,7 +26,7 @@ use crate::Expectation;
|
|||||||
|
|
||||||
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
/// Checks a `a <op>= b`
|
/// Checks a `a <op>= b`
|
||||||
pub(crate) fn check_binop_assign(
|
pub(crate) fn check_expr_binop_assign(
|
||||||
&self,
|
&self,
|
||||||
expr: &'tcx hir::Expr<'tcx>,
|
expr: &'tcx hir::Expr<'tcx>,
|
||||||
op: hir::BinOp,
|
op: hir::BinOp,
|
||||||
@ -85,7 +85,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Checks a potentially overloaded binary operator.
|
/// Checks a potentially overloaded binary operator.
|
||||||
pub(crate) fn check_binop(
|
pub(crate) fn check_expr_binop(
|
||||||
&self,
|
&self,
|
||||||
expr: &'tcx hir::Expr<'tcx>,
|
expr: &'tcx hir::Expr<'tcx>,
|
||||||
op: hir::BinOp,
|
op: hir::BinOp,
|
||||||
|
@ -86,10 +86,10 @@ impl GenericParamDef {
|
|||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
) -> Option<EarlyBinder<'tcx, ty::GenericArg<'tcx>>> {
|
) -> Option<EarlyBinder<'tcx, ty::GenericArg<'tcx>>> {
|
||||||
match self.kind {
|
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()))
|
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()))
|
Some(tcx.const_param_default(self.def_id).map_bound(|c| c.into()))
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
|
@ -782,21 +782,11 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
|
|||||||
impl ReachEverythingInTheInterfaceVisitor<'_, '_> {
|
impl ReachEverythingInTheInterfaceVisitor<'_, '_> {
|
||||||
fn generics(&mut self) -> &mut Self {
|
fn generics(&mut self) -> &mut Self {
|
||||||
for param in &self.ev.tcx.generics_of(self.item_def_id).own_params {
|
for param in &self.ev.tcx.generics_of(self.item_def_id).own_params {
|
||||||
match param.kind {
|
if let GenericParamDefKind::Const { .. } = param.kind {
|
||||||
GenericParamDefKind::Lifetime => {}
|
self.visit(self.ev.tcx.type_of(param.def_id).instantiate_identity());
|
||||||
GenericParamDefKind::Type { has_default, .. } => {
|
}
|
||||||
if has_default {
|
if let Some(default) = param.default_value(self.ev.tcx) {
|
||||||
self.visit(self.ev.tcx.type_of(param.def_id).instantiate_identity());
|
self.visit(default.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(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self
|
self
|
||||||
|
@ -130,7 +130,7 @@ top_level_options!(
|
|||||||
pub struct Options {
|
pub struct Options {
|
||||||
/// The crate config requested for the session, which may be combined
|
/// The crate config requested for the session, which may be combined
|
||||||
/// with additional crate configurations during the compile process.
|
/// 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],
|
crate_types: Vec<CrateType> [TRACKED],
|
||||||
optimize: OptLevel [TRACKED],
|
optimize: OptLevel [TRACKED],
|
||||||
/// Include the `debug_assertions` flag in dependency tracking, since it
|
/// Include the `debug_assertions` flag in dependency tracking, since it
|
||||||
|
@ -1568,6 +1568,8 @@ symbols! {
|
|||||||
readonly,
|
readonly,
|
||||||
realloc,
|
realloc,
|
||||||
reason,
|
reason,
|
||||||
|
receiver,
|
||||||
|
receiver_target,
|
||||||
recursion_limit,
|
recursion_limit,
|
||||||
reexport_test_harness_main,
|
reexport_test_harness_main,
|
||||||
ref_pat_eat_one_layer_2024,
|
ref_pat_eat_one_layer_2024,
|
||||||
|
@ -294,14 +294,98 @@ unsafe impl<T: ?Sized> DerefPure for &T {}
|
|||||||
#[unstable(feature = "deref_pure_trait", issue = "87121")]
|
#[unstable(feature = "deref_pure_trait", issue = "87121")]
|
||||||
unsafe impl<T: ?Sized> DerefPure for &mut T {}
|
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
|
/// 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>`,
|
/// `arbitrary_self_types` feature. This is implemented by stdlib pointer types like `Box<T>`,
|
||||||
/// `Rc<T>`, `&T`, and `Pin<P>`.
|
/// `Rc<T>`, `&T`, and `Pin<P>`.
|
||||||
///
|
///
|
||||||
/// This trait will shortly be removed and replaced with a more generic
|
/// This trait will shortly be removed and replaced with a more generic
|
||||||
/// facility based around the current "arbitrary self types" unstable feature.
|
/// facility based around the current "arbitrary self types" unstable feature.
|
||||||
/// That new facility will use a replacement trait called `Receiver` which is
|
/// That new facility will use the replacement trait above called `Receiver`
|
||||||
/// why this is now named `LegacyReceiver`.
|
/// which is why this is now named `LegacyReceiver`.
|
||||||
#[cfg_attr(bootstrap, lang = "receiver")]
|
#[cfg_attr(bootstrap, lang = "receiver")]
|
||||||
#[cfg_attr(not(bootstrap), lang = "legacy_receiver")]
|
#[cfg_attr(not(bootstrap), lang = "legacy_receiver")]
|
||||||
#[unstable(feature = "legacy_receiver_trait", issue = "none")]
|
#[unstable(feature = "legacy_receiver_trait", issue = "none")]
|
||||||
|
@ -170,6 +170,9 @@ pub use self::coroutine::{Coroutine, CoroutineState};
|
|||||||
pub use self::deref::DerefPure;
|
pub use self::deref::DerefPure;
|
||||||
#[unstable(feature = "legacy_receiver_trait", issue = "none")]
|
#[unstable(feature = "legacy_receiver_trait", issue = "none")]
|
||||||
pub use self::deref::LegacyReceiver;
|
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")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub use self::deref::{Deref, DerefMut};
|
pub use self::deref::{Deref, DerefMut};
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
|
@ -757,6 +757,47 @@ where
|
|||||||
self.base.get_or_insert_with(value, f)
|
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`.
|
/// Returns `true` if `self` has no elements in common with `other`.
|
||||||
/// This is equivalent to checking for an empty intersection.
|
/// 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")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
impl<T, S> Clone for HashSet<T, S>
|
impl<T, S> Clone for HashSet<T, S>
|
||||||
where
|
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)]
|
#[allow(dead_code)]
|
||||||
fn assert_covariance() {
|
fn assert_covariance() {
|
||||||
fn set<'new>(v: HashSet<&'static str>) -> HashSet<&'new str> {
|
fn set<'new>(v: HashSet<&'static str>) -> HashSet<&'new str> {
|
||||||
|
@ -15,7 +15,7 @@ pub fn access_bad_option(sess: Session) {
|
|||||||
//~^ ERROR use `Session::split_debuginfo` instead of this field
|
//~^ ERROR use `Session::split_debuginfo` instead of this field
|
||||||
|
|
||||||
let _ = sess.opts.crate_types;
|
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;
|
let _ = sess.opts.crate_name;
|
||||||
// okay!
|
// okay!
|
||||||
|
@ -10,7 +10,7 @@ note: the lint level is defined here
|
|||||||
LL | #![deny(rustc::bad_opt_access)]
|
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
|
--> $DIR/bad_opt_access.rs:17:13
|
||||||
|
|
|
|
||||||
LL | let _ = sess.opts.crate_types;
|
LL | let _ = sess.opts.crate_types;
|
||||||
|
@ -212,6 +212,10 @@ trigger_files = [
|
|||||||
"src/tools/rustdoc-gui",
|
"src/tools/rustdoc-gui",
|
||||||
"src/tools/rustdoc-js",
|
"src/tools/rustdoc-js",
|
||||||
"src/tools/rustdoc-themes",
|
"src/tools/rustdoc-themes",
|
||||||
|
|
||||||
|
# Docs
|
||||||
|
"src/doc/rustdoc.md",
|
||||||
|
"src/doc/rustdoc/",
|
||||||
]
|
]
|
||||||
exclude_labels = [
|
exclude_labels = [
|
||||||
"T-*",
|
"T-*",
|
||||||
@ -971,7 +975,6 @@ cc = ["@kobzol"]
|
|||||||
warn_non_default_branch = true
|
warn_non_default_branch = true
|
||||||
contributing_url = "https://rustc-dev-guide.rust-lang.org/getting-started.html"
|
contributing_url = "https://rustc-dev-guide.rust-lang.org/getting-started.html"
|
||||||
users_on_vacation = [
|
users_on_vacation = [
|
||||||
"fmease",
|
|
||||||
"jieyouxu",
|
"jieyouxu",
|
||||||
"jyn514",
|
"jyn514",
|
||||||
"oli-obk",
|
"oli-obk",
|
||||||
|
Loading…
Reference in New Issue
Block a user