Auto merge of #120335 - matthiaskrgr:rollup-2a0y3rd, r=matthiaskrgr
Rollup of 10 pull requests Successful merges: - #119305 (Add `AsyncFn` family of traits) - #119389 (Provide more context on recursive `impl` evaluation overflow) - #119895 (Remove `track_errors` entirely) - #120230 (Assert that a single scope is passed to `for_scope`) - #120278 (Remove --fatal-warnings on wasm targets) - #120292 (coverage: Dismantle `Instrumentor` and flatten span refinement) - #120315 (On E0308 involving `dyn Trait`, mention trait objects) - #120317 (pattern_analysis: Let `ctor_sub_tys` return any Iterator they want) - #120318 (pattern_analysis: Reuse most of the `DeconstructedPat` `Debug` impl) - #120325 (rustc_data_structures: use either instead of itertools) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
5bd5d214ef
70 changed files with 1596 additions and 609 deletions
|
@ -3654,10 +3654,10 @@ version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrayvec",
|
"arrayvec",
|
||||||
"bitflags 2.4.1",
|
"bitflags 2.4.1",
|
||||||
|
"either",
|
||||||
"elsa",
|
"elsa",
|
||||||
"ena",
|
"ena",
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"itertools",
|
|
||||||
"jobserver",
|
"jobserver",
|
||||||
"libc",
|
"libc",
|
||||||
"measureme",
|
"measureme",
|
||||||
|
|
|
@ -7,10 +7,10 @@ edition = "2021"
|
||||||
# tidy-alphabetical-start
|
# tidy-alphabetical-start
|
||||||
arrayvec = { version = "0.7", default-features = false }
|
arrayvec = { version = "0.7", default-features = false }
|
||||||
bitflags = "2.4.1"
|
bitflags = "2.4.1"
|
||||||
|
either = "1.0"
|
||||||
elsa = "=1.7.1"
|
elsa = "=1.7.1"
|
||||||
ena = "0.14.2"
|
ena = "0.14.2"
|
||||||
indexmap = { version = "2.0.0" }
|
indexmap = { version = "2.0.0" }
|
||||||
itertools = "0.11"
|
|
||||||
jobserver_crate = { version = "0.1.27", package = "jobserver" }
|
jobserver_crate = { version = "0.1.27", package = "jobserver" }
|
||||||
libc = "0.2"
|
libc = "0.2"
|
||||||
measureme = "11"
|
measureme = "11"
|
||||||
|
|
|
@ -3,7 +3,7 @@ use crate::fx::{FxHashMap, FxHasher};
|
||||||
use crate::sync::{is_dyn_thread_safe, CacheAligned};
|
use crate::sync::{is_dyn_thread_safe, CacheAligned};
|
||||||
use crate::sync::{Lock, LockGuard, Mode};
|
use crate::sync::{Lock, LockGuard, Mode};
|
||||||
#[cfg(parallel_compiler)]
|
#[cfg(parallel_compiler)]
|
||||||
use itertools::Either;
|
use either::Either;
|
||||||
use std::borrow::Borrow;
|
use std::borrow::Borrow;
|
||||||
use std::collections::hash_map::RawEntryMut;
|
use std::collections::hash_map::RawEntryMut;
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::fx::FxHashMap;
|
use crate::fx::FxHashMap;
|
||||||
use arrayvec::ArrayVec;
|
use arrayvec::ArrayVec;
|
||||||
use itertools::Either;
|
use either::Either;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
use std::ops::Index;
|
use std::ops::Index;
|
||||||
|
|
|
@ -208,6 +208,10 @@ language_item_table! {
|
||||||
FnMut, sym::fn_mut, fn_mut_trait, Target::Trait, GenericRequirement::Exact(1);
|
FnMut, sym::fn_mut, fn_mut_trait, Target::Trait, GenericRequirement::Exact(1);
|
||||||
FnOnce, sym::fn_once, fn_once_trait, Target::Trait, GenericRequirement::Exact(1);
|
FnOnce, sym::fn_once, fn_once_trait, Target::Trait, GenericRequirement::Exact(1);
|
||||||
|
|
||||||
|
AsyncFn, sym::async_fn, async_fn_trait, Target::Trait, GenericRequirement::Exact(1);
|
||||||
|
AsyncFnMut, sym::async_fn_mut, async_fn_mut_trait, Target::Trait, GenericRequirement::Exact(1);
|
||||||
|
AsyncFnOnce, sym::async_fn_once, async_fn_once_trait, Target::Trait, GenericRequirement::Exact(1);
|
||||||
|
|
||||||
FnOnceOutput, sym::fn_once_output, fn_once_output, Target::AssocTy, GenericRequirement::None;
|
FnOnceOutput, sym::fn_once_output, fn_once_output, Target::AssocTy, GenericRequirement::None;
|
||||||
|
|
||||||
Iterator, sym::iterator, iterator_trait, Target::Trait, GenericRequirement::Exact(0);
|
Iterator, sym::iterator, iterator_trait, Target::Trait, GenericRequirement::Exact(0);
|
||||||
|
|
|
@ -25,14 +25,21 @@ use rustc_trait_selection::traits::ObligationCtxt;
|
||||||
use rustc_trait_selection::traits::{self, ObligationCause};
|
use rustc_trait_selection::traits::{self, ObligationCause};
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
pub fn check_trait(tcx: TyCtxt<'_>, trait_def_id: DefId) {
|
pub fn check_trait(tcx: TyCtxt<'_>, trait_def_id: DefId) -> Result<(), ErrorGuaranteed> {
|
||||||
let lang_items = tcx.lang_items();
|
let lang_items = tcx.lang_items();
|
||||||
Checker { tcx, trait_def_id }
|
let checker = Checker { tcx, trait_def_id };
|
||||||
.check(lang_items.drop_trait(), visit_implementation_of_drop)
|
let mut res = checker.check(lang_items.drop_trait(), visit_implementation_of_drop);
|
||||||
.check(lang_items.copy_trait(), visit_implementation_of_copy)
|
res = res.and(checker.check(lang_items.copy_trait(), visit_implementation_of_copy));
|
||||||
.check(lang_items.const_param_ty_trait(), visit_implementation_of_const_param_ty)
|
res = res.and(
|
||||||
.check(lang_items.coerce_unsized_trait(), visit_implementation_of_coerce_unsized)
|
checker.check(lang_items.const_param_ty_trait(), visit_implementation_of_const_param_ty),
|
||||||
.check(lang_items.dispatch_from_dyn_trait(), visit_implementation_of_dispatch_from_dyn);
|
);
|
||||||
|
res = res.and(
|
||||||
|
checker.check(lang_items.coerce_unsized_trait(), visit_implementation_of_coerce_unsized),
|
||||||
|
);
|
||||||
|
res.and(
|
||||||
|
checker
|
||||||
|
.check(lang_items.dispatch_from_dyn_trait(), visit_implementation_of_dispatch_from_dyn),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Checker<'tcx> {
|
struct Checker<'tcx> {
|
||||||
|
@ -41,33 +48,40 @@ struct Checker<'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> Checker<'tcx> {
|
impl<'tcx> Checker<'tcx> {
|
||||||
fn check<F>(&self, trait_def_id: Option<DefId>, mut f: F) -> &Self
|
fn check<F>(&self, trait_def_id: Option<DefId>, mut f: F) -> Result<(), ErrorGuaranteed>
|
||||||
where
|
where
|
||||||
F: FnMut(TyCtxt<'tcx>, LocalDefId),
|
F: FnMut(TyCtxt<'tcx>, LocalDefId) -> Result<(), ErrorGuaranteed>,
|
||||||
{
|
{
|
||||||
|
let mut res = Ok(());
|
||||||
if Some(self.trait_def_id) == trait_def_id {
|
if Some(self.trait_def_id) == trait_def_id {
|
||||||
for &impl_def_id in self.tcx.hir().trait_impls(self.trait_def_id) {
|
for &impl_def_id in self.tcx.hir().trait_impls(self.trait_def_id) {
|
||||||
f(self.tcx, impl_def_id);
|
res = res.and(f(self.tcx, impl_def_id));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self
|
res
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_implementation_of_drop(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
|
fn visit_implementation_of_drop(
|
||||||
|
tcx: TyCtxt<'_>,
|
||||||
|
impl_did: LocalDefId,
|
||||||
|
) -> Result<(), ErrorGuaranteed> {
|
||||||
// Destructors only work on local ADT types.
|
// Destructors only work on local ADT types.
|
||||||
match tcx.type_of(impl_did).instantiate_identity().kind() {
|
match tcx.type_of(impl_did).instantiate_identity().kind() {
|
||||||
ty::Adt(def, _) if def.did().is_local() => return,
|
ty::Adt(def, _) if def.did().is_local() => return Ok(()),
|
||||||
ty::Error(_) => return,
|
ty::Error(_) => return Ok(()),
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
let impl_ = tcx.hir().expect_item(impl_did).expect_impl();
|
let impl_ = tcx.hir().expect_item(impl_did).expect_impl();
|
||||||
|
|
||||||
tcx.dcx().emit_err(errors::DropImplOnWrongItem { span: impl_.self_ty.span });
|
Err(tcx.dcx().emit_err(errors::DropImplOnWrongItem { span: impl_.self_ty.span }))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
|
fn visit_implementation_of_copy(
|
||||||
|
tcx: TyCtxt<'_>,
|
||||||
|
impl_did: LocalDefId,
|
||||||
|
) -> Result<(), ErrorGuaranteed> {
|
||||||
debug!("visit_implementation_of_copy: impl_did={:?}", impl_did);
|
debug!("visit_implementation_of_copy: impl_did={:?}", impl_did);
|
||||||
|
|
||||||
let self_type = tcx.type_of(impl_did).instantiate_identity();
|
let self_type = tcx.type_of(impl_did).instantiate_identity();
|
||||||
|
@ -79,59 +93,68 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
|
||||||
debug!("visit_implementation_of_copy: self_type={:?} (free)", self_type);
|
debug!("visit_implementation_of_copy: self_type={:?} (free)", self_type);
|
||||||
|
|
||||||
let span = match tcx.hir().expect_item(impl_did).expect_impl() {
|
let span = match tcx.hir().expect_item(impl_did).expect_impl() {
|
||||||
hir::Impl { polarity: hir::ImplPolarity::Negative(_), .. } => return,
|
hir::Impl { polarity: hir::ImplPolarity::Negative(_), .. } => return Ok(()),
|
||||||
hir::Impl { self_ty, .. } => self_ty.span,
|
hir::Impl { self_ty, .. } => self_ty.span,
|
||||||
};
|
};
|
||||||
|
|
||||||
let cause = traits::ObligationCause::misc(span, impl_did);
|
let cause = traits::ObligationCause::misc(span, impl_did);
|
||||||
match type_allowed_to_implement_copy(tcx, param_env, self_type, cause) {
|
match type_allowed_to_implement_copy(tcx, param_env, self_type, cause) {
|
||||||
Ok(()) => {}
|
Ok(()) => Ok(()),
|
||||||
Err(CopyImplementationError::InfringingFields(fields)) => {
|
Err(CopyImplementationError::InfringingFields(fields)) => {
|
||||||
infringing_fields_error(tcx, fields, LangItem::Copy, impl_did, span);
|
Err(infringing_fields_error(tcx, fields, LangItem::Copy, impl_did, span))
|
||||||
}
|
}
|
||||||
Err(CopyImplementationError::NotAnAdt) => {
|
Err(CopyImplementationError::NotAnAdt) => {
|
||||||
tcx.dcx().emit_err(errors::CopyImplOnNonAdt { span });
|
Err(tcx.dcx().emit_err(errors::CopyImplOnNonAdt { span }))
|
||||||
}
|
}
|
||||||
Err(CopyImplementationError::HasDestructor) => {
|
Err(CopyImplementationError::HasDestructor) => {
|
||||||
tcx.dcx().emit_err(errors::CopyImplOnTypeWithDtor { span });
|
Err(tcx.dcx().emit_err(errors::CopyImplOnTypeWithDtor { span }))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_implementation_of_const_param_ty(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
|
fn visit_implementation_of_const_param_ty(
|
||||||
|
tcx: TyCtxt<'_>,
|
||||||
|
impl_did: LocalDefId,
|
||||||
|
) -> Result<(), ErrorGuaranteed> {
|
||||||
let self_type = tcx.type_of(impl_did).instantiate_identity();
|
let self_type = tcx.type_of(impl_did).instantiate_identity();
|
||||||
assert!(!self_type.has_escaping_bound_vars());
|
assert!(!self_type.has_escaping_bound_vars());
|
||||||
|
|
||||||
let param_env = tcx.param_env(impl_did);
|
let param_env = tcx.param_env(impl_did);
|
||||||
|
|
||||||
let span = match tcx.hir().expect_item(impl_did).expect_impl() {
|
let span = match tcx.hir().expect_item(impl_did).expect_impl() {
|
||||||
hir::Impl { polarity: hir::ImplPolarity::Negative(_), .. } => return,
|
hir::Impl { polarity: hir::ImplPolarity::Negative(_), .. } => return Ok(()),
|
||||||
impl_ => impl_.self_ty.span,
|
impl_ => impl_.self_ty.span,
|
||||||
};
|
};
|
||||||
|
|
||||||
let cause = traits::ObligationCause::misc(span, impl_did);
|
let cause = traits::ObligationCause::misc(span, impl_did);
|
||||||
match type_allowed_to_implement_const_param_ty(tcx, param_env, self_type, cause) {
|
match type_allowed_to_implement_const_param_ty(tcx, param_env, self_type, cause) {
|
||||||
Ok(()) => {}
|
Ok(()) => Ok(()),
|
||||||
Err(ConstParamTyImplementationError::InfrigingFields(fields)) => {
|
Err(ConstParamTyImplementationError::InfrigingFields(fields)) => {
|
||||||
infringing_fields_error(tcx, fields, LangItem::ConstParamTy, impl_did, span);
|
Err(infringing_fields_error(tcx, fields, LangItem::ConstParamTy, impl_did, span))
|
||||||
}
|
}
|
||||||
Err(ConstParamTyImplementationError::NotAnAdtOrBuiltinAllowed) => {
|
Err(ConstParamTyImplementationError::NotAnAdtOrBuiltinAllowed) => {
|
||||||
tcx.dcx().emit_err(errors::ConstParamTyImplOnNonAdt { span });
|
Err(tcx.dcx().emit_err(errors::ConstParamTyImplOnNonAdt { span }))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_implementation_of_coerce_unsized(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
|
fn visit_implementation_of_coerce_unsized(
|
||||||
|
tcx: TyCtxt<'_>,
|
||||||
|
impl_did: LocalDefId,
|
||||||
|
) -> Result<(), ErrorGuaranteed> {
|
||||||
debug!("visit_implementation_of_coerce_unsized: impl_did={:?}", impl_did);
|
debug!("visit_implementation_of_coerce_unsized: impl_did={:?}", impl_did);
|
||||||
|
|
||||||
// Just compute this for the side-effects, in particular reporting
|
// Just compute this for the side-effects, in particular reporting
|
||||||
// errors; other parts of the code may demand it for the info of
|
// errors; other parts of the code may demand it for the info of
|
||||||
// course.
|
// course.
|
||||||
let span = tcx.def_span(impl_did);
|
let span = tcx.def_span(impl_did);
|
||||||
tcx.at(span).coerce_unsized_info(impl_did);
|
tcx.at(span).ensure().coerce_unsized_info(impl_did)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
|
fn visit_implementation_of_dispatch_from_dyn(
|
||||||
|
tcx: TyCtxt<'_>,
|
||||||
|
impl_did: LocalDefId,
|
||||||
|
) -> Result<(), ErrorGuaranteed> {
|
||||||
debug!("visit_implementation_of_dispatch_from_dyn: impl_did={:?}", impl_did);
|
debug!("visit_implementation_of_dispatch_from_dyn: impl_did={:?}", impl_did);
|
||||||
|
|
||||||
let span = tcx.def_span(impl_did);
|
let span = tcx.def_span(impl_did);
|
||||||
|
@ -166,26 +189,28 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef
|
||||||
match (source.kind(), target.kind()) {
|
match (source.kind(), target.kind()) {
|
||||||
(&Ref(r_a, _, mutbl_a), Ref(r_b, _, mutbl_b))
|
(&Ref(r_a, _, mutbl_a), Ref(r_b, _, mutbl_b))
|
||||||
if infcx.at(&cause, param_env).eq(DefineOpaqueTypes::No, r_a, *r_b).is_ok()
|
if infcx.at(&cause, param_env).eq(DefineOpaqueTypes::No, r_a, *r_b).is_ok()
|
||||||
&& mutbl_a == *mutbl_b => {}
|
&& mutbl_a == *mutbl_b =>
|
||||||
(&RawPtr(tm_a), &RawPtr(tm_b)) if tm_a.mutbl == tm_b.mutbl => (),
|
{
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
(&RawPtr(tm_a), &RawPtr(tm_b)) if tm_a.mutbl == tm_b.mutbl => Ok(()),
|
||||||
(&Adt(def_a, args_a), &Adt(def_b, args_b)) if def_a.is_struct() && def_b.is_struct() => {
|
(&Adt(def_a, args_a), &Adt(def_b, args_b)) if def_a.is_struct() && def_b.is_struct() => {
|
||||||
if def_a != def_b {
|
if def_a != def_b {
|
||||||
let source_path = tcx.def_path_str(def_a.did());
|
let source_path = tcx.def_path_str(def_a.did());
|
||||||
let target_path = tcx.def_path_str(def_b.did());
|
let target_path = tcx.def_path_str(def_b.did());
|
||||||
|
|
||||||
tcx.dcx().emit_err(errors::DispatchFromDynCoercion {
|
return Err(tcx.dcx().emit_err(errors::DispatchFromDynCoercion {
|
||||||
span,
|
span,
|
||||||
trait_name: "DispatchFromDyn",
|
trait_name: "DispatchFromDyn",
|
||||||
note: true,
|
note: true,
|
||||||
source_path,
|
source_path,
|
||||||
target_path,
|
target_path,
|
||||||
});
|
}));
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut res = Ok(());
|
||||||
if def_a.repr().c() || def_a.repr().packed() {
|
if def_a.repr().c() || def_a.repr().packed() {
|
||||||
tcx.dcx().emit_err(errors::DispatchFromDynRepr { span });
|
res = Err(tcx.dcx().emit_err(errors::DispatchFromDynRepr { span }));
|
||||||
}
|
}
|
||||||
|
|
||||||
let fields = &def_a.non_enum_variant().fields;
|
let fields = &def_a.non_enum_variant().fields;
|
||||||
|
@ -207,11 +232,11 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef
|
||||||
infcx.at(&cause, param_env).eq(DefineOpaqueTypes::No, ty_a, ty_b)
|
infcx.at(&cause, param_env).eq(DefineOpaqueTypes::No, ty_a, ty_b)
|
||||||
{
|
{
|
||||||
if ok.obligations.is_empty() {
|
if ok.obligations.is_empty() {
|
||||||
tcx.dcx().emit_err(errors::DispatchFromDynZST {
|
res = Err(tcx.dcx().emit_err(errors::DispatchFromDynZST {
|
||||||
span,
|
span,
|
||||||
name: field.name,
|
name: field.name,
|
||||||
ty: ty_a,
|
ty: ty_a,
|
||||||
});
|
}));
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -222,13 +247,13 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
if coerced_fields.is_empty() {
|
if coerced_fields.is_empty() {
|
||||||
tcx.dcx().emit_err(errors::DispatchFromDynSingle {
|
res = Err(tcx.dcx().emit_err(errors::DispatchFromDynSingle {
|
||||||
span,
|
span,
|
||||||
trait_name: "DispatchFromDyn",
|
trait_name: "DispatchFromDyn",
|
||||||
note: true,
|
note: true,
|
||||||
});
|
}));
|
||||||
} else if coerced_fields.len() > 1 {
|
} else if coerced_fields.len() > 1 {
|
||||||
tcx.dcx().emit_err(errors::DispatchFromDynMulti {
|
res = Err(tcx.dcx().emit_err(errors::DispatchFromDynMulti {
|
||||||
span,
|
span,
|
||||||
coercions_note: true,
|
coercions_note: true,
|
||||||
number: coerced_fields.len(),
|
number: coerced_fields.len(),
|
||||||
|
@ -244,7 +269,7 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.join(", "),
|
.join(", "),
|
||||||
});
|
}));
|
||||||
} else {
|
} else {
|
||||||
let ocx = ObligationCtxt::new(&infcx);
|
let ocx = ObligationCtxt::new(&infcx);
|
||||||
for field in coerced_fields {
|
for field in coerced_fields {
|
||||||
|
@ -261,21 +286,25 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef
|
||||||
}
|
}
|
||||||
let errors = ocx.select_all_or_error();
|
let errors = ocx.select_all_or_error();
|
||||||
if !errors.is_empty() {
|
if !errors.is_empty() {
|
||||||
infcx.err_ctxt().report_fulfillment_errors(errors);
|
res = Err(infcx.err_ctxt().report_fulfillment_errors(errors));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finally, resolve all regions.
|
// Finally, resolve all regions.
|
||||||
let outlives_env = OutlivesEnvironment::new(param_env);
|
let outlives_env = OutlivesEnvironment::new(param_env);
|
||||||
let _ = ocx.resolve_regions_and_report_errors(impl_did, &outlives_env);
|
res = res.and(ocx.resolve_regions_and_report_errors(impl_did, &outlives_env));
|
||||||
}
|
}
|
||||||
|
res
|
||||||
}
|
}
|
||||||
_ => {
|
_ => Err(tcx
|
||||||
tcx.dcx().emit_err(errors::CoerceUnsizedMay { span, trait_name: "DispatchFromDyn" });
|
.dcx()
|
||||||
}
|
.emit_err(errors::CoerceUnsizedMay { span, trait_name: "DispatchFromDyn" })),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) -> CoerceUnsizedInfo {
|
pub fn coerce_unsized_info<'tcx>(
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
impl_did: LocalDefId,
|
||||||
|
) -> Result<CoerceUnsizedInfo, ErrorGuaranteed> {
|
||||||
debug!("compute_coerce_unsized_info(impl_did={:?})", impl_did);
|
debug!("compute_coerce_unsized_info(impl_did={:?})", impl_did);
|
||||||
let span = tcx.def_span(impl_did);
|
let span = tcx.def_span(impl_did);
|
||||||
|
|
||||||
|
@ -292,8 +321,6 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) -> Coe
|
||||||
let param_env = tcx.param_env(impl_did);
|
let param_env = tcx.param_env(impl_did);
|
||||||
assert!(!source.has_escaping_bound_vars());
|
assert!(!source.has_escaping_bound_vars());
|
||||||
|
|
||||||
let err_info = CoerceUnsizedInfo { custom_kind: None };
|
|
||||||
|
|
||||||
debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (free)", source, target);
|
debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (free)", source, target);
|
||||||
|
|
||||||
let infcx = tcx.infer_ctxt().build();
|
let infcx = tcx.infer_ctxt().build();
|
||||||
|
@ -337,14 +364,13 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) -> Coe
|
||||||
if def_a != def_b {
|
if def_a != def_b {
|
||||||
let source_path = tcx.def_path_str(def_a.did());
|
let source_path = tcx.def_path_str(def_a.did());
|
||||||
let target_path = tcx.def_path_str(def_b.did());
|
let target_path = tcx.def_path_str(def_b.did());
|
||||||
tcx.dcx().emit_err(errors::DispatchFromDynSame {
|
return Err(tcx.dcx().emit_err(errors::DispatchFromDynSame {
|
||||||
span,
|
span,
|
||||||
trait_name: "CoerceUnsized",
|
trait_name: "CoerceUnsized",
|
||||||
note: true,
|
note: true,
|
||||||
source_path,
|
source_path,
|
||||||
target_path,
|
target_path,
|
||||||
});
|
}));
|
||||||
return err_info;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Here we are considering a case of converting
|
// Here we are considering a case of converting
|
||||||
|
@ -419,12 +445,11 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) -> Coe
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
if diff_fields.is_empty() {
|
if diff_fields.is_empty() {
|
||||||
tcx.dcx().emit_err(errors::CoerceUnsizedOneField {
|
return Err(tcx.dcx().emit_err(errors::CoerceUnsizedOneField {
|
||||||
span,
|
span,
|
||||||
trait_name: "CoerceUnsized",
|
trait_name: "CoerceUnsized",
|
||||||
note: true,
|
note: true,
|
||||||
});
|
}));
|
||||||
return err_info;
|
|
||||||
} else if diff_fields.len() > 1 {
|
} else if diff_fields.len() > 1 {
|
||||||
let item = tcx.hir().expect_item(impl_did);
|
let item = tcx.hir().expect_item(impl_did);
|
||||||
let span = if let ItemKind::Impl(hir::Impl { of_trait: Some(t), .. }) = &item.kind {
|
let span = if let ItemKind::Impl(hir::Impl { of_trait: Some(t), .. }) = &item.kind {
|
||||||
|
@ -433,7 +458,7 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) -> Coe
|
||||||
tcx.def_span(impl_did)
|
tcx.def_span(impl_did)
|
||||||
};
|
};
|
||||||
|
|
||||||
tcx.dcx().emit_err(errors::CoerceUnsizedMulti {
|
return Err(tcx.dcx().emit_err(errors::CoerceUnsizedMulti {
|
||||||
span,
|
span,
|
||||||
coercions_note: true,
|
coercions_note: true,
|
||||||
number: diff_fields.len(),
|
number: diff_fields.len(),
|
||||||
|
@ -442,9 +467,7 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) -> Coe
|
||||||
.map(|&(i, a, b)| format!("`{}` (`{}` to `{}`)", fields[i].name, a, b))
|
.map(|&(i, a, b)| format!("`{}` (`{}` to `{}`)", fields[i].name, a, b))
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.join(", "),
|
.join(", "),
|
||||||
});
|
}));
|
||||||
|
|
||||||
return err_info;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let (i, a, b) = diff_fields[0];
|
let (i, a, b) = diff_fields[0];
|
||||||
|
@ -453,8 +476,9 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) -> Coe
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
tcx.dcx().emit_err(errors::DispatchFromDynStruct { span, trait_name: "CoerceUnsized" });
|
return Err(tcx
|
||||||
return err_info;
|
.dcx()
|
||||||
|
.emit_err(errors::DispatchFromDynStruct { span, trait_name: "CoerceUnsized" }));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -477,7 +501,7 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) -> Coe
|
||||||
let outlives_env = OutlivesEnvironment::new(param_env);
|
let outlives_env = OutlivesEnvironment::new(param_env);
|
||||||
let _ = ocx.resolve_regions_and_report_errors(impl_did, &outlives_env);
|
let _ = ocx.resolve_regions_and_report_errors(impl_did, &outlives_env);
|
||||||
|
|
||||||
CoerceUnsizedInfo { custom_kind: kind }
|
Ok(CoerceUnsizedInfo { custom_kind: kind })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn infringing_fields_error(
|
fn infringing_fields_error(
|
||||||
|
|
|
@ -10,6 +10,7 @@ use rustc_errors::{error_code, struct_span_code_err};
|
||||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||||
use rustc_middle::query::Providers;
|
use rustc_middle::query::Providers;
|
||||||
use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt};
|
use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt};
|
||||||
|
use rustc_span::ErrorGuaranteed;
|
||||||
use rustc_trait_selection::traits;
|
use rustc_trait_selection::traits;
|
||||||
|
|
||||||
mod builtin;
|
mod builtin;
|
||||||
|
@ -18,7 +19,11 @@ mod inherent_impls_overlap;
|
||||||
mod orphan;
|
mod orphan;
|
||||||
mod unsafety;
|
mod unsafety;
|
||||||
|
|
||||||
fn check_impl(tcx: TyCtxt<'_>, impl_def_id: LocalDefId, trait_ref: ty::TraitRef<'_>) {
|
fn check_impl(
|
||||||
|
tcx: TyCtxt<'_>,
|
||||||
|
impl_def_id: LocalDefId,
|
||||||
|
trait_ref: ty::TraitRef<'_>,
|
||||||
|
) -> Result<(), ErrorGuaranteed> {
|
||||||
debug!(
|
debug!(
|
||||||
"(checking implementation) adding impl for trait '{:?}', item '{}'",
|
"(checking implementation) adding impl for trait '{:?}', item '{}'",
|
||||||
trait_ref,
|
trait_ref,
|
||||||
|
@ -28,18 +33,18 @@ fn check_impl(tcx: TyCtxt<'_>, impl_def_id: LocalDefId, trait_ref: ty::TraitRef<
|
||||||
// Skip impls where one of the self type is an error type.
|
// Skip impls where one of the self type is an error type.
|
||||||
// This occurs with e.g., resolve failures (#30589).
|
// This occurs with e.g., resolve failures (#30589).
|
||||||
if trait_ref.references_error() {
|
if trait_ref.references_error() {
|
||||||
return;
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
enforce_trait_manually_implementable(tcx, impl_def_id, trait_ref.def_id);
|
enforce_trait_manually_implementable(tcx, impl_def_id, trait_ref.def_id)
|
||||||
enforce_empty_impls_for_marker_traits(tcx, impl_def_id, trait_ref.def_id);
|
.and(enforce_empty_impls_for_marker_traits(tcx, impl_def_id, trait_ref.def_id))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn enforce_trait_manually_implementable(
|
fn enforce_trait_manually_implementable(
|
||||||
tcx: TyCtxt<'_>,
|
tcx: TyCtxt<'_>,
|
||||||
impl_def_id: LocalDefId,
|
impl_def_id: LocalDefId,
|
||||||
trait_def_id: DefId,
|
trait_def_id: DefId,
|
||||||
) {
|
) -> Result<(), ErrorGuaranteed> {
|
||||||
let impl_header_span = tcx.def_span(impl_def_id);
|
let impl_header_span = tcx.def_span(impl_def_id);
|
||||||
|
|
||||||
// Disallow *all* explicit impls of traits marked `#[rustc_deny_explicit_impl]`
|
// Disallow *all* explicit impls of traits marked `#[rustc_deny_explicit_impl]`
|
||||||
|
@ -59,18 +64,17 @@ fn enforce_trait_manually_implementable(
|
||||||
err.code(error_code!(E0328));
|
err.code(error_code!(E0328));
|
||||||
}
|
}
|
||||||
|
|
||||||
err.emit();
|
return Err(err.emit());
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if let ty::trait_def::TraitSpecializationKind::AlwaysApplicable =
|
if let ty::trait_def::TraitSpecializationKind::AlwaysApplicable =
|
||||||
tcx.trait_def(trait_def_id).specialization_kind
|
tcx.trait_def(trait_def_id).specialization_kind
|
||||||
{
|
{
|
||||||
if !tcx.features().specialization && !tcx.features().min_specialization {
|
if !tcx.features().specialization && !tcx.features().min_specialization {
|
||||||
tcx.dcx().emit_err(errors::SpecializationTrait { span: impl_header_span });
|
return Err(tcx.dcx().emit_err(errors::SpecializationTrait { span: impl_header_span }));
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// We allow impls of marker traits to overlap, so they can't override impls
|
/// We allow impls of marker traits to overlap, so they can't override impls
|
||||||
|
@ -79,22 +83,22 @@ fn enforce_empty_impls_for_marker_traits(
|
||||||
tcx: TyCtxt<'_>,
|
tcx: TyCtxt<'_>,
|
||||||
impl_def_id: LocalDefId,
|
impl_def_id: LocalDefId,
|
||||||
trait_def_id: DefId,
|
trait_def_id: DefId,
|
||||||
) {
|
) -> Result<(), ErrorGuaranteed> {
|
||||||
if !tcx.trait_def(trait_def_id).is_marker {
|
if !tcx.trait_def(trait_def_id).is_marker {
|
||||||
return;
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
if tcx.associated_item_def_ids(trait_def_id).is_empty() {
|
if tcx.associated_item_def_ids(trait_def_id).is_empty() {
|
||||||
return;
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
struct_span_code_err!(
|
Err(struct_span_code_err!(
|
||||||
tcx.dcx(),
|
tcx.dcx(),
|
||||||
tcx.def_span(impl_def_id),
|
tcx.def_span(impl_def_id),
|
||||||
E0715,
|
E0715,
|
||||||
"impls for marker traits cannot contain items"
|
"impls for marker traits cannot contain items"
|
||||||
)
|
)
|
||||||
.emit();
|
.emit())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn provide(providers: &mut Providers) {
|
pub fn provide(providers: &mut Providers) {
|
||||||
|
@ -115,23 +119,23 @@ pub fn provide(providers: &mut Providers) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn coherent_trait(tcx: TyCtxt<'_>, def_id: DefId) {
|
fn coherent_trait(tcx: TyCtxt<'_>, def_id: DefId) -> Result<(), ErrorGuaranteed> {
|
||||||
// Trigger building the specialization graph for the trait. This will detect and report any
|
// Trigger building the specialization graph for the trait. This will detect and report any
|
||||||
// overlap errors.
|
// overlap errors.
|
||||||
tcx.ensure().specialization_graph_of(def_id);
|
let mut res = tcx.ensure().specialization_graph_of(def_id);
|
||||||
|
|
||||||
let impls = tcx.hir().trait_impls(def_id);
|
let impls = tcx.hir().trait_impls(def_id);
|
||||||
for &impl_def_id in impls {
|
for &impl_def_id in impls {
|
||||||
let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().instantiate_identity();
|
let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().instantiate_identity();
|
||||||
|
|
||||||
check_impl(tcx, impl_def_id, trait_ref);
|
res = res.and(check_impl(tcx, impl_def_id, trait_ref));
|
||||||
check_object_overlap(tcx, impl_def_id, trait_ref);
|
res = res.and(check_object_overlap(tcx, impl_def_id, trait_ref));
|
||||||
|
|
||||||
unsafety::check_item(tcx, impl_def_id);
|
res = res.and(unsafety::check_item(tcx, impl_def_id));
|
||||||
tcx.ensure().orphan_check_impl(impl_def_id);
|
res = res.and(tcx.ensure().orphan_check_impl(impl_def_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
builtin::check_trait(tcx, def_id);
|
res.and(builtin::check_trait(tcx, def_id))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks whether an impl overlaps with the automatic `impl Trait for dyn Trait`.
|
/// Checks whether an impl overlaps with the automatic `impl Trait for dyn Trait`.
|
||||||
|
@ -139,12 +143,12 @@ fn check_object_overlap<'tcx>(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
impl_def_id: LocalDefId,
|
impl_def_id: LocalDefId,
|
||||||
trait_ref: ty::TraitRef<'tcx>,
|
trait_ref: ty::TraitRef<'tcx>,
|
||||||
) {
|
) -> Result<(), ErrorGuaranteed> {
|
||||||
let trait_def_id = trait_ref.def_id;
|
let trait_def_id = trait_ref.def_id;
|
||||||
|
|
||||||
if trait_ref.references_error() {
|
if trait_ref.references_error() {
|
||||||
debug!("coherence: skipping impl {:?} with error {:?}", impl_def_id, trait_ref);
|
debug!("coherence: skipping impl {:?} with error {:?}", impl_def_id, trait_ref);
|
||||||
return;
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
// check for overlap with the automatic `impl Trait for dyn Trait`
|
// check for overlap with the automatic `impl Trait for dyn Trait`
|
||||||
|
@ -173,7 +177,7 @@ fn check_object_overlap<'tcx>(
|
||||||
let mut supertrait_def_ids = traits::supertrait_def_ids(tcx, component_def_id);
|
let mut supertrait_def_ids = traits::supertrait_def_ids(tcx, component_def_id);
|
||||||
if supertrait_def_ids.any(|d| d == trait_def_id) {
|
if supertrait_def_ids.any(|d| d == trait_def_id) {
|
||||||
let span = tcx.def_span(impl_def_id);
|
let span = tcx.def_span(impl_def_id);
|
||||||
struct_span_code_err!(
|
return Err(struct_span_code_err!(
|
||||||
tcx.dcx(),
|
tcx.dcx(),
|
||||||
span,
|
span,
|
||||||
E0371,
|
E0371,
|
||||||
|
@ -189,9 +193,10 @@ fn check_object_overlap<'tcx>(
|
||||||
tcx.def_path_str(trait_def_id)
|
tcx.def_path_str(trait_def_id)
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.emit();
|
.emit());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,8 +6,9 @@ use rustc_hir as hir;
|
||||||
use rustc_hir::Unsafety;
|
use rustc_hir::Unsafety;
|
||||||
use rustc_middle::ty::TyCtxt;
|
use rustc_middle::ty::TyCtxt;
|
||||||
use rustc_span::def_id::LocalDefId;
|
use rustc_span::def_id::LocalDefId;
|
||||||
|
use rustc_span::ErrorGuaranteed;
|
||||||
|
|
||||||
pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), ErrorGuaranteed> {
|
||||||
let item = tcx.hir().expect_item(def_id);
|
let item = tcx.hir().expect_item(def_id);
|
||||||
let impl_ = item.expect_impl();
|
let impl_ = item.expect_impl();
|
||||||
|
|
||||||
|
@ -18,7 +19,7 @@ pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
||||||
impl_.generics.params.iter().find(|p| p.pure_wrt_drop).map(|_| "may_dangle");
|
impl_.generics.params.iter().find(|p| p.pure_wrt_drop).map(|_| "may_dangle");
|
||||||
match (trait_def.unsafety, unsafe_attr, impl_.unsafety, impl_.polarity) {
|
match (trait_def.unsafety, unsafe_attr, impl_.unsafety, impl_.polarity) {
|
||||||
(Unsafety::Normal, None, Unsafety::Unsafe, hir::ImplPolarity::Positive) => {
|
(Unsafety::Normal, None, Unsafety::Unsafe, hir::ImplPolarity::Positive) => {
|
||||||
struct_span_code_err!(
|
return Err(struct_span_code_err!(
|
||||||
tcx.dcx(),
|
tcx.dcx(),
|
||||||
tcx.def_span(def_id),
|
tcx.def_span(def_id),
|
||||||
E0199,
|
E0199,
|
||||||
|
@ -31,11 +32,11 @@ pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
||||||
"",
|
"",
|
||||||
rustc_errors::Applicability::MachineApplicable,
|
rustc_errors::Applicability::MachineApplicable,
|
||||||
)
|
)
|
||||||
.emit();
|
.emit());
|
||||||
}
|
}
|
||||||
|
|
||||||
(Unsafety::Unsafe, _, Unsafety::Normal, hir::ImplPolarity::Positive) => {
|
(Unsafety::Unsafe, _, Unsafety::Normal, hir::ImplPolarity::Positive) => {
|
||||||
struct_span_code_err!(
|
return Err(struct_span_code_err!(
|
||||||
tcx.dcx(),
|
tcx.dcx(),
|
||||||
tcx.def_span(def_id),
|
tcx.def_span(def_id),
|
||||||
E0200,
|
E0200,
|
||||||
|
@ -54,11 +55,11 @@ pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
||||||
"unsafe ",
|
"unsafe ",
|
||||||
rustc_errors::Applicability::MaybeIncorrect,
|
rustc_errors::Applicability::MaybeIncorrect,
|
||||||
)
|
)
|
||||||
.emit();
|
.emit());
|
||||||
}
|
}
|
||||||
|
|
||||||
(Unsafety::Normal, Some(attr_name), Unsafety::Normal, hir::ImplPolarity::Positive) => {
|
(Unsafety::Normal, Some(attr_name), Unsafety::Normal, hir::ImplPolarity::Positive) => {
|
||||||
struct_span_code_err!(
|
return Err(struct_span_code_err!(
|
||||||
tcx.dcx(),
|
tcx.dcx(),
|
||||||
tcx.def_span(def_id),
|
tcx.def_span(def_id),
|
||||||
E0569,
|
E0569,
|
||||||
|
@ -77,7 +78,7 @@ pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
||||||
"unsafe ",
|
"unsafe ",
|
||||||
rustc_errors::Applicability::MaybeIncorrect,
|
rustc_errors::Applicability::MaybeIncorrect,
|
||||||
)
|
)
|
||||||
.emit();
|
.emit());
|
||||||
}
|
}
|
||||||
|
|
||||||
(_, _, Unsafety::Unsafe, hir::ImplPolarity::Negative(_)) => {
|
(_, _, Unsafety::Unsafe, hir::ImplPolarity::Negative(_)) => {
|
||||||
|
@ -92,4 +93,5 @@ pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -172,18 +172,14 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> {
|
||||||
|
|
||||||
tcx.sess.time("coherence_checking", || {
|
tcx.sess.time("coherence_checking", || {
|
||||||
// Check impls constrain their parameters
|
// Check impls constrain their parameters
|
||||||
let res =
|
let mut res =
|
||||||
tcx.hir().try_par_for_each_module(|module| tcx.ensure().check_mod_impl_wf(module));
|
tcx.hir().try_par_for_each_module(|module| tcx.ensure().check_mod_impl_wf(module));
|
||||||
|
|
||||||
// FIXME(matthewjasper) We shouldn't need to use `track_errors` anywhere in this function
|
|
||||||
// or the compiler in general.
|
|
||||||
res.and(tcx.sess.track_errors(|| {
|
|
||||||
for &trait_def_id in tcx.all_local_trait_impls(()).keys() {
|
for &trait_def_id in tcx.all_local_trait_impls(()).keys() {
|
||||||
tcx.ensure().coherent_trait(trait_def_id);
|
res = res.and(tcx.ensure().coherent_trait(trait_def_id));
|
||||||
}
|
}
|
||||||
}))
|
|
||||||
// these queries are executed for side-effects (error reporting):
|
// these queries are executed for side-effects (error reporting):
|
||||||
.and(tcx.ensure().crate_inherent_impls(()))
|
res.and(tcx.ensure().crate_inherent_impls(()))
|
||||||
.and(tcx.ensure().crate_inherent_impls_overlap_check(()))
|
.and(tcx.ensure().crate_inherent_impls_overlap_check(()))
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
|
|
|
@ -220,6 +220,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
(self.tcx.lang_items().fn_trait(), Ident::with_dummy_span(sym::call), true),
|
(self.tcx.lang_items().fn_trait(), Ident::with_dummy_span(sym::call), true),
|
||||||
(self.tcx.lang_items().fn_mut_trait(), Ident::with_dummy_span(sym::call_mut), true),
|
(self.tcx.lang_items().fn_mut_trait(), Ident::with_dummy_span(sym::call_mut), true),
|
||||||
(self.tcx.lang_items().fn_once_trait(), Ident::with_dummy_span(sym::call_once), false),
|
(self.tcx.lang_items().fn_once_trait(), Ident::with_dummy_span(sym::call_once), false),
|
||||||
|
(self.tcx.lang_items().async_fn_trait(), Ident::with_dummy_span(sym::async_call), true),
|
||||||
|
(
|
||||||
|
self.tcx.lang_items().async_fn_mut_trait(),
|
||||||
|
Ident::with_dummy_span(sym::async_call_mut),
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
self.tcx.lang_items().async_fn_once_trait(),
|
||||||
|
Ident::with_dummy_span(sym::async_call_once),
|
||||||
|
false,
|
||||||
|
),
|
||||||
] {
|
] {
|
||||||
let Some(trait_def_id) = opt_trait_def_id else { continue };
|
let Some(trait_def_id) = opt_trait_def_id else { continue };
|
||||||
|
|
||||||
|
|
|
@ -294,6 +294,75 @@ impl<T> Trait<T> for X {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
(ty::Dynamic(t, _, ty::DynKind::Dyn), ty::Alias(ty::Opaque, alias))
|
||||||
|
if let Some(def_id) = t.principal_def_id()
|
||||||
|
&& tcx.explicit_item_bounds(alias.def_id).skip_binder().iter().any(
|
||||||
|
|(pred, _span)| match pred.kind().skip_binder() {
|
||||||
|
ty::ClauseKind::Trait(trait_predicate)
|
||||||
|
if trait_predicate.polarity
|
||||||
|
== ty::ImplPolarity::Positive =>
|
||||||
|
{
|
||||||
|
trait_predicate.def_id() == def_id
|
||||||
|
}
|
||||||
|
_ => false,
|
||||||
|
},
|
||||||
|
) =>
|
||||||
|
{
|
||||||
|
diag.help(format!(
|
||||||
|
"you can box the `{}` to coerce it to `Box<{}>`, but you'll have to \
|
||||||
|
change the expected type as well",
|
||||||
|
values.found, values.expected,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
(ty::Dynamic(t, _, ty::DynKind::Dyn), _)
|
||||||
|
if let Some(def_id) = t.principal_def_id() =>
|
||||||
|
{
|
||||||
|
let mut impl_def_ids = vec![];
|
||||||
|
tcx.for_each_relevant_impl(def_id, values.found, |did| {
|
||||||
|
impl_def_ids.push(did)
|
||||||
|
});
|
||||||
|
if let [_] = &impl_def_ids[..] {
|
||||||
|
let trait_name = tcx.item_name(def_id);
|
||||||
|
diag.help(format!(
|
||||||
|
"`{}` implements `{trait_name}` so you could box the found value \
|
||||||
|
and coerce it to the trait object `Box<dyn {trait_name}>`, you \
|
||||||
|
will have to change the expected type as well",
|
||||||
|
values.found,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(_, ty::Dynamic(t, _, ty::DynKind::Dyn))
|
||||||
|
if let Some(def_id) = t.principal_def_id() =>
|
||||||
|
{
|
||||||
|
let mut impl_def_ids = vec![];
|
||||||
|
tcx.for_each_relevant_impl(def_id, values.expected, |did| {
|
||||||
|
impl_def_ids.push(did)
|
||||||
|
});
|
||||||
|
if let [_] = &impl_def_ids[..] {
|
||||||
|
let trait_name = tcx.item_name(def_id);
|
||||||
|
diag.help(format!(
|
||||||
|
"`{}` implements `{trait_name}` so you could change the expected \
|
||||||
|
type to `Box<dyn {trait_name}>`",
|
||||||
|
values.expected,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(ty::Dynamic(t, _, ty::DynKind::DynStar), _)
|
||||||
|
if let Some(def_id) = t.principal_def_id() =>
|
||||||
|
{
|
||||||
|
let mut impl_def_ids = vec![];
|
||||||
|
tcx.for_each_relevant_impl(def_id, values.found, |did| {
|
||||||
|
impl_def_ids.push(did)
|
||||||
|
});
|
||||||
|
if let [_] = &impl_def_ids[..] {
|
||||||
|
let trait_name = tcx.item_name(def_id);
|
||||||
|
diag.help(format!(
|
||||||
|
"`{}` implements `{trait_name}`, `#[feature(dyn_star)]` is likely \
|
||||||
|
not enabled; that feature it is currently incomplete",
|
||||||
|
values.found,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
(_, ty::Alias(ty::Opaque, opaque_ty))
|
(_, ty::Alias(ty::Opaque, opaque_ty))
|
||||||
| (ty::Alias(ty::Opaque, opaque_ty), _) => {
|
| (ty::Alias(ty::Opaque, opaque_ty), _) => {
|
||||||
if opaque_ty.def_id.is_local()
|
if opaque_ty.def_id.is_local()
|
||||||
|
|
|
@ -120,7 +120,8 @@ struct QueryModifiers {
|
||||||
|
|
||||||
/// Forward the result on ensure if the query gets recomputed, and
|
/// Forward the result on ensure if the query gets recomputed, and
|
||||||
/// return `Ok(())` otherwise. Only applicable to queries returning
|
/// return `Ok(())` otherwise. Only applicable to queries returning
|
||||||
/// `Result<(), ErrorGuaranteed>`
|
/// `Result<T, ErrorGuaranteed>`. The `T` is not returned from `ensure`
|
||||||
|
/// invocations.
|
||||||
ensure_forwards_result_if_red: Option<Ident>,
|
ensure_forwards_result_if_red: Option<Ident>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -236,7 +236,14 @@ provide! { tcx, def_id, other, cdata,
|
||||||
impl_polarity => { table_direct }
|
impl_polarity => { table_direct }
|
||||||
defaultness => { table_direct }
|
defaultness => { table_direct }
|
||||||
constness => { table_direct }
|
constness => { table_direct }
|
||||||
coerce_unsized_info => { table }
|
coerce_unsized_info => {
|
||||||
|
Ok(cdata
|
||||||
|
.root
|
||||||
|
.tables
|
||||||
|
.coerce_unsized_info
|
||||||
|
.get(cdata, def_id.index)
|
||||||
|
.map(|lazy| lazy.decode((cdata, tcx)))
|
||||||
|
.process_decoded(tcx, || panic!("{def_id:?} does not have coerce_unsized_info"))) }
|
||||||
mir_const_qualif => { table }
|
mir_const_qualif => { table }
|
||||||
rendered_const => { table }
|
rendered_const => { table }
|
||||||
asyncness => { table_direct }
|
asyncness => { table_direct }
|
||||||
|
|
|
@ -1994,7 +1994,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
||||||
// if this is an impl of `CoerceUnsized`, create its
|
// if this is an impl of `CoerceUnsized`, create its
|
||||||
// "unsized info", else just store None
|
// "unsized info", else just store None
|
||||||
if Some(trait_ref.def_id) == tcx.lang_items().coerce_unsized_trait() {
|
if Some(trait_ref.def_id) == tcx.lang_items().coerce_unsized_trait() {
|
||||||
let coerce_unsized_info = tcx.coerce_unsized_info(def_id);
|
let coerce_unsized_info = tcx.coerce_unsized_info(def_id).unwrap();
|
||||||
record!(self.tables.coerce_unsized_info[def_id] <- coerce_unsized_info);
|
record!(self.tables.coerce_unsized_info[def_id] <- coerce_unsized_info);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use crate::mir;
|
use crate::mir;
|
||||||
use crate::query::CyclePlaceholder;
|
use crate::query::CyclePlaceholder;
|
||||||
use crate::traits;
|
use crate::traits;
|
||||||
|
use crate::ty::adjustment::CoerceUnsizedInfo;
|
||||||
use crate::ty::{self, Ty};
|
use crate::ty::{self, Ty};
|
||||||
use std::intrinsics::transmute_unchecked;
|
use std::intrinsics::transmute_unchecked;
|
||||||
use std::mem::{size_of, MaybeUninit};
|
use std::mem::{size_of, MaybeUninit};
|
||||||
|
@ -105,6 +106,10 @@ impl EraseType for Result<Option<ty::Instance<'_>>, rustc_errors::ErrorGuarantee
|
||||||
[u8; size_of::<Result<Option<ty::Instance<'static>>, rustc_errors::ErrorGuaranteed>>()];
|
[u8; size_of::<Result<Option<ty::Instance<'static>>, rustc_errors::ErrorGuaranteed>>()];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl EraseType for Result<CoerceUnsizedInfo, rustc_errors::ErrorGuaranteed> {
|
||||||
|
type Result = [u8; size_of::<Result<CoerceUnsizedInfo, rustc_errors::ErrorGuaranteed>>()];
|
||||||
|
}
|
||||||
|
|
||||||
impl EraseType for Result<Option<ty::EarlyBinder<ty::Const<'_>>>, rustc_errors::ErrorGuaranteed> {
|
impl EraseType for Result<Option<ty::EarlyBinder<ty::Const<'_>>>, rustc_errors::ErrorGuaranteed> {
|
||||||
type Result = [u8; size_of::<
|
type Result = [u8; size_of::<
|
||||||
Result<Option<ty::EarlyBinder<ty::Const<'static>>>, rustc_errors::ErrorGuaranteed>,
|
Result<Option<ty::EarlyBinder<ty::Const<'static>>>, rustc_errors::ErrorGuaranteed>,
|
||||||
|
|
|
@ -977,10 +977,11 @@ rustc_queries! {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Caches `CoerceUnsized` kinds for impls on custom types.
|
/// Caches `CoerceUnsized` kinds for impls on custom types.
|
||||||
query coerce_unsized_info(key: DefId) -> ty::adjustment::CoerceUnsizedInfo {
|
query coerce_unsized_info(key: DefId) -> Result<ty::adjustment::CoerceUnsizedInfo, ErrorGuaranteed> {
|
||||||
desc { |tcx| "computing CoerceUnsized info for `{}`", tcx.def_path_str(key) }
|
desc { |tcx| "computing CoerceUnsized info for `{}`", tcx.def_path_str(key) }
|
||||||
cache_on_disk_if { key.is_local() }
|
cache_on_disk_if { key.is_local() }
|
||||||
separate_provide_extern
|
separate_provide_extern
|
||||||
|
ensure_forwards_result_if_red
|
||||||
}
|
}
|
||||||
|
|
||||||
query typeck(key: LocalDefId) -> &'tcx ty::TypeckResults<'tcx> {
|
query typeck(key: LocalDefId) -> &'tcx ty::TypeckResults<'tcx> {
|
||||||
|
@ -1000,8 +1001,9 @@ rustc_queries! {
|
||||||
desc { |tcx| "checking whether `{}` has a body", tcx.def_path_str(def_id) }
|
desc { |tcx| "checking whether `{}` has a body", tcx.def_path_str(def_id) }
|
||||||
}
|
}
|
||||||
|
|
||||||
query coherent_trait(def_id: DefId) -> () {
|
query coherent_trait(def_id: DefId) -> Result<(), ErrorGuaranteed> {
|
||||||
desc { |tcx| "coherence checking all impls of trait `{}`", tcx.def_path_str(def_id) }
|
desc { |tcx| "coherence checking all impls of trait `{}`", tcx.def_path_str(def_id) }
|
||||||
|
ensure_forwards_result_if_red
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Borrow-checks the function body. If this is a closure, returns
|
/// Borrow-checks the function body. If this is a closure, returns
|
||||||
|
@ -1032,6 +1034,7 @@ rustc_queries! {
|
||||||
"checking whether impl `{}` follows the orphan rules",
|
"checking whether impl `{}` follows the orphan rules",
|
||||||
tcx.def_path_str(key),
|
tcx.def_path_str(key),
|
||||||
}
|
}
|
||||||
|
ensure_forwards_result_if_red
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check whether the function has any recursion that could cause the inliner to trigger
|
/// Check whether the function has any recursion that could cause the inliner to trigger
|
||||||
|
@ -1300,6 +1303,7 @@ rustc_queries! {
|
||||||
query specialization_graph_of(trait_id: DefId) -> Result<&'tcx specialization_graph::Graph, ErrorGuaranteed> {
|
query specialization_graph_of(trait_id: DefId) -> Result<&'tcx specialization_graph::Graph, ErrorGuaranteed> {
|
||||||
desc { |tcx| "building specialization graph of trait `{}`", tcx.def_path_str(trait_id) }
|
desc { |tcx| "building specialization graph of trait `{}`", tcx.def_path_str(trait_id) }
|
||||||
cache_on_disk_if { true }
|
cache_on_disk_if { true }
|
||||||
|
ensure_forwards_result_if_red
|
||||||
}
|
}
|
||||||
query object_safety_violations(trait_id: DefId) -> &'tcx [ObjectSafetyViolation] {
|
query object_safety_violations(trait_id: DefId) -> &'tcx [ObjectSafetyViolation] {
|
||||||
desc { |tcx| "determining object safety of trait `{}`", tcx.def_path_str(trait_id) }
|
desc { |tcx| "determining object safety of trait `{}`", tcx.def_path_str(trait_id) }
|
||||||
|
|
|
@ -350,7 +350,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||||
validate: impl Fn(Self, DefId) -> Result<(), ErrorGuaranteed>,
|
validate: impl Fn(Self, DefId) -> Result<(), ErrorGuaranteed>,
|
||||||
) -> Option<ty::Destructor> {
|
) -> Option<ty::Destructor> {
|
||||||
let drop_trait = self.lang_items().drop_trait()?;
|
let drop_trait = self.lang_items().drop_trait()?;
|
||||||
self.ensure().coherent_trait(drop_trait);
|
self.ensure().coherent_trait(drop_trait).ok()?;
|
||||||
|
|
||||||
let ty = self.type_of(adt_did).instantiate_identity();
|
let ty = self.type_of(adt_did).instantiate_identity();
|
||||||
let mut dtor_candidate = None;
|
let mut dtor_candidate = None;
|
||||||
|
|
|
@ -59,38 +59,22 @@ impl<'tcx> MirPass<'tcx> for InstrumentCoverage {
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
trace!("InstrumentCoverage starting for {def_id:?}");
|
instrument_function_for_coverage(tcx, mir_body);
|
||||||
Instrumentor::new(tcx, mir_body).inject_counters();
|
|
||||||
trace!("InstrumentCoverage done for {def_id:?}");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Instrumentor<'a, 'tcx> {
|
fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir::Body<'tcx>) {
|
||||||
tcx: TyCtxt<'tcx>,
|
let def_id = mir_body.source.def_id();
|
||||||
mir_body: &'a mut mir::Body<'tcx>,
|
let _span = debug_span!("instrument_function_for_coverage", ?def_id).entered();
|
||||||
hir_info: ExtractedHirInfo,
|
|
||||||
basic_coverage_blocks: CoverageGraph,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
|
|
||||||
fn new(tcx: TyCtxt<'tcx>, mir_body: &'a mut mir::Body<'tcx>) -> Self {
|
|
||||||
let hir_info = extract_hir_info(tcx, mir_body.source.def_id().expect_local());
|
|
||||||
|
|
||||||
debug!(?hir_info, "instrumenting {:?}", mir_body.source.def_id());
|
|
||||||
|
|
||||||
|
let hir_info = extract_hir_info(tcx, def_id.expect_local());
|
||||||
let basic_coverage_blocks = CoverageGraph::from_mir(mir_body);
|
let basic_coverage_blocks = CoverageGraph::from_mir(mir_body);
|
||||||
|
|
||||||
Self { tcx, mir_body, hir_info, basic_coverage_blocks }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn inject_counters(&'a mut self) {
|
|
||||||
////////////////////////////////////////////////////
|
////////////////////////////////////////////////////
|
||||||
// Compute coverage spans from the `CoverageGraph`.
|
// Compute coverage spans from the `CoverageGraph`.
|
||||||
let Some(coverage_spans) = CoverageSpans::generate_coverage_spans(
|
let Some(coverage_spans) =
|
||||||
self.mir_body,
|
spans::generate_coverage_spans(mir_body, &hir_info, &basic_coverage_blocks)
|
||||||
&self.hir_info,
|
else {
|
||||||
&self.basic_coverage_blocks,
|
|
||||||
) else {
|
|
||||||
// No relevant spans were found in MIR, so skip instrumenting this function.
|
// No relevant spans were found in MIR, so skip instrumenting this function.
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
@ -101,22 +85,25 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
|
||||||
// and all `Expression` dependencies (operands) are also generated, for any other
|
// and all `Expression` dependencies (operands) are also generated, for any other
|
||||||
// `BasicCoverageBlock`s not already associated with a coverage span.
|
// `BasicCoverageBlock`s not already associated with a coverage span.
|
||||||
let bcb_has_coverage_spans = |bcb| coverage_spans.bcb_has_coverage_spans(bcb);
|
let bcb_has_coverage_spans = |bcb| coverage_spans.bcb_has_coverage_spans(bcb);
|
||||||
let coverage_counters = CoverageCounters::make_bcb_counters(
|
let coverage_counters =
|
||||||
&self.basic_coverage_blocks,
|
CoverageCounters::make_bcb_counters(&basic_coverage_blocks, bcb_has_coverage_spans);
|
||||||
bcb_has_coverage_spans,
|
|
||||||
);
|
|
||||||
|
|
||||||
let mappings = self.create_mappings(&coverage_spans, &coverage_counters);
|
let mappings = create_mappings(tcx, &hir_info, &coverage_spans, &coverage_counters);
|
||||||
if mappings.is_empty() {
|
if mappings.is_empty() {
|
||||||
// No spans could be converted into valid mappings, so skip this function.
|
// No spans could be converted into valid mappings, so skip this function.
|
||||||
debug!("no spans could be converted into valid mappings; skipping");
|
debug!("no spans could be converted into valid mappings; skipping");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.inject_coverage_statements(bcb_has_coverage_spans, &coverage_counters);
|
inject_coverage_statements(
|
||||||
|
mir_body,
|
||||||
|
&basic_coverage_blocks,
|
||||||
|
bcb_has_coverage_spans,
|
||||||
|
&coverage_counters,
|
||||||
|
);
|
||||||
|
|
||||||
self.mir_body.function_coverage_info = Some(Box::new(FunctionCoverageInfo {
|
mir_body.function_coverage_info = Some(Box::new(FunctionCoverageInfo {
|
||||||
function_source_hash: self.hir_info.function_source_hash,
|
function_source_hash: hir_info.function_source_hash,
|
||||||
num_counters: coverage_counters.num_counters(),
|
num_counters: coverage_counters.num_counters(),
|
||||||
expressions: coverage_counters.into_expressions(),
|
expressions: coverage_counters.into_expressions(),
|
||||||
mappings,
|
mappings,
|
||||||
|
@ -128,18 +115,18 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
|
||||||
///
|
///
|
||||||
/// Precondition: All BCBs corresponding to those spans have been given
|
/// Precondition: All BCBs corresponding to those spans have been given
|
||||||
/// coverage counters.
|
/// coverage counters.
|
||||||
fn create_mappings(
|
fn create_mappings<'tcx>(
|
||||||
&self,
|
tcx: TyCtxt<'tcx>,
|
||||||
|
hir_info: &ExtractedHirInfo,
|
||||||
coverage_spans: &CoverageSpans,
|
coverage_spans: &CoverageSpans,
|
||||||
coverage_counters: &CoverageCounters,
|
coverage_counters: &CoverageCounters,
|
||||||
) -> Vec<Mapping> {
|
) -> Vec<Mapping> {
|
||||||
let source_map = self.tcx.sess.source_map();
|
let source_map = tcx.sess.source_map();
|
||||||
let body_span = self.hir_info.body_span;
|
let body_span = hir_info.body_span;
|
||||||
|
|
||||||
let source_file = source_map.lookup_source_file(body_span.lo());
|
let source_file = source_map.lookup_source_file(body_span.lo());
|
||||||
use rustc_session::RemapFileNameExt;
|
use rustc_session::RemapFileNameExt;
|
||||||
let file_name =
|
let file_name = Symbol::intern(&source_file.name.for_codegen(tcx.sess).to_string_lossy());
|
||||||
Symbol::intern(&source_file.name.for_codegen(self.tcx.sess).to_string_lossy());
|
|
||||||
|
|
||||||
let term_for_bcb = |bcb| {
|
let term_for_bcb = |bcb| {
|
||||||
coverage_counters
|
coverage_counters
|
||||||
|
@ -162,8 +149,9 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
|
||||||
|
|
||||||
/// For each BCB node or BCB edge that has an associated coverage counter,
|
/// For each BCB node or BCB edge that has an associated coverage counter,
|
||||||
/// inject any necessary coverage statements into MIR.
|
/// inject any necessary coverage statements into MIR.
|
||||||
fn inject_coverage_statements(
|
fn inject_coverage_statements<'tcx>(
|
||||||
&mut self,
|
mir_body: &mut mir::Body<'tcx>,
|
||||||
|
basic_coverage_blocks: &CoverageGraph,
|
||||||
bcb_has_coverage_spans: impl Fn(BasicCoverageBlock) -> bool,
|
bcb_has_coverage_spans: impl Fn(BasicCoverageBlock) -> bool,
|
||||||
coverage_counters: &CoverageCounters,
|
coverage_counters: &CoverageCounters,
|
||||||
) {
|
) {
|
||||||
|
@ -179,9 +167,9 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
|
||||||
};
|
};
|
||||||
if do_inject {
|
if do_inject {
|
||||||
inject_statement(
|
inject_statement(
|
||||||
self.mir_body,
|
mir_body,
|
||||||
self.make_mir_coverage_kind(counter_kind),
|
make_mir_coverage_kind(counter_kind),
|
||||||
self.basic_coverage_blocks[bcb].leader_bb(),
|
basic_coverage_blocks[bcb].leader_bb(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -201,27 +189,26 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
|
||||||
|
|
||||||
// We need to inject a coverage statement into a new BB between the
|
// We need to inject a coverage statement into a new BB between the
|
||||||
// last BB of `from_bcb` and the first BB of `to_bcb`.
|
// last BB of `from_bcb` and the first BB of `to_bcb`.
|
||||||
let from_bb = self.basic_coverage_blocks[from_bcb].last_bb();
|
let from_bb = basic_coverage_blocks[from_bcb].last_bb();
|
||||||
let to_bb = self.basic_coverage_blocks[to_bcb].leader_bb();
|
let to_bb = basic_coverage_blocks[to_bcb].leader_bb();
|
||||||
|
|
||||||
let new_bb = inject_edge_counter_basic_block(self.mir_body, from_bb, to_bb);
|
let new_bb = inject_edge_counter_basic_block(mir_body, from_bb, to_bb);
|
||||||
debug!(
|
debug!(
|
||||||
"Edge {from_bcb:?} (last {from_bb:?}) -> {to_bcb:?} (leader {to_bb:?}) \
|
"Edge {from_bcb:?} (last {from_bb:?}) -> {to_bcb:?} (leader {to_bb:?}) \
|
||||||
requires a new MIR BasicBlock {new_bb:?} for edge counter {counter_kind:?}",
|
requires a new MIR BasicBlock {new_bb:?} for edge counter {counter_kind:?}",
|
||||||
);
|
);
|
||||||
|
|
||||||
// Inject a counter into the newly-created BB.
|
// Inject a counter into the newly-created BB.
|
||||||
inject_statement(self.mir_body, self.make_mir_coverage_kind(counter_kind), new_bb);
|
inject_statement(mir_body, make_mir_coverage_kind(counter_kind), new_bb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_mir_coverage_kind(&self, counter_kind: &BcbCounter) -> CoverageKind {
|
fn make_mir_coverage_kind(counter_kind: &BcbCounter) -> CoverageKind {
|
||||||
match *counter_kind {
|
match *counter_kind {
|
||||||
BcbCounter::Counter { id } => CoverageKind::CounterIncrement { id },
|
BcbCounter::Counter { id } => CoverageKind::CounterIncrement { id },
|
||||||
BcbCounter::Expression { id } => CoverageKind::ExpressionUsed { id },
|
BcbCounter::Expression { id } => CoverageKind::ExpressionUsed { id },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fn inject_edge_counter_basic_block(
|
fn inject_edge_counter_basic_block(
|
||||||
mir_body: &mut mir::Body<'_>,
|
mir_body: &mut mir::Body<'_>,
|
||||||
|
|
|
@ -26,6 +26,15 @@ pub(super) struct CoverageSpans {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CoverageSpans {
|
impl CoverageSpans {
|
||||||
|
pub(super) fn bcb_has_coverage_spans(&self, bcb: BasicCoverageBlock) -> bool {
|
||||||
|
self.bcb_has_mappings.contains(bcb)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn all_bcb_mappings(&self) -> impl Iterator<Item = &BcbMapping> {
|
||||||
|
self.mappings.iter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Extracts coverage-relevant spans from MIR, and associates them with
|
/// Extracts coverage-relevant spans from MIR, and associates them with
|
||||||
/// their corresponding BCBs.
|
/// their corresponding BCBs.
|
||||||
///
|
///
|
||||||
|
@ -34,14 +43,12 @@ impl CoverageSpans {
|
||||||
mir_body: &mir::Body<'_>,
|
mir_body: &mir::Body<'_>,
|
||||||
hir_info: &ExtractedHirInfo,
|
hir_info: &ExtractedHirInfo,
|
||||||
basic_coverage_blocks: &CoverageGraph,
|
basic_coverage_blocks: &CoverageGraph,
|
||||||
) -> Option<Self> {
|
) -> Option<CoverageSpans> {
|
||||||
let mut mappings = vec![];
|
let mut mappings = vec![];
|
||||||
|
|
||||||
let coverage_spans = CoverageSpansGenerator::generate_coverage_spans(
|
let sorted_spans =
|
||||||
mir_body,
|
from_mir::mir_to_initial_sorted_coverage_spans(mir_body, hir_info, basic_coverage_blocks);
|
||||||
hir_info,
|
let coverage_spans = SpansRefiner::refine_sorted_spans(basic_coverage_blocks, sorted_spans);
|
||||||
basic_coverage_blocks,
|
|
||||||
);
|
|
||||||
mappings.extend(coverage_spans.into_iter().map(|CoverageSpan { bcb, span, .. }| {
|
mappings.extend(coverage_spans.into_iter().map(|CoverageSpan { bcb, span, .. }| {
|
||||||
// Each span produced by the generator represents an ordinary code region.
|
// Each span produced by the generator represents an ordinary code region.
|
||||||
BcbMapping { kind: BcbMappingKind::Code(bcb), span }
|
BcbMapping { kind: BcbMappingKind::Code(bcb), span }
|
||||||
|
@ -62,16 +69,7 @@ impl CoverageSpans {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(Self { bcb_has_mappings, mappings })
|
Some(CoverageSpans { bcb_has_mappings, mappings })
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn bcb_has_coverage_spans(&self, bcb: BasicCoverageBlock) -> bool {
|
|
||||||
self.bcb_has_mappings.contains(bcb)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn all_bcb_mappings(&self) -> impl Iterator<Item = &BcbMapping> {
|
|
||||||
self.mappings.iter()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A BCB is deconstructed into one or more `Span`s. Each `Span` maps to a `CoverageSpan` that
|
/// A BCB is deconstructed into one or more `Span`s. Each `Span` maps to a `CoverageSpan` that
|
||||||
|
@ -130,7 +128,7 @@ impl CoverageSpan {
|
||||||
/// * Merge spans that represent continuous (both in source code and control flow), non-branching
|
/// * Merge spans that represent continuous (both in source code and control flow), non-branching
|
||||||
/// execution
|
/// execution
|
||||||
/// * Carve out (leave uncovered) any span that will be counted by another MIR (notably, closures)
|
/// * Carve out (leave uncovered) any span that will be counted by another MIR (notably, closures)
|
||||||
struct CoverageSpansGenerator<'a> {
|
struct SpansRefiner<'a> {
|
||||||
/// The BasicCoverageBlock Control Flow Graph (BCB CFG).
|
/// The BasicCoverageBlock Control Flow Graph (BCB CFG).
|
||||||
basic_coverage_blocks: &'a CoverageGraph,
|
basic_coverage_blocks: &'a CoverageGraph,
|
||||||
|
|
||||||
|
@ -173,40 +171,15 @@ struct CoverageSpansGenerator<'a> {
|
||||||
refined_spans: Vec<CoverageSpan>,
|
refined_spans: Vec<CoverageSpan>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> CoverageSpansGenerator<'a> {
|
impl<'a> SpansRefiner<'a> {
|
||||||
/// Generate a minimal set of `CoverageSpan`s, each representing a contiguous code region to be
|
/// Takes the initial list of (sorted) spans extracted from MIR, and "refines"
|
||||||
/// counted.
|
/// them by merging compatible adjacent spans, removing redundant spans,
|
||||||
///
|
/// and carving holes in spans when they overlap in unwanted ways.
|
||||||
/// The basic steps are:
|
fn refine_sorted_spans(
|
||||||
///
|
|
||||||
/// 1. Extract an initial set of spans from the `Statement`s and `Terminator`s of each
|
|
||||||
/// `BasicCoverageBlockData`.
|
|
||||||
/// 2. Sort the spans by span.lo() (starting position). Spans that start at the same position
|
|
||||||
/// are sorted with longer spans before shorter spans; and equal spans are sorted
|
|
||||||
/// (deterministically) based on "dominator" relationship (if any).
|
|
||||||
/// 3. Traverse the spans in sorted order to identify spans that can be dropped (for instance,
|
|
||||||
/// if another span or spans are already counting the same code region), or should be merged
|
|
||||||
/// into a broader combined span (because it represents a contiguous, non-branching, and
|
|
||||||
/// uninterrupted region of source code).
|
|
||||||
///
|
|
||||||
/// Closures are exposed in their enclosing functions as `Assign` `Rvalue`s, and since
|
|
||||||
/// closures have their own MIR, their `Span` in their enclosing function should be left
|
|
||||||
/// "uncovered".
|
|
||||||
///
|
|
||||||
/// Note the resulting vector of `CoverageSpan`s may not be fully sorted (and does not need
|
|
||||||
/// to be).
|
|
||||||
pub(super) fn generate_coverage_spans(
|
|
||||||
mir_body: &mir::Body<'_>,
|
|
||||||
hir_info: &ExtractedHirInfo,
|
|
||||||
basic_coverage_blocks: &'a CoverageGraph,
|
basic_coverage_blocks: &'a CoverageGraph,
|
||||||
|
sorted_spans: Vec<CoverageSpan>,
|
||||||
) -> Vec<CoverageSpan> {
|
) -> Vec<CoverageSpan> {
|
||||||
let sorted_spans = from_mir::mir_to_initial_sorted_coverage_spans(
|
let this = Self {
|
||||||
mir_body,
|
|
||||||
hir_info,
|
|
||||||
basic_coverage_blocks,
|
|
||||||
);
|
|
||||||
|
|
||||||
let coverage_spans = Self {
|
|
||||||
basic_coverage_blocks,
|
basic_coverage_blocks,
|
||||||
sorted_spans_iter: sorted_spans.into_iter(),
|
sorted_spans_iter: sorted_spans.into_iter(),
|
||||||
some_curr: None,
|
some_curr: None,
|
||||||
|
@ -217,7 +190,7 @@ impl<'a> CoverageSpansGenerator<'a> {
|
||||||
refined_spans: Vec::with_capacity(basic_coverage_blocks.num_nodes() * 2),
|
refined_spans: Vec::with_capacity(basic_coverage_blocks.num_nodes() * 2),
|
||||||
};
|
};
|
||||||
|
|
||||||
coverage_spans.to_refined_spans()
|
this.to_refined_spans()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Iterate through the sorted `CoverageSpan`s, and return the refined list of merged and
|
/// Iterate through the sorted `CoverageSpan`s, and return the refined list of merged and
|
||||||
|
|
|
@ -12,6 +12,12 @@ use crate::coverage::graph::{
|
||||||
use crate::coverage::spans::CoverageSpan;
|
use crate::coverage::spans::CoverageSpan;
|
||||||
use crate::coverage::ExtractedHirInfo;
|
use crate::coverage::ExtractedHirInfo;
|
||||||
|
|
||||||
|
/// Traverses the MIR body to produce an initial collection of coverage-relevant
|
||||||
|
/// spans, each associated with a node in the coverage graph (BCB) and possibly
|
||||||
|
/// other metadata.
|
||||||
|
///
|
||||||
|
/// The returned spans are sorted in a specific order that is expected by the
|
||||||
|
/// subsequent span-refinement step.
|
||||||
pub(super) fn mir_to_initial_sorted_coverage_spans(
|
pub(super) fn mir_to_initial_sorted_coverage_spans(
|
||||||
mir_body: &mir::Body<'_>,
|
mir_body: &mir::Body<'_>,
|
||||||
hir_info: &ExtractedHirInfo,
|
hir_info: &ExtractedHirInfo,
|
||||||
|
|
|
@ -1113,7 +1113,13 @@ fn find_vtable_types_for_unsizing<'tcx>(
|
||||||
assert_eq!(source_adt_def, target_adt_def);
|
assert_eq!(source_adt_def, target_adt_def);
|
||||||
|
|
||||||
let CustomCoerceUnsized::Struct(coerce_index) =
|
let CustomCoerceUnsized::Struct(coerce_index) =
|
||||||
crate::custom_coerce_unsize_info(tcx, source_ty, target_ty);
|
match crate::custom_coerce_unsize_info(tcx, source_ty, target_ty) {
|
||||||
|
Ok(ccu) => ccu,
|
||||||
|
Err(e) => {
|
||||||
|
let e = Ty::new_error(tcx.tcx, e);
|
||||||
|
return (e, e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let source_fields = &source_adt_def.non_enum_variant().fields;
|
let source_fields = &source_adt_def.non_enum_variant().fields;
|
||||||
let target_fields = &target_adt_def.non_enum_variant().fields;
|
let target_fields = &target_adt_def.non_enum_variant().fields;
|
||||||
|
|
|
@ -15,6 +15,7 @@ use rustc_middle::query::{Providers, TyCtxtAt};
|
||||||
use rustc_middle::traits;
|
use rustc_middle::traits;
|
||||||
use rustc_middle::ty::adjustment::CustomCoerceUnsized;
|
use rustc_middle::ty::adjustment::CustomCoerceUnsized;
|
||||||
use rustc_middle::ty::{self, Ty};
|
use rustc_middle::ty::{self, Ty};
|
||||||
|
use rustc_span::ErrorGuaranteed;
|
||||||
|
|
||||||
mod collector;
|
mod collector;
|
||||||
mod errors;
|
mod errors;
|
||||||
|
@ -28,7 +29,7 @@ fn custom_coerce_unsize_info<'tcx>(
|
||||||
tcx: TyCtxtAt<'tcx>,
|
tcx: TyCtxtAt<'tcx>,
|
||||||
source_ty: Ty<'tcx>,
|
source_ty: Ty<'tcx>,
|
||||||
target_ty: Ty<'tcx>,
|
target_ty: Ty<'tcx>,
|
||||||
) -> CustomCoerceUnsized {
|
) -> Result<CustomCoerceUnsized, ErrorGuaranteed> {
|
||||||
let trait_ref = ty::TraitRef::from_lang_item(
|
let trait_ref = ty::TraitRef::from_lang_item(
|
||||||
tcx.tcx,
|
tcx.tcx,
|
||||||
LangItem::CoerceUnsized,
|
LangItem::CoerceUnsized,
|
||||||
|
@ -40,7 +41,7 @@ fn custom_coerce_unsize_info<'tcx>(
|
||||||
Ok(traits::ImplSource::UserDefined(traits::ImplSourceUserDefinedData {
|
Ok(traits::ImplSource::UserDefined(traits::ImplSourceUserDefinedData {
|
||||||
impl_def_id,
|
impl_def_id,
|
||||||
..
|
..
|
||||||
})) => tcx.coerce_unsized_info(impl_def_id).custom_kind.unwrap(),
|
})) => Ok(tcx.coerce_unsized_info(impl_def_id)?.custom_kind.unwrap()),
|
||||||
impl_source => {
|
impl_source => {
|
||||||
bug!("invalid `CoerceUnsized` impl_source: {:?}", impl_source);
|
bug!("invalid `CoerceUnsized` impl_source: {:?}", impl_source);
|
||||||
}
|
}
|
||||||
|
|
|
@ -391,6 +391,11 @@ impl IntRange {
|
||||||
/// first.
|
/// first.
|
||||||
impl fmt::Debug for IntRange {
|
impl fmt::Debug for IntRange {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
if self.is_singleton() {
|
||||||
|
// Only finite ranges can be singletons.
|
||||||
|
let Finite(lo) = self.lo else { unreachable!() };
|
||||||
|
write!(f, "{lo}")?;
|
||||||
|
} else {
|
||||||
if let Finite(lo) = self.lo {
|
if let Finite(lo) = self.lo {
|
||||||
write!(f, "{lo}")?;
|
write!(f, "{lo}")?;
|
||||||
}
|
}
|
||||||
|
@ -398,6 +403,7 @@ impl fmt::Debug for IntRange {
|
||||||
if let Finite(hi) = self.hi {
|
if let Finite(hi) = self.hi {
|
||||||
write!(f, "{hi}")?;
|
write!(f, "{hi}")?;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -101,15 +101,23 @@ pub trait TypeCx: Sized + fmt::Debug {
|
||||||
|
|
||||||
/// The types of the fields for this constructor. The result must have a length of
|
/// The types of the fields for this constructor. The result must have a length of
|
||||||
/// `ctor_arity()`.
|
/// `ctor_arity()`.
|
||||||
fn ctor_sub_tys(&self, ctor: &Constructor<Self>, ty: &Self::Ty) -> &[Self::Ty];
|
fn ctor_sub_tys<'a>(
|
||||||
|
&'a self,
|
||||||
|
ctor: &'a Constructor<Self>,
|
||||||
|
ty: &'a Self::Ty,
|
||||||
|
) -> impl Iterator<Item = Self::Ty> + ExactSizeIterator + Captures<'a>;
|
||||||
|
|
||||||
/// The set of all the constructors for `ty`.
|
/// The set of all the constructors for `ty`.
|
||||||
///
|
///
|
||||||
/// This must follow the invariants of `ConstructorSet`
|
/// This must follow the invariants of `ConstructorSet`
|
||||||
fn ctors_for_ty(&self, ty: &Self::Ty) -> Result<ConstructorSet<Self>, Self::Error>;
|
fn ctors_for_ty(&self, ty: &Self::Ty) -> Result<ConstructorSet<Self>, Self::Error>;
|
||||||
|
|
||||||
/// Best-effort `Debug` implementation.
|
/// Write the name of the variant represented by `pat`. Used for the best-effort `Debug` impl of
|
||||||
fn debug_pat(f: &mut fmt::Formatter<'_>, pat: &DeconstructedPat<'_, Self>) -> fmt::Result;
|
/// `DeconstructedPat`. Only invoqued when `pat.ctor()` is `Struct | Variant(_) | UnionField`.
|
||||||
|
fn write_variant_name(
|
||||||
|
f: &mut fmt::Formatter<'_>,
|
||||||
|
pat: &crate::pat::DeconstructedPat<'_, Self>,
|
||||||
|
) -> fmt::Result;
|
||||||
|
|
||||||
/// Raise a bug.
|
/// Raise a bug.
|
||||||
fn bug(&self, fmt: fmt::Arguments<'_>) -> !;
|
fn bug(&self, fmt: fmt::Arguments<'_>) -> !;
|
||||||
|
|
|
@ -142,7 +142,75 @@ impl<'p, Cx: TypeCx> DeconstructedPat<'p, Cx> {
|
||||||
/// This is best effort and not good enough for a `Display` impl.
|
/// This is best effort and not good enough for a `Display` impl.
|
||||||
impl<'p, Cx: TypeCx> fmt::Debug for DeconstructedPat<'p, Cx> {
|
impl<'p, Cx: TypeCx> fmt::Debug for DeconstructedPat<'p, Cx> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
Cx::debug_pat(f, self)
|
let pat = self;
|
||||||
|
let mut first = true;
|
||||||
|
let mut start_or_continue = |s| {
|
||||||
|
if first {
|
||||||
|
first = false;
|
||||||
|
""
|
||||||
|
} else {
|
||||||
|
s
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let mut start_or_comma = || start_or_continue(", ");
|
||||||
|
|
||||||
|
match pat.ctor() {
|
||||||
|
Struct | Variant(_) | UnionField => {
|
||||||
|
Cx::write_variant_name(f, pat)?;
|
||||||
|
// Without `cx`, we can't know which field corresponds to which, so we can't
|
||||||
|
// get the names of the fields. Instead we just display everything as a tuple
|
||||||
|
// struct, which should be good enough.
|
||||||
|
write!(f, "(")?;
|
||||||
|
for p in pat.iter_fields() {
|
||||||
|
write!(f, "{}", start_or_comma())?;
|
||||||
|
write!(f, "{p:?}")?;
|
||||||
|
}
|
||||||
|
write!(f, ")")
|
||||||
|
}
|
||||||
|
// Note: given the expansion of `&str` patterns done in `expand_pattern`, we should
|
||||||
|
// be careful to detect strings here. However a string literal pattern will never
|
||||||
|
// be reported as a non-exhaustiveness witness, so we can ignore this issue.
|
||||||
|
Ref => {
|
||||||
|
let subpattern = pat.iter_fields().next().unwrap();
|
||||||
|
write!(f, "&{:?}", subpattern)
|
||||||
|
}
|
||||||
|
Slice(slice) => {
|
||||||
|
let mut subpatterns = pat.iter_fields();
|
||||||
|
write!(f, "[")?;
|
||||||
|
match slice.kind {
|
||||||
|
SliceKind::FixedLen(_) => {
|
||||||
|
for p in subpatterns {
|
||||||
|
write!(f, "{}{:?}", start_or_comma(), p)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SliceKind::VarLen(prefix_len, _) => {
|
||||||
|
for p in subpatterns.by_ref().take(prefix_len) {
|
||||||
|
write!(f, "{}{:?}", start_or_comma(), p)?;
|
||||||
|
}
|
||||||
|
write!(f, "{}", start_or_comma())?;
|
||||||
|
write!(f, "..")?;
|
||||||
|
for p in subpatterns {
|
||||||
|
write!(f, "{}{:?}", start_or_comma(), p)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
write!(f, "]")
|
||||||
|
}
|
||||||
|
Bool(b) => write!(f, "{b}"),
|
||||||
|
// Best-effort, will render signed ranges incorrectly
|
||||||
|
IntRange(range) => write!(f, "{range:?}"),
|
||||||
|
F32Range(lo, hi, end) => write!(f, "{lo}{end}{hi}"),
|
||||||
|
F64Range(lo, hi, end) => write!(f, "{lo}{end}{hi}"),
|
||||||
|
Str(value) => write!(f, "{value:?}"),
|
||||||
|
Opaque(..) => write!(f, "<constant pattern>"),
|
||||||
|
Or => {
|
||||||
|
for pat in pat.iter_fields() {
|
||||||
|
write!(f, "{}{:?}", start_or_continue(" | "), pat)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Wildcard | Missing { .. } | NonExhaustive | Hidden => write!(f, "_ : {:?}", pat.ty()),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -241,8 +309,7 @@ impl<Cx: TypeCx> WitnessPat<Cx> {
|
||||||
/// For example, if `ctor` is a `Constructor::Variant` for `Option::Some`, we get the pattern
|
/// For example, if `ctor` is a `Constructor::Variant` for `Option::Some`, we get the pattern
|
||||||
/// `Some(_)`.
|
/// `Some(_)`.
|
||||||
pub(crate) fn wild_from_ctor(pcx: &PlaceCtxt<'_, Cx>, ctor: Constructor<Cx>) -> Self {
|
pub(crate) fn wild_from_ctor(pcx: &PlaceCtxt<'_, Cx>, ctor: Constructor<Cx>) -> Self {
|
||||||
let field_tys = pcx.ctor_sub_tys(&ctor);
|
let fields = pcx.ctor_sub_tys(&ctor).map(|ty| Self::wildcard(ty)).collect();
|
||||||
let fields = field_tys.iter().cloned().map(|ty| Self::wildcard(ty)).collect();
|
|
||||||
Self::new(ctor, fields, pcx.ty.clone())
|
Self::new(ctor, fields, pcx.ty.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,6 @@ use std::fmt;
|
||||||
use std::iter::once;
|
use std::iter::once;
|
||||||
|
|
||||||
use rustc_arena::{DroplessArena, TypedArena};
|
use rustc_arena::{DroplessArena, TypedArena};
|
||||||
use rustc_data_structures::captures::Captures;
|
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_hir::HirId;
|
use rustc_hir::HirId;
|
||||||
use rustc_index::{Idx, IndexVec};
|
use rustc_index::{Idx, IndexVec};
|
||||||
|
@ -20,7 +19,7 @@ use rustc_target::abi::{FieldIdx, Integer, VariantIdx, FIRST_VARIANT};
|
||||||
use crate::constructor::{
|
use crate::constructor::{
|
||||||
IntRange, MaybeInfiniteInt, OpaqueId, RangeEnd, Slice, SliceKind, VariantVisibility,
|
IntRange, MaybeInfiniteInt, OpaqueId, RangeEnd, Slice, SliceKind, VariantVisibility,
|
||||||
};
|
};
|
||||||
use crate::{errors, TypeCx};
|
use crate::{errors, Captures, TypeCx};
|
||||||
|
|
||||||
use crate::constructor::Constructor::*;
|
use crate::constructor::Constructor::*;
|
||||||
|
|
||||||
|
@ -210,11 +209,11 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> {
|
||||||
/// Returns the types of the fields for a given constructor. The result must have a length of
|
/// Returns the types of the fields for a given constructor. The result must have a length of
|
||||||
/// `ctor.arity()`.
|
/// `ctor.arity()`.
|
||||||
#[instrument(level = "trace", skip(self))]
|
#[instrument(level = "trace", skip(self))]
|
||||||
pub(crate) fn ctor_sub_tys(
|
pub(crate) fn ctor_sub_tys<'a>(
|
||||||
&self,
|
&'a self,
|
||||||
ctor: &Constructor<'p, 'tcx>,
|
ctor: &'a Constructor<'p, 'tcx>,
|
||||||
ty: RevealedTy<'tcx>,
|
ty: RevealedTy<'tcx>,
|
||||||
) -> &[RevealedTy<'tcx>] {
|
) -> impl Iterator<Item = RevealedTy<'tcx>> + ExactSizeIterator + Captures<'a> {
|
||||||
fn reveal_and_alloc<'a, 'tcx>(
|
fn reveal_and_alloc<'a, 'tcx>(
|
||||||
cx: &'a RustcMatchCheckCtxt<'_, 'tcx>,
|
cx: &'a RustcMatchCheckCtxt<'_, 'tcx>,
|
||||||
iter: impl Iterator<Item = Ty<'tcx>>,
|
iter: impl Iterator<Item = Ty<'tcx>>,
|
||||||
|
@ -222,7 +221,7 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> {
|
||||||
cx.dropless_arena.alloc_from_iter(iter.map(|ty| cx.reveal_opaque_ty(ty)))
|
cx.dropless_arena.alloc_from_iter(iter.map(|ty| cx.reveal_opaque_ty(ty)))
|
||||||
}
|
}
|
||||||
let cx = self;
|
let cx = self;
|
||||||
match ctor {
|
let slice = match ctor {
|
||||||
Struct | Variant(_) | UnionField => match ty.kind() {
|
Struct | Variant(_) | UnionField => match ty.kind() {
|
||||||
ty::Tuple(fs) => reveal_and_alloc(cx, fs.iter()),
|
ty::Tuple(fs) => reveal_and_alloc(cx, fs.iter()),
|
||||||
ty::Adt(adt, args) => {
|
ty::Adt(adt, args) => {
|
||||||
|
@ -263,7 +262,8 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> {
|
||||||
Or => {
|
Or => {
|
||||||
bug!("called `Fields::wildcards` on an `Or` ctor")
|
bug!("called `Fields::wildcards` on an `Or` ctor")
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
slice.iter().copied()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The number of fields for this constructor.
|
/// The number of fields for this constructor.
|
||||||
|
@ -850,103 +850,6 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> {
|
||||||
|
|
||||||
Pat { ty: pat.ty().inner(), span: DUMMY_SP, kind }
|
Pat { ty: pat.ty().inner(), span: DUMMY_SP, kind }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Best-effort `Debug` implementation.
|
|
||||||
pub(crate) fn debug_pat(
|
|
||||||
f: &mut fmt::Formatter<'_>,
|
|
||||||
pat: &crate::pat::DeconstructedPat<'_, Self>,
|
|
||||||
) -> fmt::Result {
|
|
||||||
let mut first = true;
|
|
||||||
let mut start_or_continue = |s| {
|
|
||||||
if first {
|
|
||||||
first = false;
|
|
||||||
""
|
|
||||||
} else {
|
|
||||||
s
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let mut start_or_comma = || start_or_continue(", ");
|
|
||||||
|
|
||||||
match pat.ctor() {
|
|
||||||
Struct | Variant(_) | UnionField => match pat.ty().kind() {
|
|
||||||
ty::Adt(def, _) if def.is_box() => {
|
|
||||||
// Without `box_patterns`, the only legal pattern of type `Box` is `_` (outside
|
|
||||||
// of `std`). So this branch is only reachable when the feature is enabled and
|
|
||||||
// the pattern is a box pattern.
|
|
||||||
let subpattern = pat.iter_fields().next().unwrap();
|
|
||||||
write!(f, "box {subpattern:?}")
|
|
||||||
}
|
|
||||||
ty::Adt(..) | ty::Tuple(..) => {
|
|
||||||
let variant =
|
|
||||||
match pat.ty().kind() {
|
|
||||||
ty::Adt(adt, _) => Some(adt.variant(
|
|
||||||
RustcMatchCheckCtxt::variant_index_for_adt(pat.ctor(), *adt),
|
|
||||||
)),
|
|
||||||
ty::Tuple(_) => None,
|
|
||||||
_ => unreachable!(),
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(variant) = variant {
|
|
||||||
write!(f, "{}", variant.name)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Without `cx`, we can't know which field corresponds to which, so we can't
|
|
||||||
// get the names of the fields. Instead we just display everything as a tuple
|
|
||||||
// struct, which should be good enough.
|
|
||||||
write!(f, "(")?;
|
|
||||||
for p in pat.iter_fields() {
|
|
||||||
write!(f, "{}", start_or_comma())?;
|
|
||||||
write!(f, "{p:?}")?;
|
|
||||||
}
|
|
||||||
write!(f, ")")
|
|
||||||
}
|
|
||||||
_ => write!(f, "_"),
|
|
||||||
},
|
|
||||||
// Note: given the expansion of `&str` patterns done in `expand_pattern`, we should
|
|
||||||
// be careful to detect strings here. However a string literal pattern will never
|
|
||||||
// be reported as a non-exhaustiveness witness, so we can ignore this issue.
|
|
||||||
Ref => {
|
|
||||||
let subpattern = pat.iter_fields().next().unwrap();
|
|
||||||
write!(f, "&{:?}", subpattern)
|
|
||||||
}
|
|
||||||
Slice(slice) => {
|
|
||||||
let mut subpatterns = pat.iter_fields();
|
|
||||||
write!(f, "[")?;
|
|
||||||
match slice.kind {
|
|
||||||
SliceKind::FixedLen(_) => {
|
|
||||||
for p in subpatterns {
|
|
||||||
write!(f, "{}{:?}", start_or_comma(), p)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SliceKind::VarLen(prefix_len, _) => {
|
|
||||||
for p in subpatterns.by_ref().take(prefix_len) {
|
|
||||||
write!(f, "{}{:?}", start_or_comma(), p)?;
|
|
||||||
}
|
|
||||||
write!(f, "{}", start_or_comma())?;
|
|
||||||
write!(f, "..")?;
|
|
||||||
for p in subpatterns {
|
|
||||||
write!(f, "{}{:?}", start_or_comma(), p)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
write!(f, "]")
|
|
||||||
}
|
|
||||||
Bool(b) => write!(f, "{b}"),
|
|
||||||
// Best-effort, will render signed ranges incorrectly
|
|
||||||
IntRange(range) => write!(f, "{range:?}"),
|
|
||||||
F32Range(lo, hi, end) => write!(f, "{lo}{end}{hi}"),
|
|
||||||
F64Range(lo, hi, end) => write!(f, "{lo}{end}{hi}"),
|
|
||||||
Str(value) => write!(f, "{value}"),
|
|
||||||
Opaque(..) => write!(f, "<constant pattern>"),
|
|
||||||
Or => {
|
|
||||||
for pat in pat.iter_fields() {
|
|
||||||
write!(f, "{}{:?}", start_or_continue(" | "), pat)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
Wildcard | Missing { .. } | NonExhaustive | Hidden => write!(f, "_ : {:?}", pat.ty()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'p, 'tcx> TypeCx for RustcMatchCheckCtxt<'p, 'tcx> {
|
impl<'p, 'tcx> TypeCx for RustcMatchCheckCtxt<'p, 'tcx> {
|
||||||
|
@ -964,11 +867,11 @@ impl<'p, 'tcx> TypeCx for RustcMatchCheckCtxt<'p, 'tcx> {
|
||||||
fn ctor_arity(&self, ctor: &crate::constructor::Constructor<Self>, ty: &Self::Ty) -> usize {
|
fn ctor_arity(&self, ctor: &crate::constructor::Constructor<Self>, ty: &Self::Ty) -> usize {
|
||||||
self.ctor_arity(ctor, *ty)
|
self.ctor_arity(ctor, *ty)
|
||||||
}
|
}
|
||||||
fn ctor_sub_tys(
|
fn ctor_sub_tys<'a>(
|
||||||
&self,
|
&'a self,
|
||||||
ctor: &crate::constructor::Constructor<Self>,
|
ctor: &'a crate::constructor::Constructor<Self>,
|
||||||
ty: &Self::Ty,
|
ty: &'a Self::Ty,
|
||||||
) -> &[Self::Ty] {
|
) -> impl Iterator<Item = Self::Ty> + ExactSizeIterator + Captures<'a> {
|
||||||
self.ctor_sub_tys(ctor, *ty)
|
self.ctor_sub_tys(ctor, *ty)
|
||||||
}
|
}
|
||||||
fn ctors_for_ty(
|
fn ctors_for_ty(
|
||||||
|
@ -978,12 +881,21 @@ impl<'p, 'tcx> TypeCx for RustcMatchCheckCtxt<'p, 'tcx> {
|
||||||
self.ctors_for_ty(*ty)
|
self.ctors_for_ty(*ty)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn debug_pat(
|
fn write_variant_name(
|
||||||
f: &mut fmt::Formatter<'_>,
|
f: &mut fmt::Formatter<'_>,
|
||||||
pat: &crate::pat::DeconstructedPat<'_, Self>,
|
pat: &crate::pat::DeconstructedPat<'_, Self>,
|
||||||
) -> fmt::Result {
|
) -> fmt::Result {
|
||||||
Self::debug_pat(f, pat)
|
if let ty::Adt(adt, _) = pat.ty().kind() {
|
||||||
|
if adt.is_box() {
|
||||||
|
write!(f, "Box")?
|
||||||
|
} else {
|
||||||
|
let variant = adt.variant(Self::variant_index_for_adt(pat.ctor(), *adt));
|
||||||
|
write!(f, "{}", variant.name)?;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn bug(&self, fmt: fmt::Arguments<'_>) -> ! {
|
fn bug(&self, fmt: fmt::Arguments<'_>) -> ! {
|
||||||
span_bug!(self.scrut_span, "{}", fmt)
|
span_bug!(self.scrut_span, "{}", fmt)
|
||||||
}
|
}
|
||||||
|
|
|
@ -750,7 +750,10 @@ impl<'a, Cx: TypeCx> PlaceCtxt<'a, Cx> {
|
||||||
pub(crate) fn ctor_arity(&self, ctor: &Constructor<Cx>) -> usize {
|
pub(crate) fn ctor_arity(&self, ctor: &Constructor<Cx>) -> usize {
|
||||||
self.mcx.tycx.ctor_arity(ctor, self.ty)
|
self.mcx.tycx.ctor_arity(ctor, self.ty)
|
||||||
}
|
}
|
||||||
pub(crate) fn ctor_sub_tys(&self, ctor: &Constructor<Cx>) -> &[Cx::Ty] {
|
pub(crate) fn ctor_sub_tys(
|
||||||
|
&'a self,
|
||||||
|
ctor: &'a Constructor<Cx>,
|
||||||
|
) -> impl Iterator<Item = Cx::Ty> + ExactSizeIterator + Captures<'a> {
|
||||||
self.mcx.tycx.ctor_sub_tys(ctor, self.ty)
|
self.mcx.tycx.ctor_sub_tys(ctor, self.ty)
|
||||||
}
|
}
|
||||||
pub(crate) fn ctors_for_ty(&self) -> Result<ConstructorSet<Cx>, Cx::Error> {
|
pub(crate) fn ctors_for_ty(&self) -> Result<ConstructorSet<Cx>, Cx::Error> {
|
||||||
|
@ -1058,8 +1061,7 @@ impl<'p, Cx: TypeCx> Matrix<'p, Cx> {
|
||||||
) -> Matrix<'p, Cx> {
|
) -> Matrix<'p, Cx> {
|
||||||
let ctor_sub_tys = pcx.ctor_sub_tys(ctor);
|
let ctor_sub_tys = pcx.ctor_sub_tys(ctor);
|
||||||
let arity = ctor_sub_tys.len();
|
let arity = ctor_sub_tys.len();
|
||||||
let specialized_place_ty =
|
let specialized_place_ty = ctor_sub_tys.chain(self.place_ty[1..].iter().cloned()).collect();
|
||||||
ctor_sub_tys.iter().chain(self.place_ty[1..].iter()).cloned().collect();
|
|
||||||
let ctor_sub_validity = self.place_validity[0].specialize(ctor);
|
let ctor_sub_validity = self.place_validity[0].specialize(ctor);
|
||||||
let specialized_place_validity = std::iter::repeat(ctor_sub_validity)
|
let specialized_place_validity = std::iter::repeat(ctor_sub_validity)
|
||||||
.take(arity)
|
.take(arity)
|
||||||
|
|
|
@ -332,20 +332,6 @@ impl Session {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME(matthewjasper) Remove this method, it should never be needed.
|
|
||||||
pub fn track_errors<F, T>(&self, f: F) -> Result<T, ErrorGuaranteed>
|
|
||||||
where
|
|
||||||
F: FnOnce() -> T,
|
|
||||||
{
|
|
||||||
let old_count = self.dcx().err_count();
|
|
||||||
let result = f();
|
|
||||||
if self.dcx().err_count() == old_count {
|
|
||||||
Ok(result)
|
|
||||||
} else {
|
|
||||||
Err(self.dcx().delayed_bug("`self.err_count()` changed but an error was not emitted"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Used for code paths of expensive computations that should only take place when
|
/// Used for code paths of expensive computations that should only take place when
|
||||||
/// warnings or errors are emitted. If no messages are emitted ("good path"), then
|
/// warnings or errors are emitted. If no messages are emitted ("good path"), then
|
||||||
/// it's likely a bug.
|
/// it's likely a bug.
|
||||||
|
@ -1524,16 +1510,25 @@ pub trait RemapFileNameExt {
|
||||||
where
|
where
|
||||||
Self: 'a;
|
Self: 'a;
|
||||||
|
|
||||||
fn for_scope(&self, sess: &Session, scopes: RemapPathScopeComponents) -> Self::Output<'_>;
|
/// Returns a possibly remapped filename based on the passed scope and remap cli options.
|
||||||
|
///
|
||||||
|
/// One and only one scope should be passed to this method. For anything related to
|
||||||
|
/// "codegen" see the [`RemapFileNameExt::for_codegen`] method.
|
||||||
|
fn for_scope(&self, sess: &Session, scope: RemapPathScopeComponents) -> Self::Output<'_>;
|
||||||
|
|
||||||
|
/// Return a possibly remapped filename, to be used in "codegen" related parts.
|
||||||
fn for_codegen(&self, sess: &Session) -> Self::Output<'_>;
|
fn for_codegen(&self, sess: &Session) -> Self::Output<'_>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RemapFileNameExt for rustc_span::FileName {
|
impl RemapFileNameExt for rustc_span::FileName {
|
||||||
type Output<'a> = rustc_span::FileNameDisplay<'a>;
|
type Output<'a> = rustc_span::FileNameDisplay<'a>;
|
||||||
|
|
||||||
fn for_scope(&self, sess: &Session, scopes: RemapPathScopeComponents) -> Self::Output<'_> {
|
fn for_scope(&self, sess: &Session, scope: RemapPathScopeComponents) -> Self::Output<'_> {
|
||||||
if sess.opts.unstable_opts.remap_path_scope.contains(scopes) {
|
assert!(
|
||||||
|
scope.bits().count_ones() == 1,
|
||||||
|
"one and only one scope should be passed to for_scope"
|
||||||
|
);
|
||||||
|
if sess.opts.unstable_opts.remap_path_scope.contains(scope) {
|
||||||
self.prefer_remapped_unconditionaly()
|
self.prefer_remapped_unconditionaly()
|
||||||
} else {
|
} else {
|
||||||
self.prefer_local()
|
self.prefer_local()
|
||||||
|
@ -1552,8 +1547,12 @@ impl RemapFileNameExt for rustc_span::FileName {
|
||||||
impl RemapFileNameExt for rustc_span::RealFileName {
|
impl RemapFileNameExt for rustc_span::RealFileName {
|
||||||
type Output<'a> = &'a Path;
|
type Output<'a> = &'a Path;
|
||||||
|
|
||||||
fn for_scope(&self, sess: &Session, scopes: RemapPathScopeComponents) -> Self::Output<'_> {
|
fn for_scope(&self, sess: &Session, scope: RemapPathScopeComponents) -> Self::Output<'_> {
|
||||||
if sess.opts.unstable_opts.remap_path_scope.contains(scopes) {
|
assert!(
|
||||||
|
scope.bits().count_ones() == 1,
|
||||||
|
"one and only one scope should be passed to for_scope"
|
||||||
|
);
|
||||||
|
if sess.opts.unstable_opts.remap_path_scope.contains(scope) {
|
||||||
self.remapped_path_if_available()
|
self.remapped_path_if_available()
|
||||||
} else {
|
} else {
|
||||||
self.local_path_if_available()
|
self.local_path_if_available()
|
||||||
|
|
|
@ -425,8 +425,14 @@ symbols! {
|
||||||
assume,
|
assume,
|
||||||
assume_init,
|
assume_init,
|
||||||
async_await,
|
async_await,
|
||||||
|
async_call,
|
||||||
|
async_call_mut,
|
||||||
|
async_call_once,
|
||||||
async_closure,
|
async_closure,
|
||||||
|
async_fn,
|
||||||
async_fn_in_trait,
|
async_fn_in_trait,
|
||||||
|
async_fn_mut,
|
||||||
|
async_fn_once,
|
||||||
async_fn_track_caller,
|
async_fn_track_caller,
|
||||||
async_for_loop,
|
async_for_loop,
|
||||||
async_iterator,
|
async_iterator,
|
||||||
|
|
|
@ -38,9 +38,6 @@ pub fn options() -> TargetOptions {
|
||||||
// supposed to be imported and have all other symbols generate errors if
|
// supposed to be imported and have all other symbols generate errors if
|
||||||
// they remain undefined.
|
// they remain undefined.
|
||||||
concat!($prefix, "--allow-undefined"),
|
concat!($prefix, "--allow-undefined"),
|
||||||
// Rust code should never have warnings, and warnings are often
|
|
||||||
// indicative of bugs, let's prevent them.
|
|
||||||
concat!($prefix, "--fatal-warnings"),
|
|
||||||
// LLD only implements C++-like demangling, which doesn't match our own
|
// LLD only implements C++-like demangling, which doesn't match our own
|
||||||
// mangling scheme. Tell LLD to not demangle anything and leave it up to
|
// mangling scheme. Tell LLD to not demangle anything and leave it up to
|
||||||
// us to demangle these symbols later. Currently rustc does not perform
|
// us to demangle these symbols later. Currently rustc does not perform
|
||||||
|
|
|
@ -5,10 +5,7 @@ use crate::spec::{
|
||||||
pub fn target() -> Target {
|
pub fn target() -> Target {
|
||||||
// Reset flags for non-Em flavors back to empty to satisfy sanity checking tests.
|
// Reset flags for non-Em flavors back to empty to satisfy sanity checking tests.
|
||||||
let pre_link_args = LinkArgs::new();
|
let pre_link_args = LinkArgs::new();
|
||||||
let post_link_args = TargetOptions::link_args(
|
let post_link_args = TargetOptions::link_args(LinkerFlavor::EmCc, &["-sABORTING_MALLOC=0"]);
|
||||||
LinkerFlavor::EmCc,
|
|
||||||
&["-sABORTING_MALLOC=0", "-Wl,--fatal-warnings"],
|
|
||||||
);
|
|
||||||
|
|
||||||
let opts = TargetOptions {
|
let opts = TargetOptions {
|
||||||
os: "emscripten".into(),
|
os: "emscripten".into(),
|
||||||
|
|
|
@ -7,7 +7,7 @@ use super::{
|
||||||
|
|
||||||
use crate::errors;
|
use crate::errors;
|
||||||
use crate::infer::InferCtxt;
|
use crate::infer::InferCtxt;
|
||||||
use crate::traits::{NormalizeExt, ObligationCtxt};
|
use crate::traits::{ImplDerivedObligationCause, NormalizeExt, ObligationCtxt};
|
||||||
|
|
||||||
use hir::def::CtorOf;
|
use hir::def::CtorOf;
|
||||||
use rustc_data_structures::fx::FxHashSet;
|
use rustc_data_structures::fx::FxHashSet;
|
||||||
|
@ -2973,7 +2973,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
| ObligationCauseCode::ObjectTypeBound(..) => {}
|
| ObligationCauseCode::ObjectTypeBound(..) => {}
|
||||||
ObligationCauseCode::RustCall => {
|
ObligationCauseCode::RustCall => {
|
||||||
if let Some(pred) = predicate.to_opt_poly_trait_pred()
|
if let Some(pred) = predicate.to_opt_poly_trait_pred()
|
||||||
&& Some(pred.def_id()) == self.tcx.lang_items().sized_trait()
|
&& Some(pred.def_id()) == tcx.lang_items().sized_trait()
|
||||||
{
|
{
|
||||||
err.note("argument required to be sized due to `extern \"rust-call\"` ABI");
|
err.note("argument required to be sized due to `extern \"rust-call\"` ABI");
|
||||||
}
|
}
|
||||||
|
@ -3022,15 +3022,15 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
let def_id = trait_pred.def_id();
|
let def_id = trait_pred.def_id();
|
||||||
let visible_item = if let Some(local) = def_id.as_local() {
|
let visible_item = if let Some(local) = def_id.as_local() {
|
||||||
// Check for local traits being reachable.
|
// Check for local traits being reachable.
|
||||||
let vis = &self.tcx.resolutions(()).effective_visibilities;
|
let vis = &tcx.resolutions(()).effective_visibilities;
|
||||||
// Account for non-`pub` traits in the root of the local crate.
|
// Account for non-`pub` traits in the root of the local crate.
|
||||||
let is_locally_reachable = self.tcx.parent(def_id).is_crate_root();
|
let is_locally_reachable = tcx.parent(def_id).is_crate_root();
|
||||||
vis.is_reachable(local) || is_locally_reachable
|
vis.is_reachable(local) || is_locally_reachable
|
||||||
} else {
|
} else {
|
||||||
// Check for foreign traits being reachable.
|
// Check for foreign traits being reachable.
|
||||||
self.tcx.visible_parent_map(()).get(&def_id).is_some()
|
tcx.visible_parent_map(()).get(&def_id).is_some()
|
||||||
};
|
};
|
||||||
if Some(def_id) == self.tcx.lang_items().sized_trait()
|
if Some(def_id) == tcx.lang_items().sized_trait()
|
||||||
&& let Some(hir::Node::TraitItem(hir::TraitItem {
|
&& let Some(hir::Node::TraitItem(hir::TraitItem {
|
||||||
ident,
|
ident,
|
||||||
kind: hir::TraitItemKind::Type(bounds, None),
|
kind: hir::TraitItemKind::Type(bounds, None),
|
||||||
|
@ -3039,7 +3039,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
// Do not suggest relaxing if there is an explicit `Sized` obligation.
|
// Do not suggest relaxing if there is an explicit `Sized` obligation.
|
||||||
&& !bounds.iter()
|
&& !bounds.iter()
|
||||||
.filter_map(|bound| bound.trait_ref())
|
.filter_map(|bound| bound.trait_ref())
|
||||||
.any(|tr| tr.trait_def_id() == self.tcx.lang_items().sized_trait())
|
.any(|tr| tr.trait_def_id() == tcx.lang_items().sized_trait())
|
||||||
{
|
{
|
||||||
let (span, separator) = if let [.., last] = bounds {
|
let (span, separator) = if let [.., last] = bounds {
|
||||||
(last.span().shrink_to_hi(), " +")
|
(last.span().shrink_to_hi(), " +")
|
||||||
|
@ -3102,10 +3102,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
}
|
}
|
||||||
ObligationCauseCode::Coercion { source, target } => {
|
ObligationCauseCode::Coercion { source, target } => {
|
||||||
let mut file = None;
|
let mut file = None;
|
||||||
let source =
|
let source = tcx.short_ty_string(self.resolve_vars_if_possible(source), &mut file);
|
||||||
self.tcx.short_ty_string(self.resolve_vars_if_possible(source), &mut file);
|
let target = tcx.short_ty_string(self.resolve_vars_if_possible(target), &mut file);
|
||||||
let target =
|
|
||||||
self.tcx.short_ty_string(self.resolve_vars_if_possible(target), &mut file);
|
|
||||||
err.note(with_forced_trimmed_paths!(format!(
|
err.note(with_forced_trimmed_paths!(format!(
|
||||||
"required for the cast from `{source}` to `{target}`",
|
"required for the cast from `{source}` to `{target}`",
|
||||||
)));
|
)));
|
||||||
|
@ -3158,7 +3156,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
err.help("see https://doc.rust-lang.org/stable/std/array/fn.from_fn.html for more information");
|
err.help("see https://doc.rust-lang.org/stable/std/array/fn.from_fn.html for more information");
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.tcx.sess.is_nightly_build()
|
if tcx.sess.is_nightly_build()
|
||||||
&& matches!(is_constable, IsConstable::Fn | IsConstable::Ctor)
|
&& matches!(is_constable, IsConstable::Fn | IsConstable::Ctor)
|
||||||
{
|
{
|
||||||
err.help(
|
err.help(
|
||||||
|
@ -3168,8 +3166,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ObligationCauseCode::VariableType(hir_id) => {
|
ObligationCauseCode::VariableType(hir_id) => {
|
||||||
let parent_node = self.tcx.hir().parent_id(hir_id);
|
let parent_node = tcx.hir().parent_id(hir_id);
|
||||||
match self.tcx.opt_hir_node(parent_node) {
|
match tcx.opt_hir_node(parent_node) {
|
||||||
Some(Node::Local(hir::Local { ty: Some(ty), .. })) => {
|
Some(Node::Local(hir::Local { ty: Some(ty), .. })) => {
|
||||||
err.span_suggestion_verbose(
|
err.span_suggestion_verbose(
|
||||||
ty.span.shrink_to_lo(),
|
ty.span.shrink_to_lo(),
|
||||||
|
@ -3207,7 +3205,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
err.note("all local variables must have a statically known size");
|
err.note("all local variables must have a statically known size");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !self.tcx.features().unsized_locals {
|
if !tcx.features().unsized_locals {
|
||||||
err.help("unsized locals are gated as an unstable feature");
|
err.help("unsized locals are gated as an unstable feature");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3289,7 +3287,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
err.note("all function arguments must have a statically known size");
|
err.note("all function arguments must have a statically known size");
|
||||||
}
|
}
|
||||||
if tcx.sess.opts.unstable_features.is_nightly_build()
|
if tcx.sess.opts.unstable_features.is_nightly_build()
|
||||||
&& !self.tcx.features().unsized_fn_params
|
&& !tcx.features().unsized_fn_params
|
||||||
{
|
{
|
||||||
err.help("unsized fn params are gated as an unstable feature");
|
err.help("unsized fn params are gated as an unstable feature");
|
||||||
}
|
}
|
||||||
|
@ -3358,7 +3356,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
"all values captured by value by a closure must have a statically known size",
|
"all values captured by value by a closure must have a statically known size",
|
||||||
);
|
);
|
||||||
let hir::ExprKind::Closure(closure) =
|
let hir::ExprKind::Closure(closure) =
|
||||||
self.tcx.hir_node_by_def_id(closure_def_id).expect_expr().kind
|
tcx.hir_node_by_def_id(closure_def_id).expect_expr().kind
|
||||||
else {
|
else {
|
||||||
bug!("expected closure in SizedClosureCapture obligation");
|
bug!("expected closure in SizedClosureCapture obligation");
|
||||||
};
|
};
|
||||||
|
@ -3369,7 +3367,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ObligationCauseCode::SizedCoroutineInterior(coroutine_def_id) => {
|
ObligationCauseCode::SizedCoroutineInterior(coroutine_def_id) => {
|
||||||
let what = match self.tcx.coroutine_kind(coroutine_def_id) {
|
let what = match tcx.coroutine_kind(coroutine_def_id) {
|
||||||
None
|
None
|
||||||
| Some(hir::CoroutineKind::Coroutine(_))
|
| Some(hir::CoroutineKind::Coroutine(_))
|
||||||
| Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _)) => {
|
| Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _)) => {
|
||||||
|
@ -3420,10 +3418,10 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
'print: {
|
'print: {
|
||||||
if !is_upvar_tys_infer_tuple {
|
if !is_upvar_tys_infer_tuple {
|
||||||
let mut file = None;
|
let mut file = None;
|
||||||
let ty_str = self.tcx.short_ty_string(ty, &mut file);
|
let ty_str = tcx.short_ty_string(ty, &mut file);
|
||||||
let msg = format!("required because it appears within the type `{ty_str}`");
|
let msg = format!("required because it appears within the type `{ty_str}`");
|
||||||
match ty.kind() {
|
match ty.kind() {
|
||||||
ty::Adt(def, _) => match self.tcx.opt_item_ident(def.did()) {
|
ty::Adt(def, _) => match tcx.opt_item_ident(def.did()) {
|
||||||
Some(ident) => err.span_note(ident.span, msg),
|
Some(ident) => err.span_note(ident.span, msg),
|
||||||
None => err.note(msg),
|
None => err.note(msg),
|
||||||
},
|
},
|
||||||
|
@ -3446,7 +3444,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
{
|
{
|
||||||
break 'print;
|
break 'print;
|
||||||
}
|
}
|
||||||
err.span_note(self.tcx.def_span(def_id), msg)
|
err.span_note(tcx.def_span(def_id), msg)
|
||||||
}
|
}
|
||||||
ty::CoroutineWitness(def_id, args) => {
|
ty::CoroutineWitness(def_id, args) => {
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
|
@ -3463,7 +3461,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
err.note(msg.trim_end_matches(", ").to_string())
|
err.note(msg.trim_end_matches(", ").to_string())
|
||||||
}
|
}
|
||||||
ty::Coroutine(def_id, _) => {
|
ty::Coroutine(def_id, _) => {
|
||||||
let sp = self.tcx.def_span(def_id);
|
let sp = tcx.def_span(def_id);
|
||||||
|
|
||||||
// Special-case this to say "async block" instead of `[static coroutine]`.
|
// Special-case this to say "async block" instead of `[static coroutine]`.
|
||||||
let kind = tcx.coroutine_kind(def_id).unwrap();
|
let kind = tcx.coroutine_kind(def_id).unwrap();
|
||||||
|
@ -3475,7 +3473,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
ty::Closure(def_id, _) => err.span_note(
|
ty::Closure(def_id, _) => err.span_note(
|
||||||
self.tcx.def_span(def_id),
|
tcx.def_span(def_id),
|
||||||
"required because it's used within this closure",
|
"required because it's used within this closure",
|
||||||
),
|
),
|
||||||
ty::Str => err.note("`str` is considered to contain a `[u8]` slice for auto trait purposes"),
|
ty::Str => err.note("`str` is considered to contain a `[u8]` slice for auto trait purposes"),
|
||||||
|
@ -3519,14 +3517,12 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
self.resolve_vars_if_possible(data.derived.parent_trait_pred);
|
self.resolve_vars_if_possible(data.derived.parent_trait_pred);
|
||||||
let parent_def_id = parent_trait_pred.def_id();
|
let parent_def_id = parent_trait_pred.def_id();
|
||||||
let mut file = None;
|
let mut file = None;
|
||||||
let self_ty =
|
let self_ty_str =
|
||||||
self.tcx.short_ty_string(parent_trait_pred.skip_binder().self_ty(), &mut file);
|
tcx.short_ty_string(parent_trait_pred.skip_binder().self_ty(), &mut file);
|
||||||
let msg = format!(
|
let trait_name = parent_trait_pred.print_modifiers_and_trait_path().to_string();
|
||||||
"required for `{self_ty}` to implement `{}`",
|
let msg = format!("required for `{self_ty_str}` to implement `{trait_name}`");
|
||||||
parent_trait_pred.print_modifiers_and_trait_path()
|
|
||||||
);
|
|
||||||
let mut is_auto_trait = false;
|
let mut is_auto_trait = false;
|
||||||
match self.tcx.hir().get_if_local(data.impl_or_alias_def_id) {
|
match tcx.hir().get_if_local(data.impl_or_alias_def_id) {
|
||||||
Some(Node::Item(hir::Item {
|
Some(Node::Item(hir::Item {
|
||||||
kind: hir::ItemKind::Trait(is_auto, ..),
|
kind: hir::ItemKind::Trait(is_auto, ..),
|
||||||
ident,
|
ident,
|
||||||
|
@ -3538,7 +3534,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
err.span_note(ident.span, msg);
|
err.span_note(ident.span, msg);
|
||||||
}
|
}
|
||||||
Some(Node::Item(hir::Item {
|
Some(Node::Item(hir::Item {
|
||||||
kind: hir::ItemKind::Impl(hir::Impl { of_trait, self_ty, .. }),
|
kind: hir::ItemKind::Impl(hir::Impl { of_trait, self_ty, generics, .. }),
|
||||||
..
|
..
|
||||||
})) => {
|
})) => {
|
||||||
let mut spans = Vec::with_capacity(2);
|
let mut spans = Vec::with_capacity(2);
|
||||||
|
@ -3565,6 +3561,15 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
err.span_note(spans, msg);
|
err.span_note(spans, msg);
|
||||||
|
point_at_assoc_type_restriction(
|
||||||
|
tcx,
|
||||||
|
err,
|
||||||
|
&self_ty_str,
|
||||||
|
&trait_name,
|
||||||
|
predicate,
|
||||||
|
&generics,
|
||||||
|
&data,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
err.note(msg);
|
err.note(msg);
|
||||||
|
@ -3618,9 +3623,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
pluralize!(count)
|
pluralize!(count)
|
||||||
));
|
));
|
||||||
let mut file = None;
|
let mut file = None;
|
||||||
let self_ty = self
|
let self_ty =
|
||||||
.tcx
|
tcx.short_ty_string(parent_trait_pred.skip_binder().self_ty(), &mut file);
|
||||||
.short_ty_string(parent_trait_pred.skip_binder().self_ty(), &mut file);
|
|
||||||
err.note(format!(
|
err.note(format!(
|
||||||
"required for `{self_ty}` to implement `{}`",
|
"required for `{self_ty}` to implement `{}`",
|
||||||
parent_trait_pred.print_modifiers_and_trait_path()
|
parent_trait_pred.print_modifiers_and_trait_path()
|
||||||
|
@ -3678,10 +3682,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
multispan.push_span_label(span, "required by this bound");
|
multispan.push_span_label(span, "required by this bound");
|
||||||
err.span_note(
|
err.span_note(
|
||||||
multispan,
|
multispan,
|
||||||
format!(
|
format!("required by a bound on the type alias `{}`", tcx.item_name(def_id)),
|
||||||
"required by a bound on the type alias `{}`",
|
|
||||||
self.infcx.tcx.item_name(def_id)
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
ObligationCauseCode::FunctionArgumentObligation {
|
ObligationCauseCode::FunctionArgumentObligation {
|
||||||
|
@ -3712,25 +3713,23 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
ObligationCauseCode::CompareImplItemObligation { trait_item_def_id, kind, .. } => {
|
ObligationCauseCode::CompareImplItemObligation { trait_item_def_id, kind, .. } => {
|
||||||
let item_name = self.tcx.item_name(trait_item_def_id);
|
let item_name = tcx.item_name(trait_item_def_id);
|
||||||
let msg = format!(
|
let msg = format!(
|
||||||
"the requirement `{predicate}` appears on the `impl`'s {kind} \
|
"the requirement `{predicate}` appears on the `impl`'s {kind} \
|
||||||
`{item_name}` but not on the corresponding trait's {kind}",
|
`{item_name}` but not on the corresponding trait's {kind}",
|
||||||
);
|
);
|
||||||
let sp = self
|
let sp = tcx
|
||||||
.tcx
|
|
||||||
.opt_item_ident(trait_item_def_id)
|
.opt_item_ident(trait_item_def_id)
|
||||||
.map(|i| i.span)
|
.map(|i| i.span)
|
||||||
.unwrap_or_else(|| self.tcx.def_span(trait_item_def_id));
|
.unwrap_or_else(|| tcx.def_span(trait_item_def_id));
|
||||||
let mut assoc_span: MultiSpan = sp.into();
|
let mut assoc_span: MultiSpan = sp.into();
|
||||||
assoc_span.push_span_label(
|
assoc_span.push_span_label(
|
||||||
sp,
|
sp,
|
||||||
format!("this trait's {kind} doesn't have the requirement `{predicate}`"),
|
format!("this trait's {kind} doesn't have the requirement `{predicate}`"),
|
||||||
);
|
);
|
||||||
if let Some(ident) = self
|
if let Some(ident) = tcx
|
||||||
.tcx
|
|
||||||
.opt_associated_item(trait_item_def_id)
|
.opt_associated_item(trait_item_def_id)
|
||||||
.and_then(|i| self.tcx.opt_item_ident(i.container_id(self.tcx)))
|
.and_then(|i| tcx.opt_item_ident(i.container_id(tcx)))
|
||||||
{
|
{
|
||||||
assoc_span.push_span_label(ident.span, "in this trait");
|
assoc_span.push_span_label(ident.span, "in this trait");
|
||||||
}
|
}
|
||||||
|
@ -4820,6 +4819,29 @@ fn hint_missing_borrow<'tcx>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Collect all the paths that reference `Self`.
|
||||||
|
/// Used to suggest replacing associated types with an explicit type in `where` clauses.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct SelfVisitor<'v> {
|
||||||
|
pub paths: Vec<&'v hir::Ty<'v>>,
|
||||||
|
pub name: Option<Symbol>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'v> Visitor<'v> for SelfVisitor<'v> {
|
||||||
|
fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
|
||||||
|
if let hir::TyKind::Path(path) = ty.kind
|
||||||
|
&& let hir::QPath::TypeRelative(inner_ty, segment) = path
|
||||||
|
&& (Some(segment.ident.name) == self.name || self.name.is_none())
|
||||||
|
&& let hir::TyKind::Path(inner_path) = inner_ty.kind
|
||||||
|
&& let hir::QPath::Resolved(None, inner_path) = inner_path
|
||||||
|
&& let Res::SelfTyAlias { .. } = inner_path.res
|
||||||
|
{
|
||||||
|
self.paths.push(ty);
|
||||||
|
}
|
||||||
|
hir::intravisit::walk_ty(self, ty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Collect all the returned expressions within the input expression.
|
/// Collect all the returned expressions within the input expression.
|
||||||
/// Used to point at the return spans when we want to suggest some change to them.
|
/// Used to point at the return spans when we want to suggest some change to them.
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
@ -5064,6 +5086,134 @@ pub fn suggest_desugaring_async_fn_to_impl_future_in_trait<'tcx>(
|
||||||
Some(sugg)
|
Some(sugg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// On `impl` evaluation cycles, look for `Self::AssocTy` restrictions in `where` clauses, explain
|
||||||
|
/// they are not allowed and if possible suggest alternatives.
|
||||||
|
fn point_at_assoc_type_restriction(
|
||||||
|
tcx: TyCtxt<'_>,
|
||||||
|
err: &mut Diagnostic,
|
||||||
|
self_ty_str: &str,
|
||||||
|
trait_name: &str,
|
||||||
|
predicate: ty::Predicate<'_>,
|
||||||
|
generics: &hir::Generics<'_>,
|
||||||
|
data: &ImplDerivedObligationCause<'_>,
|
||||||
|
) {
|
||||||
|
let ty::PredicateKind::Clause(clause) = predicate.kind().skip_binder() else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let ty::ClauseKind::Projection(proj) = clause else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let name = tcx.item_name(proj.projection_ty.def_id);
|
||||||
|
let mut predicates = generics.predicates.iter().peekable();
|
||||||
|
let mut prev: Option<&hir::WhereBoundPredicate<'_>> = None;
|
||||||
|
while let Some(pred) = predicates.next() {
|
||||||
|
let hir::WherePredicate::BoundPredicate(pred) = pred else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
let mut bounds = pred.bounds.iter().peekable();
|
||||||
|
while let Some(bound) = bounds.next() {
|
||||||
|
let Some(trait_ref) = bound.trait_ref() else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
if bound.span() != data.span {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if let hir::TyKind::Path(path) = pred.bounded_ty.kind
|
||||||
|
&& let hir::QPath::TypeRelative(ty, segment) = path
|
||||||
|
&& segment.ident.name == name
|
||||||
|
&& let hir::TyKind::Path(inner_path) = ty.kind
|
||||||
|
&& let hir::QPath::Resolved(None, inner_path) = inner_path
|
||||||
|
&& let Res::SelfTyAlias { .. } = inner_path.res
|
||||||
|
{
|
||||||
|
// The following block is to determine the right span to delete for this bound
|
||||||
|
// that will leave valid code after the suggestion is applied.
|
||||||
|
let span = if pred.origin == hir::PredicateOrigin::WhereClause
|
||||||
|
&& generics
|
||||||
|
.predicates
|
||||||
|
.iter()
|
||||||
|
.filter(|p| {
|
||||||
|
matches!(
|
||||||
|
p,
|
||||||
|
hir::WherePredicate::BoundPredicate(p)
|
||||||
|
if hir::PredicateOrigin::WhereClause == p.origin
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.count()
|
||||||
|
== 1
|
||||||
|
{
|
||||||
|
// There's only one `where` bound, that needs to be removed. Remove the whole
|
||||||
|
// `where` clause.
|
||||||
|
generics.where_clause_span
|
||||||
|
} else if let Some(hir::WherePredicate::BoundPredicate(next)) = predicates.peek()
|
||||||
|
&& pred.origin == next.origin
|
||||||
|
{
|
||||||
|
// There's another bound, include the comma for the current one.
|
||||||
|
pred.span.until(next.span)
|
||||||
|
} else if let Some(prev) = prev
|
||||||
|
&& pred.origin == prev.origin
|
||||||
|
{
|
||||||
|
// Last bound, try to remove the previous comma.
|
||||||
|
prev.span.shrink_to_hi().to(pred.span)
|
||||||
|
} else if pred.origin == hir::PredicateOrigin::WhereClause {
|
||||||
|
pred.span.with_hi(generics.where_clause_span.hi())
|
||||||
|
} else {
|
||||||
|
pred.span
|
||||||
|
};
|
||||||
|
|
||||||
|
err.span_suggestion_verbose(
|
||||||
|
span,
|
||||||
|
"associated type for the current `impl` cannot be restricted in `where` \
|
||||||
|
clauses, remove this bound",
|
||||||
|
"",
|
||||||
|
Applicability::MaybeIncorrect,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if let Some(new) =
|
||||||
|
tcx.associated_items(data.impl_or_alias_def_id).find_by_name_and_kind(
|
||||||
|
tcx,
|
||||||
|
Ident::with_dummy_span(name),
|
||||||
|
ty::AssocKind::Type,
|
||||||
|
data.impl_or_alias_def_id,
|
||||||
|
)
|
||||||
|
{
|
||||||
|
// The associated type is specified in the `impl` we're
|
||||||
|
// looking at. Point at it.
|
||||||
|
let span = tcx.def_span(new.def_id);
|
||||||
|
err.span_label(
|
||||||
|
span,
|
||||||
|
format!(
|
||||||
|
"associated type `<{self_ty_str} as {trait_name}>::{name}` is specified \
|
||||||
|
here",
|
||||||
|
),
|
||||||
|
);
|
||||||
|
// Search for the associated type `Self::{name}`, get
|
||||||
|
// its type and suggest replacing the bound with it.
|
||||||
|
let mut visitor = SelfVisitor { paths: vec![], name: Some(name) };
|
||||||
|
visitor.visit_trait_ref(trait_ref);
|
||||||
|
for path in visitor.paths {
|
||||||
|
err.span_suggestion_verbose(
|
||||||
|
path.span,
|
||||||
|
"replace the associated type with the type specified in this `impl`",
|
||||||
|
tcx.type_of(new.def_id).skip_binder().to_string(),
|
||||||
|
Applicability::MachineApplicable,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let mut visitor = SelfVisitor { paths: vec![], name: None };
|
||||||
|
visitor.visit_trait_ref(trait_ref);
|
||||||
|
let span: MultiSpan =
|
||||||
|
visitor.paths.iter().map(|p| p.span).collect::<Vec<Span>>().into();
|
||||||
|
err.span_note(
|
||||||
|
span,
|
||||||
|
"associated types for the current `impl` cannot be restricted in `where` \
|
||||||
|
clauses",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
prev = Some(pred);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn get_deref_type_and_refs(mut ty: Ty<'_>) -> (Ty<'_>, Vec<hir::Mutability>) {
|
fn get_deref_type_and_refs(mut ty: Ty<'_>) -> (Ty<'_>, Vec<hir::Mutability>) {
|
||||||
let mut refs = vec![];
|
let mut refs = vec![];
|
||||||
|
|
||||||
|
|
108
library/core/src/ops/async_function.rs
Normal file
108
library/core/src/ops/async_function.rs
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
use crate::future::Future;
|
||||||
|
use crate::marker::Tuple;
|
||||||
|
|
||||||
|
/// An async-aware version of the [`Fn`](crate::ops::Fn) trait.
|
||||||
|
///
|
||||||
|
/// All `async fn` and functions returning futures implement this trait.
|
||||||
|
#[unstable(feature = "async_fn_traits", issue = "none")]
|
||||||
|
#[rustc_paren_sugar]
|
||||||
|
#[fundamental]
|
||||||
|
#[must_use = "async closures are lazy and do nothing unless called"]
|
||||||
|
#[cfg_attr(not(bootstrap), lang = "async_fn")]
|
||||||
|
pub trait AsyncFn<Args: Tuple>: AsyncFnMut<Args> {
|
||||||
|
/// Future returned by [`AsyncFn::async_call`].
|
||||||
|
#[unstable(feature = "async_fn_traits", issue = "none")]
|
||||||
|
type CallFuture<'a>: Future<Output = Self::Output>
|
||||||
|
where
|
||||||
|
Self: 'a;
|
||||||
|
|
||||||
|
/// Call the [`AsyncFn`], returning a future which may borrow from the called closure.
|
||||||
|
#[unstable(feature = "async_fn_traits", issue = "none")]
|
||||||
|
extern "rust-call" fn async_call(&self, args: Args) -> Self::CallFuture<'_>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An async-aware version of the [`FnMut`](crate::ops::FnMut) trait.
|
||||||
|
///
|
||||||
|
/// All `async fn` and functions returning futures implement this trait.
|
||||||
|
#[unstable(feature = "async_fn_traits", issue = "none")]
|
||||||
|
#[rustc_paren_sugar]
|
||||||
|
#[fundamental]
|
||||||
|
#[must_use = "async closures are lazy and do nothing unless called"]
|
||||||
|
#[cfg_attr(not(bootstrap), lang = "async_fn_mut")]
|
||||||
|
pub trait AsyncFnMut<Args: Tuple>: AsyncFnOnce<Args> {
|
||||||
|
/// Future returned by [`AsyncFnMut::async_call_mut`].
|
||||||
|
#[unstable(feature = "async_fn_traits", issue = "none")]
|
||||||
|
type CallMutFuture<'a>: Future<Output = Self::Output>
|
||||||
|
where
|
||||||
|
Self: 'a;
|
||||||
|
|
||||||
|
/// Call the [`AsyncFnMut`], returning a future which may borrow from the called closure.
|
||||||
|
#[unstable(feature = "async_fn_traits", issue = "none")]
|
||||||
|
extern "rust-call" fn async_call_mut(&mut self, args: Args) -> Self::CallMutFuture<'_>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An async-aware version of the [`FnOnce`](crate::ops::FnOnce) trait.
|
||||||
|
///
|
||||||
|
/// All `async fn` and functions returning futures implement this trait.
|
||||||
|
#[unstable(feature = "async_fn_traits", issue = "none")]
|
||||||
|
#[rustc_paren_sugar]
|
||||||
|
#[fundamental]
|
||||||
|
#[must_use = "async closures are lazy and do nothing unless called"]
|
||||||
|
#[cfg_attr(not(bootstrap), lang = "async_fn_once")]
|
||||||
|
pub trait AsyncFnOnce<Args: Tuple> {
|
||||||
|
/// Future returned by [`AsyncFnOnce::async_call_once`].
|
||||||
|
#[unstable(feature = "async_fn_traits", issue = "none")]
|
||||||
|
type CallOnceFuture: Future<Output = Self::Output>;
|
||||||
|
|
||||||
|
/// Output type of the called closure's future.
|
||||||
|
#[unstable(feature = "async_fn_traits", issue = "none")]
|
||||||
|
type Output;
|
||||||
|
|
||||||
|
/// Call the [`AsyncFnOnce`], returning a future which may move out of the called closure.
|
||||||
|
#[unstable(feature = "async_fn_traits", issue = "none")]
|
||||||
|
extern "rust-call" fn async_call_once(self, args: Args) -> Self::CallOnceFuture;
|
||||||
|
}
|
||||||
|
|
||||||
|
mod impls {
|
||||||
|
use super::{AsyncFn, AsyncFnMut, AsyncFnOnce};
|
||||||
|
use crate::future::Future;
|
||||||
|
use crate::marker::Tuple;
|
||||||
|
|
||||||
|
#[unstable(feature = "async_fn_traits", issue = "none")]
|
||||||
|
impl<F: Fn<A>, A: Tuple> AsyncFn<A> for F
|
||||||
|
where
|
||||||
|
<F as FnOnce<A>>::Output: Future,
|
||||||
|
{
|
||||||
|
type CallFuture<'a> = <F as FnOnce<A>>::Output where Self: 'a;
|
||||||
|
|
||||||
|
extern "rust-call" fn async_call(&self, args: A) -> Self::CallFuture<'_> {
|
||||||
|
self.call(args)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unstable(feature = "async_fn_traits", issue = "none")]
|
||||||
|
impl<F: FnMut<A>, A: Tuple> AsyncFnMut<A> for F
|
||||||
|
where
|
||||||
|
<F as FnOnce<A>>::Output: Future,
|
||||||
|
{
|
||||||
|
type CallMutFuture<'a> = <F as FnOnce<A>>::Output where Self: 'a;
|
||||||
|
|
||||||
|
extern "rust-call" fn async_call_mut(&mut self, args: A) -> Self::CallMutFuture<'_> {
|
||||||
|
self.call_mut(args)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unstable(feature = "async_fn_traits", issue = "none")]
|
||||||
|
impl<F: FnOnce<A>, A: Tuple> AsyncFnOnce<A> for F
|
||||||
|
where
|
||||||
|
<F as FnOnce<A>>::Output: Future,
|
||||||
|
{
|
||||||
|
type CallOnceFuture = <F as FnOnce<A>>::Output;
|
||||||
|
|
||||||
|
type Output = <<F as FnOnce<A>>::Output as Future>::Output;
|
||||||
|
|
||||||
|
extern "rust-call" fn async_call_once(self, args: A) -> Self::CallOnceFuture {
|
||||||
|
self.call_once(args)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -139,6 +139,7 @@
|
||||||
#![stable(feature = "rust1", since = "1.0.0")]
|
#![stable(feature = "rust1", since = "1.0.0")]
|
||||||
|
|
||||||
mod arith;
|
mod arith;
|
||||||
|
mod async_function;
|
||||||
mod bit;
|
mod bit;
|
||||||
mod control_flow;
|
mod control_flow;
|
||||||
mod coroutine;
|
mod coroutine;
|
||||||
|
@ -173,6 +174,9 @@ pub use self::drop::Drop;
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub use self::function::{Fn, FnMut, FnOnce};
|
pub use self::function::{Fn, FnMut, FnOnce};
|
||||||
|
|
||||||
|
#[unstable(feature = "async_fn_traits", issue = "none")]
|
||||||
|
pub use self::async_function::{AsyncFn, AsyncFnMut, AsyncFnOnce};
|
||||||
|
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub use self::index::{Index, IndexMut};
|
pub use self::index::{Index, IndexMut};
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,5 @@ fn foo<A: TraitWAssocConst<A=32>>() { //~ ERROR E0658
|
||||||
|
|
||||||
fn main<A: TraitWAssocConst<A=32>>() {
|
fn main<A: TraitWAssocConst<A=32>>() {
|
||||||
//~^ ERROR E0658
|
//~^ ERROR E0658
|
||||||
//~| ERROR E0131
|
|
||||||
foo::<Demo>();
|
foo::<Demo>();
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,13 +43,7 @@ LL | impl TraitWAssocConst for impl Demo {
|
||||||
|
|
|
|
||||||
= note: `impl Trait` is only allowed in arguments and return types of functions and methods
|
= note: `impl Trait` is only allowed in arguments and return types of functions and methods
|
||||||
|
|
||||||
error[E0131]: `main` function is not allowed to have generic parameters
|
error: aborting due to 5 previous errors
|
||||||
--> $DIR/issue-105330.rs:15:8
|
|
||||||
|
|
|
||||||
LL | fn main<A: TraitWAssocConst<A=32>>() {
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `main` cannot have generic parameters
|
|
||||||
|
|
||||||
error: aborting due to 6 previous errors
|
Some errors have detailed explanations: E0404, E0562, E0658.
|
||||||
|
For more information about an error, try `rustc --explain E0404`.
|
||||||
Some errors have detailed explanations: E0131, E0404, E0562, E0658.
|
|
||||||
For more information about an error, try `rustc --explain E0131`.
|
|
||||||
|
|
|
@ -7,6 +7,9 @@ LL | | where
|
||||||
LL | | Self::A: Baz,
|
LL | | Self::A: Baz,
|
||||||
LL | | Self::B: Fiz,
|
LL | | Self::B: Fiz,
|
||||||
| |_________________^
|
| |_________________^
|
||||||
|
LL | {
|
||||||
|
LL | type A = ();
|
||||||
|
| ------ associated type `<(T,) as Grault>::A` is specified here
|
||||||
|
|
|
|
||||||
note: required for `(T,)` to implement `Grault`
|
note: required for `(T,)` to implement `Grault`
|
||||||
--> $DIR/impl-wf-cycle-1.rs:15:17
|
--> $DIR/impl-wf-cycle-1.rs:15:17
|
||||||
|
@ -18,6 +21,10 @@ LL | Self::A: Baz,
|
||||||
| --- unsatisfied trait bound introduced here
|
| --- unsatisfied trait bound introduced here
|
||||||
= note: 1 redundant requirement hidden
|
= note: 1 redundant requirement hidden
|
||||||
= note: required for `(T,)` to implement `Grault`
|
= note: required for `(T,)` to implement `Grault`
|
||||||
|
help: associated type for the current `impl` cannot be restricted in `where` clauses, remove this bound
|
||||||
|
|
|
||||||
|
LL - Self::A: Baz,
|
||||||
|
|
|
||||||
|
|
||||||
error: aborting due to 1 previous error
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,9 @@ LL | |
|
||||||
LL | | where
|
LL | | where
|
||||||
LL | | Self::A: Copy,
|
LL | | Self::A: Copy,
|
||||||
| |__________________^
|
| |__________________^
|
||||||
|
LL | {
|
||||||
|
LL | type A = ();
|
||||||
|
| ------ associated type `<(T,) as Grault>::A` is specified here
|
||||||
|
|
|
|
||||||
note: required for `(T,)` to implement `Grault`
|
note: required for `(T,)` to implement `Grault`
|
||||||
--> $DIR/impl-wf-cycle-2.rs:7:17
|
--> $DIR/impl-wf-cycle-2.rs:7:17
|
||||||
|
@ -15,6 +18,11 @@ LL | impl<T: Grault> Grault for (T,)
|
||||||
...
|
...
|
||||||
LL | Self::A: Copy,
|
LL | Self::A: Copy,
|
||||||
| ---- unsatisfied trait bound introduced here
|
| ---- unsatisfied trait bound introduced here
|
||||||
|
help: associated type for the current `impl` cannot be restricted in `where` clauses, remove this bound
|
||||||
|
|
|
||||||
|
LL - where
|
||||||
|
LL - Self::A: Copy,
|
||||||
|
|
|
||||||
|
|
||||||
error: aborting due to 1 previous error
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
|
13
tests/ui/associated-types/impl-wf-cycle-3.rs
Normal file
13
tests/ui/associated-types/impl-wf-cycle-3.rs
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
trait A<T> {}
|
||||||
|
|
||||||
|
trait B {
|
||||||
|
type Type;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> B for T //~ ERROR overflow evaluating the requirement
|
||||||
|
where
|
||||||
|
T: A<Self::Type>,
|
||||||
|
{
|
||||||
|
type Type = bool;
|
||||||
|
}
|
||||||
|
fn main() {}
|
27
tests/ui/associated-types/impl-wf-cycle-3.stderr
Normal file
27
tests/ui/associated-types/impl-wf-cycle-3.stderr
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
error[E0275]: overflow evaluating the requirement `<T as B>::Type == <T as B>::Type`
|
||||||
|
--> $DIR/impl-wf-cycle-3.rs:7:1
|
||||||
|
|
|
||||||
|
LL | / impl<T> B for T
|
||||||
|
LL | | where
|
||||||
|
LL | | T: A<Self::Type>,
|
||||||
|
| |_____________________^
|
||||||
|
LL | {
|
||||||
|
LL | type Type = bool;
|
||||||
|
| --------- associated type `<T as B>::Type` is specified here
|
||||||
|
|
|
||||||
|
note: required for `T` to implement `B`
|
||||||
|
--> $DIR/impl-wf-cycle-3.rs:7:9
|
||||||
|
|
|
||||||
|
LL | impl<T> B for T
|
||||||
|
| ^ ^
|
||||||
|
LL | where
|
||||||
|
LL | T: A<Self::Type>,
|
||||||
|
| ------------- unsatisfied trait bound introduced here
|
||||||
|
help: replace the associated type with the type specified in this `impl`
|
||||||
|
|
|
||||||
|
LL | T: A<bool>,
|
||||||
|
| ~~~~
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0275`.
|
15
tests/ui/associated-types/impl-wf-cycle-4.rs
Normal file
15
tests/ui/associated-types/impl-wf-cycle-4.rs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
trait Filter {
|
||||||
|
type ToMatch;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Filter for T //~ ERROR overflow evaluating the requirement
|
||||||
|
where
|
||||||
|
T: Fn(Self::ToMatch),
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
struct JustFilter<F: Filter> {
|
||||||
|
filter: F,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
25
tests/ui/associated-types/impl-wf-cycle-4.stderr
Normal file
25
tests/ui/associated-types/impl-wf-cycle-4.stderr
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
error[E0275]: overflow evaluating the requirement `<T as Filter>::ToMatch == <T as Filter>::ToMatch`
|
||||||
|
--> $DIR/impl-wf-cycle-4.rs:5:1
|
||||||
|
|
|
||||||
|
LL | / impl<T> Filter for T
|
||||||
|
LL | | where
|
||||||
|
LL | | T: Fn(Self::ToMatch),
|
||||||
|
| |_________________________^
|
||||||
|
|
|
||||||
|
note: required for `T` to implement `Filter`
|
||||||
|
--> $DIR/impl-wf-cycle-4.rs:5:9
|
||||||
|
|
|
||||||
|
LL | impl<T> Filter for T
|
||||||
|
| ^^^^^^ ^
|
||||||
|
LL | where
|
||||||
|
LL | T: Fn(Self::ToMatch),
|
||||||
|
| ----------------- unsatisfied trait bound introduced here
|
||||||
|
note: associated types for the current `impl` cannot be restricted in `where` clauses
|
||||||
|
--> $DIR/impl-wf-cycle-4.rs:7:11
|
||||||
|
|
|
||||||
|
LL | T: Fn(Self::ToMatch),
|
||||||
|
| ^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0275`.
|
31
tests/ui/associated-types/impl-wf-cycle-5.fixed
Normal file
31
tests/ui/associated-types/impl-wf-cycle-5.fixed
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
// run-rustfix
|
||||||
|
|
||||||
|
trait Baz {}
|
||||||
|
impl Baz for () {}
|
||||||
|
impl<T> Baz for (T,) {}
|
||||||
|
|
||||||
|
trait Fiz {}
|
||||||
|
impl Fiz for bool {}
|
||||||
|
|
||||||
|
trait Grault {
|
||||||
|
type A;
|
||||||
|
type B;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Grault for () {
|
||||||
|
type A = ();
|
||||||
|
type B = bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Grault for (T,)
|
||||||
|
//~^ ERROR overflow evaluating the requirement `<(T,) as Grault>::A == _`
|
||||||
|
where
|
||||||
|
T: Grault,
|
||||||
|
{
|
||||||
|
type A = ();
|
||||||
|
type B = bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let _: <((),) as Grault>::A = ();
|
||||||
|
}
|
32
tests/ui/associated-types/impl-wf-cycle-5.rs
Normal file
32
tests/ui/associated-types/impl-wf-cycle-5.rs
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
// run-rustfix
|
||||||
|
|
||||||
|
trait Baz {}
|
||||||
|
impl Baz for () {}
|
||||||
|
impl<T> Baz for (T,) {}
|
||||||
|
|
||||||
|
trait Fiz {}
|
||||||
|
impl Fiz for bool {}
|
||||||
|
|
||||||
|
trait Grault {
|
||||||
|
type A;
|
||||||
|
type B;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Grault for () {
|
||||||
|
type A = ();
|
||||||
|
type B = bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Grault for (T,)
|
||||||
|
//~^ ERROR overflow evaluating the requirement `<(T,) as Grault>::A == _`
|
||||||
|
where
|
||||||
|
T: Grault,
|
||||||
|
Self::A: Baz,
|
||||||
|
{
|
||||||
|
type A = ();
|
||||||
|
type B = bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let _: <((),) as Grault>::A = ();
|
||||||
|
}
|
31
tests/ui/associated-types/impl-wf-cycle-5.stderr
Normal file
31
tests/ui/associated-types/impl-wf-cycle-5.stderr
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
error[E0275]: overflow evaluating the requirement `<(T,) as Grault>::A == _`
|
||||||
|
--> $DIR/impl-wf-cycle-5.rs:20:1
|
||||||
|
|
|
||||||
|
LL | / impl<T> Grault for (T,)
|
||||||
|
LL | |
|
||||||
|
LL | | where
|
||||||
|
LL | | T: Grault,
|
||||||
|
LL | | Self::A: Baz,
|
||||||
|
| |_________________^
|
||||||
|
LL | {
|
||||||
|
LL | type A = ();
|
||||||
|
| ------ associated type `<(T,) as Grault>::A` is specified here
|
||||||
|
|
|
||||||
|
note: required for `(T,)` to implement `Grault`
|
||||||
|
--> $DIR/impl-wf-cycle-5.rs:20:9
|
||||||
|
|
|
||||||
|
LL | impl<T> Grault for (T,)
|
||||||
|
| ^^^^^^ ^^^^
|
||||||
|
...
|
||||||
|
LL | Self::A: Baz,
|
||||||
|
| --- unsatisfied trait bound introduced here
|
||||||
|
help: associated type for the current `impl` cannot be restricted in `where` clauses, remove this bound
|
||||||
|
|
|
||||||
|
LL - T: Grault,
|
||||||
|
LL - Self::A: Baz,
|
||||||
|
LL + T: Grault,
|
||||||
|
|
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0275`.
|
30
tests/ui/associated-types/impl-wf-cycle-6.fixed
Normal file
30
tests/ui/associated-types/impl-wf-cycle-6.fixed
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
// run-rustfix
|
||||||
|
|
||||||
|
trait Baz {}
|
||||||
|
impl Baz for () {}
|
||||||
|
impl<T> Baz for (T,) {}
|
||||||
|
|
||||||
|
trait Fiz {}
|
||||||
|
impl Fiz for bool {}
|
||||||
|
|
||||||
|
trait Grault {
|
||||||
|
type A;
|
||||||
|
type B;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Grault for () {
|
||||||
|
type A = ();
|
||||||
|
type B = bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Grault> Grault for (T,)
|
||||||
|
//~^ ERROR overflow evaluating the requirement `<(T,) as Grault>::A == _`
|
||||||
|
|
||||||
|
{
|
||||||
|
type A = ();
|
||||||
|
type B = bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let _: <((),) as Grault>::A = ();
|
||||||
|
}
|
31
tests/ui/associated-types/impl-wf-cycle-6.rs
Normal file
31
tests/ui/associated-types/impl-wf-cycle-6.rs
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
// run-rustfix
|
||||||
|
|
||||||
|
trait Baz {}
|
||||||
|
impl Baz for () {}
|
||||||
|
impl<T> Baz for (T,) {}
|
||||||
|
|
||||||
|
trait Fiz {}
|
||||||
|
impl Fiz for bool {}
|
||||||
|
|
||||||
|
trait Grault {
|
||||||
|
type A;
|
||||||
|
type B;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Grault for () {
|
||||||
|
type A = ();
|
||||||
|
type B = bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Grault> Grault for (T,)
|
||||||
|
//~^ ERROR overflow evaluating the requirement `<(T,) as Grault>::A == _`
|
||||||
|
where
|
||||||
|
Self::A: Baz,
|
||||||
|
{
|
||||||
|
type A = ();
|
||||||
|
type B = bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let _: <((),) as Grault>::A = ();
|
||||||
|
}
|
29
tests/ui/associated-types/impl-wf-cycle-6.stderr
Normal file
29
tests/ui/associated-types/impl-wf-cycle-6.stderr
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
error[E0275]: overflow evaluating the requirement `<(T,) as Grault>::A == _`
|
||||||
|
--> $DIR/impl-wf-cycle-6.rs:20:1
|
||||||
|
|
|
||||||
|
LL | / impl<T: Grault> Grault for (T,)
|
||||||
|
LL | |
|
||||||
|
LL | | where
|
||||||
|
LL | | Self::A: Baz,
|
||||||
|
| |_________________^
|
||||||
|
LL | {
|
||||||
|
LL | type A = ();
|
||||||
|
| ------ associated type `<(T,) as Grault>::A` is specified here
|
||||||
|
|
|
||||||
|
note: required for `(T,)` to implement `Grault`
|
||||||
|
--> $DIR/impl-wf-cycle-6.rs:20:17
|
||||||
|
|
|
||||||
|
LL | impl<T: Grault> Grault for (T,)
|
||||||
|
| ^^^^^^ ^^^^
|
||||||
|
...
|
||||||
|
LL | Self::A: Baz,
|
||||||
|
| --- unsatisfied trait bound introduced here
|
||||||
|
help: associated type for the current `impl` cannot be restricted in `where` clauses, remove this bound
|
||||||
|
|
|
||||||
|
LL - where
|
||||||
|
LL - Self::A: Baz,
|
||||||
|
|
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0275`.
|
|
@ -22,7 +22,22 @@ pub trait Column: Expression {}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
//~^ ERROR the trait bound `<Col as Expression>::SqlType: NotNull` is not satisfied
|
//~^ ERROR the trait bound `<Col as Expression>::SqlType: NotNull` is not satisfied
|
||||||
|
//~| ERROR the trait bound `<Col as Expression>::SqlType: NotNull` is not satisfied
|
||||||
|
//~| ERROR the trait bound `<Col as Expression>::SqlType: NotNull` is not satisfied
|
||||||
|
//~| ERROR the trait bound `<Col as Expression>::SqlType: NotNull` is not satisfied
|
||||||
|
//~| ERROR the trait bound `<Col as Expression>::SqlType: NotNull` is not satisfied
|
||||||
|
//~| ERROR the trait bound `<Col as Expression>::SqlType: NotNull` is not satisfied
|
||||||
|
//~| ERROR the trait bound `<Col as Expression>::SqlType: NotNull` is not satisfied
|
||||||
|
//~| ERROR the trait bound `<Col as Expression>::SqlType: NotNull` is not satisfied
|
||||||
|
//~| ERROR the trait bound `<Col as Expression>::SqlType: NotNull` is not satisfied
|
||||||
|
//~| ERROR the trait bound `<Col as Expression>::SqlType: NotNull` is not satisfied
|
||||||
|
//~| ERROR the trait bound `<Col as Expression>::SqlType: NotNull` is not satisfied
|
||||||
|
//~| ERROR the trait bound `<Col as Expression>::SqlType: NotNull` is not satisfied
|
||||||
|
//~| ERROR the trait bound `<Col as Expression>::SqlType: NotNull` is not satisfied
|
||||||
|
//~| ERROR the trait bound `<Col as Expression>::SqlType: NotNull` is not satisfied
|
||||||
pub enum ColumnInsertValue<Col, Expr> where
|
pub enum ColumnInsertValue<Col, Expr> where
|
||||||
|
//~^ ERROR the trait bound `<Col as Expression>::SqlType: NotNull` is not satisfied
|
||||||
|
//~| ERROR the trait bound `<Col as Expression>::SqlType: NotNull` is not satisfied
|
||||||
Col: Column,
|
Col: Column,
|
||||||
Expr: Expression<SqlType=<Col::SqlType as IntoNullable>::Nullable>,
|
Expr: Expression<SqlType=<Col::SqlType as IntoNullable>::Nullable>,
|
||||||
{
|
{
|
||||||
|
|
|
@ -17,6 +17,272 @@ help: consider further restricting the associated type
|
||||||
LL | Expr: Expression<SqlType=<Col::SqlType as IntoNullable>::Nullable>, <Col as Expression>::SqlType: NotNull,
|
LL | Expr: Expression<SqlType=<Col::SqlType as IntoNullable>::Nullable>, <Col as Expression>::SqlType: NotNull,
|
||||||
| +++++++++++++++++++++++++++++++++++++++
|
| +++++++++++++++++++++++++++++++++++++++
|
||||||
|
|
||||||
error: aborting due to 1 previous error
|
error[E0277]: the trait bound `<Col as Expression>::SqlType: NotNull` is not satisfied
|
||||||
|
--> $DIR/issue-38821.rs:38:1
|
||||||
|
|
|
||||||
|
LL | pub enum ColumnInsertValue<Col, Expr> where
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`
|
||||||
|
|
|
||||||
|
note: required for `<Col as Expression>::SqlType` to implement `IntoNullable`
|
||||||
|
--> $DIR/issue-38821.rs:9:18
|
||||||
|
|
|
||||||
|
LL | impl<T: NotNull> IntoNullable for T {
|
||||||
|
| ------- ^^^^^^^^^^^^ ^
|
||||||
|
| |
|
||||||
|
| unsatisfied trait bound introduced here
|
||||||
|
help: consider extending the `where` clause, but there might be an alternative better way to express this requirement
|
||||||
|
|
|
||||||
|
LL | Expr: Expression<SqlType=<Col::SqlType as IntoNullable>::Nullable>, <Col as Expression>::SqlType: NotNull
|
||||||
|
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
error[E0277]: the trait bound `<Col as Expression>::SqlType: NotNull` is not satisfied
|
||||||
|
--> $DIR/issue-38821.rs:38:1
|
||||||
|
|
|
||||||
|
LL | / pub enum ColumnInsertValue<Col, Expr> where
|
||||||
|
LL | |
|
||||||
|
LL | |
|
||||||
|
LL | | Col: Column,
|
||||||
|
... |
|
||||||
|
LL | | Default(Col),
|
||||||
|
LL | | }
|
||||||
|
| |_^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`
|
||||||
|
|
|
||||||
|
note: required for `<Col as Expression>::SqlType` to implement `IntoNullable`
|
||||||
|
--> $DIR/issue-38821.rs:9:18
|
||||||
|
|
|
||||||
|
LL | impl<T: NotNull> IntoNullable for T {
|
||||||
|
| ------- ^^^^^^^^^^^^ ^
|
||||||
|
| |
|
||||||
|
| unsatisfied trait bound introduced here
|
||||||
|
help: consider extending the `where` clause, but there might be an alternative better way to express this requirement
|
||||||
|
|
|
||||||
|
LL | Expr: Expression<SqlType=<Col::SqlType as IntoNullable>::Nullable>, <Col as Expression>::SqlType: NotNull
|
||||||
|
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
error[E0277]: the trait bound `<Col as Expression>::SqlType: NotNull` is not satisfied
|
||||||
|
--> $DIR/issue-38821.rs:23:10
|
||||||
|
|
|
||||||
|
LL | #[derive(Debug, Copy, Clone)]
|
||||||
|
| ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`
|
||||||
|
|
|
||||||
|
note: required for `<Col as Expression>::SqlType` to implement `IntoNullable`
|
||||||
|
--> $DIR/issue-38821.rs:9:18
|
||||||
|
|
|
||||||
|
LL | impl<T: NotNull> IntoNullable for T {
|
||||||
|
| ------- ^^^^^^^^^^^^ ^
|
||||||
|
| |
|
||||||
|
| unsatisfied trait bound introduced here
|
||||||
|
= note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
help: consider further restricting the associated type
|
||||||
|
|
|
||||||
|
LL | Expr: Expression<SqlType=<Col::SqlType as IntoNullable>::Nullable>, <Col as Expression>::SqlType: NotNull,
|
||||||
|
| +++++++++++++++++++++++++++++++++++++++
|
||||||
|
|
||||||
|
error[E0277]: the trait bound `<Col as Expression>::SqlType: NotNull` is not satisfied
|
||||||
|
--> $DIR/issue-38821.rs:23:10
|
||||||
|
|
|
||||||
|
LL | #[derive(Debug, Copy, Clone)]
|
||||||
|
| ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`
|
||||||
|
|
|
||||||
|
note: required for `<Col as Expression>::SqlType` to implement `IntoNullable`
|
||||||
|
--> $DIR/issue-38821.rs:9:18
|
||||||
|
|
|
||||||
|
LL | impl<T: NotNull> IntoNullable for T {
|
||||||
|
| ------- ^^^^^^^^^^^^ ^
|
||||||
|
| |
|
||||||
|
| unsatisfied trait bound introduced here
|
||||||
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||||
|
= note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
help: consider further restricting the associated type
|
||||||
|
|
|
||||||
|
LL | Expr: Expression<SqlType=<Col::SqlType as IntoNullable>::Nullable>, <Col as Expression>::SqlType: NotNull,
|
||||||
|
| +++++++++++++++++++++++++++++++++++++++
|
||||||
|
|
||||||
|
error[E0277]: the trait bound `<Col as Expression>::SqlType: NotNull` is not satisfied
|
||||||
|
--> $DIR/issue-38821.rs:23:10
|
||||||
|
|
|
||||||
|
LL | #[derive(Debug, Copy, Clone)]
|
||||||
|
| ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`
|
||||||
|
|
|
||||||
|
note: required for `<Col as Expression>::SqlType` to implement `IntoNullable`
|
||||||
|
--> $DIR/issue-38821.rs:9:18
|
||||||
|
|
|
||||||
|
LL | impl<T: NotNull> IntoNullable for T {
|
||||||
|
| ------- ^^^^^^^^^^^^ ^
|
||||||
|
| |
|
||||||
|
| unsatisfied trait bound introduced here
|
||||||
|
= note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
|
error[E0277]: the trait bound `<Col as Expression>::SqlType: NotNull` is not satisfied
|
||||||
|
--> $DIR/issue-38821.rs:23:10
|
||||||
|
|
|
||||||
|
LL | #[derive(Debug, Copy, Clone)]
|
||||||
|
| ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`
|
||||||
|
|
|
||||||
|
note: required for `<Col as Expression>::SqlType` to implement `IntoNullable`
|
||||||
|
--> $DIR/issue-38821.rs:9:18
|
||||||
|
|
|
||||||
|
LL | impl<T: NotNull> IntoNullable for T {
|
||||||
|
| ------- ^^^^^^^^^^^^ ^
|
||||||
|
| |
|
||||||
|
| unsatisfied trait bound introduced here
|
||||||
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||||
|
= note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
|
error[E0277]: the trait bound `<Col as Expression>::SqlType: NotNull` is not satisfied
|
||||||
|
--> $DIR/issue-38821.rs:23:17
|
||||||
|
|
|
||||||
|
LL | #[derive(Debug, Copy, Clone)]
|
||||||
|
| ^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`
|
||||||
|
|
|
||||||
|
note: required for `<Col as Expression>::SqlType` to implement `IntoNullable`
|
||||||
|
--> $DIR/issue-38821.rs:9:18
|
||||||
|
|
|
||||||
|
LL | impl<T: NotNull> IntoNullable for T {
|
||||||
|
| ------- ^^^^^^^^^^^^ ^
|
||||||
|
| |
|
||||||
|
| unsatisfied trait bound introduced here
|
||||||
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||||
|
= note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
help: consider further restricting the associated type
|
||||||
|
|
|
||||||
|
LL | Expr: Expression<SqlType=<Col::SqlType as IntoNullable>::Nullable>, <Col as Expression>::SqlType: NotNull,
|
||||||
|
| +++++++++++++++++++++++++++++++++++++++
|
||||||
|
|
||||||
|
error[E0277]: the trait bound `<Col as Expression>::SqlType: NotNull` is not satisfied
|
||||||
|
--> $DIR/issue-38821.rs:23:23
|
||||||
|
|
|
||||||
|
LL | #[derive(Debug, Copy, Clone)]
|
||||||
|
| ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`
|
||||||
|
|
|
||||||
|
note: required for `<Col as Expression>::SqlType` to implement `IntoNullable`
|
||||||
|
--> $DIR/issue-38821.rs:9:18
|
||||||
|
|
|
||||||
|
LL | impl<T: NotNull> IntoNullable for T {
|
||||||
|
| ------- ^^^^^^^^^^^^ ^
|
||||||
|
| |
|
||||||
|
| unsatisfied trait bound introduced here
|
||||||
|
= note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
help: consider further restricting the associated type
|
||||||
|
|
|
||||||
|
LL | Expr: Expression<SqlType=<Col::SqlType as IntoNullable>::Nullable>, <Col as Expression>::SqlType: NotNull,
|
||||||
|
| +++++++++++++++++++++++++++++++++++++++
|
||||||
|
|
||||||
|
error[E0277]: the trait bound `<Col as Expression>::SqlType: NotNull` is not satisfied
|
||||||
|
--> $DIR/issue-38821.rs:23:23
|
||||||
|
|
|
||||||
|
LL | #[derive(Debug, Copy, Clone)]
|
||||||
|
| ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`
|
||||||
|
|
|
||||||
|
note: required for `<Col as Expression>::SqlType` to implement `IntoNullable`
|
||||||
|
--> $DIR/issue-38821.rs:9:18
|
||||||
|
|
|
||||||
|
LL | impl<T: NotNull> IntoNullable for T {
|
||||||
|
| ------- ^^^^^^^^^^^^ ^
|
||||||
|
| |
|
||||||
|
| unsatisfied trait bound introduced here
|
||||||
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||||
|
= note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
help: consider further restricting the associated type
|
||||||
|
|
|
||||||
|
LL | Expr: Expression<SqlType=<Col::SqlType as IntoNullable>::Nullable>, <Col as Expression>::SqlType: NotNull,
|
||||||
|
| +++++++++++++++++++++++++++++++++++++++
|
||||||
|
|
||||||
|
error[E0277]: the trait bound `<Col as Expression>::SqlType: NotNull` is not satisfied
|
||||||
|
--> $DIR/issue-38821.rs:23:23
|
||||||
|
|
|
||||||
|
LL | #[derive(Debug, Copy, Clone)]
|
||||||
|
| ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`
|
||||||
|
|
|
||||||
|
note: required for `<Col as Expression>::SqlType` to implement `IntoNullable`
|
||||||
|
--> $DIR/issue-38821.rs:9:18
|
||||||
|
|
|
||||||
|
LL | impl<T: NotNull> IntoNullable for T {
|
||||||
|
| ------- ^^^^^^^^^^^^ ^
|
||||||
|
| |
|
||||||
|
| unsatisfied trait bound introduced here
|
||||||
|
= note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
|
error[E0277]: the trait bound `<Col as Expression>::SqlType: NotNull` is not satisfied
|
||||||
|
--> $DIR/issue-38821.rs:23:23
|
||||||
|
|
|
||||||
|
LL | #[derive(Debug, Copy, Clone)]
|
||||||
|
| ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`
|
||||||
|
|
|
||||||
|
note: required for `<Col as Expression>::SqlType` to implement `IntoNullable`
|
||||||
|
--> $DIR/issue-38821.rs:9:18
|
||||||
|
|
|
||||||
|
LL | impl<T: NotNull> IntoNullable for T {
|
||||||
|
| ------- ^^^^^^^^^^^^ ^
|
||||||
|
| |
|
||||||
|
| unsatisfied trait bound introduced here
|
||||||
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||||
|
= note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
|
error[E0277]: the trait bound `<Col as Expression>::SqlType: NotNull` is not satisfied
|
||||||
|
--> $DIR/issue-38821.rs:23:10
|
||||||
|
|
|
||||||
|
LL | #[derive(Debug, Copy, Clone)]
|
||||||
|
| ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`
|
||||||
|
|
|
||||||
|
note: required for `<Col as Expression>::SqlType` to implement `IntoNullable`
|
||||||
|
--> $DIR/issue-38821.rs:9:18
|
||||||
|
|
|
||||||
|
LL | impl<T: NotNull> IntoNullable for T {
|
||||||
|
| ------- ^^^^^^^^^^^^ ^
|
||||||
|
| |
|
||||||
|
| unsatisfied trait bound introduced here
|
||||||
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||||
|
= note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
|
error[E0277]: the trait bound `<Col as Expression>::SqlType: NotNull` is not satisfied
|
||||||
|
--> $DIR/issue-38821.rs:23:10
|
||||||
|
|
|
||||||
|
LL | #[derive(Debug, Copy, Clone)]
|
||||||
|
| ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`
|
||||||
|
|
|
||||||
|
note: required for `<Col as Expression>::SqlType` to implement `IntoNullable`
|
||||||
|
--> $DIR/issue-38821.rs:9:18
|
||||||
|
|
|
||||||
|
LL | impl<T: NotNull> IntoNullable for T {
|
||||||
|
| ------- ^^^^^^^^^^^^ ^
|
||||||
|
| |
|
||||||
|
| unsatisfied trait bound introduced here
|
||||||
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||||
|
= note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
|
error[E0277]: the trait bound `<Col as Expression>::SqlType: NotNull` is not satisfied
|
||||||
|
--> $DIR/issue-38821.rs:23:23
|
||||||
|
|
|
||||||
|
LL | #[derive(Debug, Copy, Clone)]
|
||||||
|
| ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`
|
||||||
|
|
|
||||||
|
note: required for `<Col as Expression>::SqlType` to implement `IntoNullable`
|
||||||
|
--> $DIR/issue-38821.rs:9:18
|
||||||
|
|
|
||||||
|
LL | impl<T: NotNull> IntoNullable for T {
|
||||||
|
| ------- ^^^^^^^^^^^^ ^
|
||||||
|
| |
|
||||||
|
| unsatisfied trait bound introduced here
|
||||||
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||||
|
= note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
|
error[E0277]: the trait bound `<Col as Expression>::SqlType: NotNull` is not satisfied
|
||||||
|
--> $DIR/issue-38821.rs:23:23
|
||||||
|
|
|
||||||
|
LL | #[derive(Debug, Copy, Clone)]
|
||||||
|
| ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`
|
||||||
|
|
|
||||||
|
note: required for `<Col as Expression>::SqlType` to implement `IntoNullable`
|
||||||
|
--> $DIR/issue-38821.rs:9:18
|
||||||
|
|
|
||||||
|
LL | impl<T: NotNull> IntoNullable for T {
|
||||||
|
| ------- ^^^^^^^^^^^^ ^
|
||||||
|
| |
|
||||||
|
| unsatisfied trait bound introduced here
|
||||||
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||||
|
= note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
|
error: aborting due to 16 previous errors
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0277`.
|
For more information about this error, try `rustc --explain E0277`.
|
||||||
|
|
16
tests/ui/async-await/async-fn/simple.rs
Normal file
16
tests/ui/async-await/async-fn/simple.rs
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
// edition: 2021
|
||||||
|
// check-pass
|
||||||
|
|
||||||
|
#![feature(async_fn_traits)]
|
||||||
|
|
||||||
|
use std::ops::AsyncFn;
|
||||||
|
|
||||||
|
async fn foo() {}
|
||||||
|
|
||||||
|
async fn call_asyncly(f: impl AsyncFn(i32) -> i32) -> i32 {
|
||||||
|
f(1).await
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let fut = call_asyncly(|x| async move { x + 1 });
|
||||||
|
}
|
|
@ -3,7 +3,7 @@
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::ops::CoerceUnsized;
|
use std::ops::CoerceUnsized;
|
||||||
|
|
||||||
struct Foo<T> {
|
struct Foo<T: ?Sized> {
|
||||||
data: Box<T>,
|
data: Box<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
pub struct Foo {
|
pub struct Foo {
|
||||||
x: [u8; SIZE],
|
x: [u8; SIZE],
|
||||||
//~^ ERROR mismatched types
|
//~^ ERROR mismatched types
|
||||||
|
//~| ERROR mismatched types
|
||||||
}
|
}
|
||||||
|
|
||||||
const SIZE: u32 = 1;
|
const SIZE: u32 = 1;
|
||||||
|
|
|
@ -4,6 +4,14 @@ error[E0308]: mismatched types
|
||||||
LL | x: [u8; SIZE],
|
LL | x: [u8; SIZE],
|
||||||
| ^^^^ expected `usize`, found `u32`
|
| ^^^^ expected `usize`, found `u32`
|
||||||
|
|
||||||
error: aborting due to 1 previous error
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/bad-generic-in-copy-impl.rs:3:13
|
||||||
|
|
|
||||||
|
LL | x: [u8; SIZE],
|
||||||
|
| ^^^^ expected `usize`, found `u32`
|
||||||
|
|
|
||||||
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0308`.
|
For more information about this error, try `rustc --explain E0308`.
|
||||||
|
|
|
@ -191,7 +191,14 @@ error[E0223]: ambiguous associated type
|
||||||
--> $DIR/bad-assoc-ty.rs:33:10
|
--> $DIR/bad-assoc-ty.rs:33:10
|
||||||
|
|
|
|
||||||
LL | type H = Fn(u8) -> (u8)::Output;
|
LL | type H = Fn(u8) -> (u8)::Output;
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<(dyn Fn(u8) -> u8 + 'static) as IntoFuture>::Output`
|
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
help: use fully-qualified syntax
|
||||||
|
|
|
||||||
|
LL | type H = <(dyn Fn(u8) -> u8 + 'static) as AsyncFnOnce>::Output;
|
||||||
|
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
LL | type H = <(dyn Fn(u8) -> u8 + 'static) as IntoFuture>::Output;
|
||||||
|
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
error[E0223]: ambiguous associated type
|
error[E0223]: ambiguous associated type
|
||||||
--> $DIR/bad-assoc-ty.rs:39:19
|
--> $DIR/bad-assoc-ty.rs:39:19
|
||||||
|
|
|
@ -8,6 +8,7 @@ LL | f5.2 = Bar1 {f: 36};
|
||||||
|
|
|
|
||||||
= note: expected trait object `dyn ToBar`
|
= note: expected trait object `dyn ToBar`
|
||||||
found struct `Bar1`
|
found struct `Bar1`
|
||||||
|
= help: `Bar1` implements `ToBar` so you could box the found value and coerce it to the trait object `Box<dyn ToBar>`, you will have to change the expected type as well
|
||||||
|
|
||||||
error[E0277]: the size for values of type `dyn ToBar` cannot be known at compilation time
|
error[E0277]: the size for values of type `dyn ToBar` cannot be known at compilation time
|
||||||
--> $DIR/dst-bad-assign-3.rs:33:5
|
--> $DIR/dst-bad-assign-3.rs:33:5
|
||||||
|
|
|
@ -8,6 +8,7 @@ LL | f5.ptr = Bar1 {f: 36};
|
||||||
|
|
|
|
||||||
= note: expected trait object `dyn ToBar`
|
= note: expected trait object `dyn ToBar`
|
||||||
found struct `Bar1`
|
found struct `Bar1`
|
||||||
|
= help: `Bar1` implements `ToBar` so you could box the found value and coerce it to the trait object `Box<dyn ToBar>`, you will have to change the expected type as well
|
||||||
|
|
||||||
error[E0277]: the size for values of type `dyn ToBar` cannot be known at compilation time
|
error[E0277]: the size for values of type `dyn ToBar` cannot be known at compilation time
|
||||||
--> $DIR/dst-bad-assign.rs:35:5
|
--> $DIR/dst-bad-assign.rs:35:5
|
||||||
|
|
|
@ -8,6 +8,7 @@ LL | dyn_star_foreign::require_dyn_star_display(1usize);
|
||||||
|
|
|
|
||||||
= note: expected trait object `(dyn* std::fmt::Display + 'static)`
|
= note: expected trait object `(dyn* std::fmt::Display + 'static)`
|
||||||
found type `usize`
|
found type `usize`
|
||||||
|
= help: `usize` implements `Display`, `#[feature(dyn_star)]` is likely not enabled; that feature it is currently incomplete
|
||||||
note: function defined here
|
note: function defined here
|
||||||
--> $DIR/auxiliary/dyn-star-foreign.rs:6:8
|
--> $DIR/auxiliary/dyn-star-foreign.rs:6:8
|
||||||
|
|
|
|
||||||
|
|
|
@ -3,6 +3,7 @@ use std::collections::BTreeSet;
|
||||||
#[derive(Hash)]
|
#[derive(Hash)]
|
||||||
pub enum ElemDerived {
|
pub enum ElemDerived {
|
||||||
//~^ ERROR recursive type `ElemDerived` has infinite size
|
//~^ ERROR recursive type `ElemDerived` has infinite size
|
||||||
|
//~| ERROR cycle detected
|
||||||
A(ElemDerived)
|
A(ElemDerived)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ error[E0072]: recursive type `ElemDerived` has infinite size
|
||||||
|
|
|
|
||||||
LL | pub enum ElemDerived {
|
LL | pub enum ElemDerived {
|
||||||
| ^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^
|
||||||
LL |
|
...
|
||||||
LL | A(ElemDerived)
|
LL | A(ElemDerived)
|
||||||
| ----------- recursive without indirection
|
| ----------- recursive without indirection
|
||||||
|
|
|
|
||||||
|
@ -12,6 +12,21 @@ help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle
|
||||||
LL | A(Box<ElemDerived>)
|
LL | A(Box<ElemDerived>)
|
||||||
| ++++ +
|
| ++++ +
|
||||||
|
|
||||||
error: aborting due to 1 previous error
|
error[E0391]: cycle detected when computing drop-check constraints for `ElemDerived`
|
||||||
|
--> $DIR/issue-72554.rs:4:1
|
||||||
|
|
|
||||||
|
LL | pub enum ElemDerived {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: ...which immediately requires computing drop-check constraints for `ElemDerived` again
|
||||||
|
note: cycle used when computing drop-check constraints for `Elem`
|
||||||
|
--> $DIR/issue-72554.rs:11:1
|
||||||
|
|
|
||||||
|
LL | pub enum Elem {
|
||||||
|
| ^^^^^^^^^^^^^
|
||||||
|
= note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0072`.
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
Some errors have detailed explanations: E0072, E0391.
|
||||||
|
For more information about an error, try `rustc --explain E0072`.
|
||||||
|
|
|
@ -27,6 +27,7 @@ LL | type VRefCont<'a> = &'a V where Self: 'a;
|
||||||
| ^^^^^
|
| ^^^^^
|
||||||
= note: expected trait object `(dyn RefCont<'_, u8> + 'static)`
|
= note: expected trait object `(dyn RefCont<'_, u8> + 'static)`
|
||||||
found reference `&u8`
|
found reference `&u8`
|
||||||
|
= help: `&u8` implements `RefCont` so you could box the found value and coerce it to the trait object `Box<dyn RefCont>`, you will have to change the expected type as well
|
||||||
= note: required for the cast from `Box<BTreeMap<u8, u8>>` to `Box<dyn MapLike<u8, u8, VRefCont = (dyn RefCont<'_, u8> + 'static)>>`
|
= note: required for the cast from `Box<BTreeMap<u8, u8>>` to `Box<dyn MapLike<u8, u8, VRefCont = (dyn RefCont<'_, u8> + 'static)>>`
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error: aborting due to 2 previous errors
|
||||||
|
|
18
tests/ui/impl-trait/dyn-impl-type-mismatch.rs
Normal file
18
tests/ui/impl-trait/dyn-impl-type-mismatch.rs
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
trait Trait {}
|
||||||
|
struct Struct;
|
||||||
|
impl Trait for Struct {}
|
||||||
|
fn foo() -> impl Trait {
|
||||||
|
Struct
|
||||||
|
}
|
||||||
|
fn main() {
|
||||||
|
let a: Box<dyn Trait> = if true {
|
||||||
|
Box::new(Struct)
|
||||||
|
} else {
|
||||||
|
foo() //~ ERROR E0308
|
||||||
|
};
|
||||||
|
let a: dyn Trait = if true {
|
||||||
|
Struct //~ ERROR E0308
|
||||||
|
} else {
|
||||||
|
foo() //~ ERROR E0308
|
||||||
|
};
|
||||||
|
}
|
43
tests/ui/impl-trait/dyn-impl-type-mismatch.stderr
Normal file
43
tests/ui/impl-trait/dyn-impl-type-mismatch.stderr
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/dyn-impl-type-mismatch.rs:11:9
|
||||||
|
|
|
||||||
|
LL | fn foo() -> impl Trait {
|
||||||
|
| ---------- the found opaque type
|
||||||
|
...
|
||||||
|
LL | foo()
|
||||||
|
| ^^^^^ expected `Box<dyn Trait>`, found opaque type
|
||||||
|
|
|
||||||
|
= note: expected struct `Box<dyn Trait>`
|
||||||
|
found opaque type `impl Trait`
|
||||||
|
= note: for more on the distinction between the stack and the heap, read https://doc.rust-lang.org/book/ch15-01-box.html, https://doc.rust-lang.org/rust-by-example/std/box.html, and https://doc.rust-lang.org/std/boxed/index.html
|
||||||
|
help: store this in the heap by calling `Box::new`
|
||||||
|
|
|
||||||
|
LL | Box::new(foo())
|
||||||
|
| +++++++++ +
|
||||||
|
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/dyn-impl-type-mismatch.rs:14:9
|
||||||
|
|
|
||||||
|
LL | Struct
|
||||||
|
| ^^^^^^ expected `dyn Trait`, found `Struct`
|
||||||
|
|
|
||||||
|
= note: expected trait object `dyn Trait`
|
||||||
|
found struct `Struct`
|
||||||
|
= help: `Struct` implements `Trait` so you could box the found value and coerce it to the trait object `Box<dyn Trait>`, you will have to change the expected type as well
|
||||||
|
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/dyn-impl-type-mismatch.rs:16:9
|
||||||
|
|
|
||||||
|
LL | fn foo() -> impl Trait {
|
||||||
|
| ---------- the found opaque type
|
||||||
|
...
|
||||||
|
LL | foo()
|
||||||
|
| ^^^^^ expected `dyn Trait`, found opaque type
|
||||||
|
|
|
||||||
|
= note: expected trait object `dyn Trait`
|
||||||
|
found opaque type `impl Trait`
|
||||||
|
= help: you can box the `impl Trait` to coerce it to `Box<dyn Trait>`, but you'll have to change the expected type as well
|
||||||
|
|
||||||
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0308`.
|
|
@ -6,6 +6,7 @@ LL | fn fuz() -> (usize, Trait) { (42, Struct) }
|
||||||
|
|
|
|
||||||
= note: expected trait object `(dyn Trait + 'static)`
|
= note: expected trait object `(dyn Trait + 'static)`
|
||||||
found struct `Struct`
|
found struct `Struct`
|
||||||
|
= help: `Struct` implements `Trait` so you could box the found value and coerce it to the trait object `Box<dyn Trait>`, you will have to change the expected type as well
|
||||||
|
|
||||||
error[E0277]: the size for values of type `(dyn Trait + 'static)` cannot be known at compilation time
|
error[E0277]: the size for values of type `(dyn Trait + 'static)` cannot be known at compilation time
|
||||||
--> $DIR/dyn-trait-return-should-be-impl-trait.rs:7:13
|
--> $DIR/dyn-trait-return-should-be-impl-trait.rs:7:13
|
||||||
|
@ -27,6 +28,7 @@ LL | fn bar() -> (usize, dyn Trait) { (42, Struct) }
|
||||||
|
|
|
|
||||||
= note: expected trait object `(dyn Trait + 'static)`
|
= note: expected trait object `(dyn Trait + 'static)`
|
||||||
found struct `Struct`
|
found struct `Struct`
|
||||||
|
= help: `Struct` implements `Trait` so you could box the found value and coerce it to the trait object `Box<dyn Trait>`, you will have to change the expected type as well
|
||||||
|
|
||||||
error[E0277]: the size for values of type `(dyn Trait + 'static)` cannot be known at compilation time
|
error[E0277]: the size for values of type `(dyn Trait + 'static)` cannot be known at compilation time
|
||||||
--> $DIR/dyn-trait-return-should-be-impl-trait.rs:10:13
|
--> $DIR/dyn-trait-return-should-be-impl-trait.rs:10:13
|
||||||
|
|
|
@ -27,6 +27,7 @@ LL | 1.query::<dyn ToString>("")
|
||||||
|
|
|
|
||||||
= note: expected trait object `dyn ToString`
|
= note: expected trait object `dyn ToString`
|
||||||
found reference `&'static str`
|
found reference `&'static str`
|
||||||
|
= help: `&'static str` implements `ToString` so you could box the found value and coerce it to the trait object `Box<dyn ToString>`, you will have to change the expected type as well
|
||||||
note: method defined here
|
note: method defined here
|
||||||
--> $DIR/issue-61525.rs:2:8
|
--> $DIR/issue-61525.rs:2:8
|
||||||
|
|
|
|
||||||
|
|
|
@ -7,16 +7,6 @@ LL | impl<T: Default> A for T {
|
||||||
LL | impl<T: Default + ~const Sup> const A for T {
|
LL | impl<T: Default + ~const Sup> const A for T {
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation
|
||||||
|
|
||||||
error[E0308]: mismatched types
|
error: aborting due to 1 previous error
|
||||||
--> $DIR/specializing-constness-2.rs:27:5
|
|
||||||
|
|
|
||||||
LL | <T as A>::a();
|
|
||||||
| ^^^^^^^^^^^^^ expected `host`, found `true`
|
|
||||||
|
|
|
||||||
= note: expected constant `host`
|
|
||||||
found constant `true`
|
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
For more information about this error, try `rustc --explain E0119`.
|
||||||
|
|
||||||
Some errors have detailed explanations: E0119, E0308.
|
|
||||||
For more information about an error, try `rustc --explain E0119`.
|
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
struct S<const L: usize>;
|
struct S<const L: usize>;
|
||||||
|
|
||||||
impl<const N: i32> Copy for S<N> {}
|
impl<const N: i32> Copy for S<N> {}
|
||||||
//~^ ERROR the constant `N` is not of type `usize`
|
|
||||||
impl<const M: usize> Copy for S<M> {}
|
impl<const M: usize> Copy for S<M> {}
|
||||||
//~^ ERROR: conflicting implementations of trait `Copy` for type `S<_>`
|
//~^ ERROR: conflicting implementations of trait `Copy` for type `S<_>`
|
||||||
|
|
||||||
|
|
|
@ -1,29 +1,11 @@
|
||||||
error[E0119]: conflicting implementations of trait `Copy` for type `S<_>`
|
error[E0119]: conflicting implementations of trait `Copy` for type `S<_>`
|
||||||
--> $DIR/bad-const-wf-doesnt-specialize.rs:10:1
|
--> $DIR/bad-const-wf-doesnt-specialize.rs:9:1
|
||||||
|
|
|
|
||||||
LL | impl<const N: i32> Copy for S<N> {}
|
LL | impl<const N: i32> Copy for S<N> {}
|
||||||
| -------------------------------- first implementation here
|
| -------------------------------- first implementation here
|
||||||
LL |
|
|
||||||
LL | impl<const M: usize> Copy for S<M> {}
|
LL | impl<const M: usize> Copy for S<M> {}
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `S<_>`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `S<_>`
|
||||||
|
|
||||||
error: the constant `N` is not of type `usize`
|
error: aborting due to 1 previous error
|
||||||
--> $DIR/bad-const-wf-doesnt-specialize.rs:8:29
|
|
||||||
|
|
|
||||||
LL | impl<const N: i32> Copy for S<N> {}
|
|
||||||
| ^^^^ expected `usize`, found `i32`
|
|
||||||
|
|
|
||||||
note: required for `S<N>` to implement `Clone`
|
|
||||||
--> $DIR/bad-const-wf-doesnt-specialize.rs:5:10
|
|
||||||
|
|
|
||||||
LL | #[derive(Clone)]
|
|
||||||
| ^^^^^
|
|
||||||
LL | struct S<const L: usize>;
|
|
||||||
| ----- unsatisfied trait bound introduced in this `derive` macro
|
|
||||||
note: required by a bound in `Copy`
|
|
||||||
--> $SRC_DIR/core/src/marker.rs:LL:COL
|
|
||||||
= note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
|
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0119`.
|
For more information about this error, try `rustc --explain E0119`.
|
||||||
|
|
|
@ -198,7 +198,6 @@ trait Qux {
|
||||||
//~^ ERROR the placeholder `_` is not allowed within types on item signatures for associated types
|
//~^ ERROR the placeholder `_` is not allowed within types on item signatures for associated types
|
||||||
}
|
}
|
||||||
impl Qux for Struct {
|
impl Qux for Struct {
|
||||||
//~^ ERROR: not all trait items implemented, missing: `F`
|
|
||||||
type A = _;
|
type A = _;
|
||||||
//~^ ERROR the placeholder `_` is not allowed within types on item signatures for associated types
|
//~^ ERROR the placeholder `_` is not allowed within types on item signatures for associated types
|
||||||
type B = _;
|
type B = _;
|
||||||
|
|
|
@ -29,7 +29,7 @@ LL | struct BadStruct2<_, T>(_, T);
|
||||||
| ^ expected identifier, found reserved identifier
|
| ^ expected identifier, found reserved identifier
|
||||||
|
|
||||||
error: associated constant in `impl` without body
|
error: associated constant in `impl` without body
|
||||||
--> $DIR/typeck_type_placeholder_item.rs:206:5
|
--> $DIR/typeck_type_placeholder_item.rs:205:5
|
||||||
|
|
|
|
||||||
LL | const C: _;
|
LL | const C: _;
|
||||||
| ^^^^^^^^^^-
|
| ^^^^^^^^^^-
|
||||||
|
@ -411,7 +411,7 @@ LL | type Y = impl Trait<_>;
|
||||||
| ^ not allowed in type signatures
|
| ^ not allowed in type signatures
|
||||||
|
|
||||||
error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
|
error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
|
||||||
--> $DIR/typeck_type_placeholder_item.rs:217:31
|
--> $DIR/typeck_type_placeholder_item.rs:216:31
|
||||||
|
|
|
|
||||||
LL | fn value() -> Option<&'static _> {
|
LL | fn value() -> Option<&'static _> {
|
||||||
| ----------------^-
|
| ----------------^-
|
||||||
|
@ -420,7 +420,7 @@ LL | fn value() -> Option<&'static _> {
|
||||||
| help: replace with the correct return type: `Option<&'static u8>`
|
| help: replace with the correct return type: `Option<&'static u8>`
|
||||||
|
|
||||||
error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants
|
error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants
|
||||||
--> $DIR/typeck_type_placeholder_item.rs:222:10
|
--> $DIR/typeck_type_placeholder_item.rs:221:10
|
||||||
|
|
|
|
||||||
LL | const _: Option<_> = map(value);
|
LL | const _: Option<_> = map(value);
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
|
@ -429,7 +429,7 @@ LL | const _: Option<_> = map(value);
|
||||||
| help: replace with the correct type: `Option<u8>`
|
| help: replace with the correct type: `Option<u8>`
|
||||||
|
|
||||||
error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
|
error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
|
||||||
--> $DIR/typeck_type_placeholder_item.rs:225:31
|
--> $DIR/typeck_type_placeholder_item.rs:224:31
|
||||||
|
|
|
|
||||||
LL | fn evens_squared(n: usize) -> _ {
|
LL | fn evens_squared(n: usize) -> _ {
|
||||||
| ^
|
| ^
|
||||||
|
@ -438,13 +438,13 @@ LL | fn evens_squared(n: usize) -> _ {
|
||||||
| help: replace with an appropriate return type: `impl Iterator<Item = usize>`
|
| help: replace with an appropriate return type: `impl Iterator<Item = usize>`
|
||||||
|
|
||||||
error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants
|
error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants
|
||||||
--> $DIR/typeck_type_placeholder_item.rs:230:10
|
--> $DIR/typeck_type_placeholder_item.rs:229:10
|
||||||
|
|
|
|
||||||
LL | const _: _ = (1..10).filter(|x| x % 2 == 0).map(|x| x * x);
|
LL | const _: _ = (1..10).filter(|x| x % 2 == 0).map(|x| x * x);
|
||||||
| ^ not allowed in type signatures
|
| ^ not allowed in type signatures
|
||||||
|
|
|
|
||||||
note: however, the inferred type `Map<Filter<Range<i32>, {closure@typeck_type_placeholder_item.rs:230:29}>, {closure@typeck_type_placeholder_item.rs:230:49}>` cannot be named
|
note: however, the inferred type `Map<Filter<Range<i32>, {closure@typeck_type_placeholder_item.rs:229:29}>, {closure@typeck_type_placeholder_item.rs:229:49}>` cannot be named
|
||||||
--> $DIR/typeck_type_placeholder_item.rs:230:14
|
--> $DIR/typeck_type_placeholder_item.rs:229:14
|
||||||
|
|
|
|
||||||
LL | const _: _ = (1..10).filter(|x| x % 2 == 0).map(|x| x * x);
|
LL | const _: _ = (1..10).filter(|x| x % 2 == 0).map(|x| x * x);
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -631,25 +631,25 @@ LL | fn clone_from(&mut self, other: &FnTest9) { *self = FnTest9; }
|
||||||
| ~~~~~~~~
|
| ~~~~~~~~
|
||||||
|
|
||||||
error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated types
|
error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated types
|
||||||
--> $DIR/typeck_type_placeholder_item.rs:202:14
|
--> $DIR/typeck_type_placeholder_item.rs:201:14
|
||||||
|
|
|
|
||||||
LL | type A = _;
|
LL | type A = _;
|
||||||
| ^ not allowed in type signatures
|
| ^ not allowed in type signatures
|
||||||
|
|
||||||
error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated types
|
error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated types
|
||||||
--> $DIR/typeck_type_placeholder_item.rs:204:14
|
--> $DIR/typeck_type_placeholder_item.rs:203:14
|
||||||
|
|
|
|
||||||
LL | type B = _;
|
LL | type B = _;
|
||||||
| ^ not allowed in type signatures
|
| ^ not allowed in type signatures
|
||||||
|
|
||||||
error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated constants
|
error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated constants
|
||||||
--> $DIR/typeck_type_placeholder_item.rs:206:14
|
--> $DIR/typeck_type_placeholder_item.rs:205:14
|
||||||
|
|
|
|
||||||
LL | const C: _;
|
LL | const C: _;
|
||||||
| ^ not allowed in type signatures
|
| ^ not allowed in type signatures
|
||||||
|
|
||||||
error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated constants
|
error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated constants
|
||||||
--> $DIR/typeck_type_placeholder_item.rs:209:14
|
--> $DIR/typeck_type_placeholder_item.rs:208:14
|
||||||
|
|
|
|
||||||
LL | const D: _ = 42;
|
LL | const D: _ = 42;
|
||||||
| ^
|
| ^
|
||||||
|
@ -657,16 +657,7 @@ LL | const D: _ = 42;
|
||||||
| not allowed in type signatures
|
| not allowed in type signatures
|
||||||
| help: replace with the correct type: `i32`
|
| help: replace with the correct type: `i32`
|
||||||
|
|
||||||
error[E0046]: not all trait items implemented, missing: `F`
|
error: aborting due to 71 previous errors
|
||||||
--> $DIR/typeck_type_placeholder_item.rs:200:1
|
|
||||||
|
|
|
||||||
LL | type F: std::ops::Fn(_);
|
|
||||||
| ----------------------- `F` from trait
|
|
||||||
...
|
|
||||||
LL | impl Qux for Struct {
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^ missing `F` in implementation
|
|
||||||
|
|
||||||
error: aborting due to 72 previous errors
|
Some errors have detailed explanations: E0121, E0282, E0403.
|
||||||
|
For more information about an error, try `rustc --explain E0121`.
|
||||||
Some errors have detailed explanations: E0046, E0121, E0282, E0403.
|
|
||||||
For more information about an error, try `rustc --explain E0046`.
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue