Auto merge of #99047 - matthiaskrgr:rollup-01vn70s, r=matthiaskrgr
Rollup of 6 pull requests Successful merges: - #95635 (sess: stabilize `--terminal-width` as `--diagnostic-width`) - #98718 (Stabilize `into_future`) - #98795 (A few cleanups) - #98798 (Fix caching bug in `download-rustc = true`) - #99019 (Add doc comments in `rustc_middle::mir`) - #99026 (Add test for and fix rust-lang/rust-clippy#9131) Failed merges: - #98957 ( don't allow ZST in ScalarInt ) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
0f97e02bdc
52 changed files with 707 additions and 665 deletions
|
@ -495,8 +495,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
NllRegionVariableOrigin::RootEmptyRegion
|
||||
| NllRegionVariableOrigin::Existential { .. } => {
|
||||
NllRegionVariableOrigin::Existential { .. } => {
|
||||
// For existential, regions, nothing to do.
|
||||
}
|
||||
}
|
||||
|
@ -1410,8 +1409,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
self.check_bound_universal_region(fr, placeholder, errors_buffer);
|
||||
}
|
||||
|
||||
NllRegionVariableOrigin::RootEmptyRegion
|
||||
| NllRegionVariableOrigin::Existential { .. } => {
|
||||
NllRegionVariableOrigin::Existential { .. } => {
|
||||
// nothing to check here
|
||||
}
|
||||
}
|
||||
|
@ -1513,8 +1511,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
self.check_bound_universal_region(fr, placeholder, errors_buffer);
|
||||
}
|
||||
|
||||
NllRegionVariableOrigin::RootEmptyRegion
|
||||
| NllRegionVariableOrigin::Existential { .. } => {
|
||||
NllRegionVariableOrigin::Existential { .. } => {
|
||||
// nothing to check here
|
||||
}
|
||||
}
|
||||
|
@ -1788,9 +1785,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
universe1.cannot_name(placeholder.universe)
|
||||
}
|
||||
|
||||
NllRegionVariableOrigin::RootEmptyRegion
|
||||
| NllRegionVariableOrigin::FreeRegion
|
||||
| NllRegionVariableOrigin::Existential { .. } => false,
|
||||
NllRegionVariableOrigin::FreeRegion | NllRegionVariableOrigin::Existential { .. } => {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2152,8 +2149,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
let blame_source = match from_region_origin {
|
||||
NllRegionVariableOrigin::FreeRegion
|
||||
| NllRegionVariableOrigin::Existential { from_forall: false } => true,
|
||||
NllRegionVariableOrigin::RootEmptyRegion
|
||||
| NllRegionVariableOrigin::Placeholder(_)
|
||||
NllRegionVariableOrigin::Placeholder(_)
|
||||
| NllRegionVariableOrigin::Existential { from_forall: true } => false,
|
||||
};
|
||||
|
||||
|
|
|
@ -1,11 +1,20 @@
|
|||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::vec_map::VecMap;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::OpaqueTyOrigin;
|
||||
use rustc_infer::infer::error_reporting::unexpected_hidden_region_diagnostic;
|
||||
use rustc_infer::infer::InferCtxt;
|
||||
use rustc_infer::infer::TyCtxtInferExt as _;
|
||||
use rustc_infer::traits::{Obligation, ObligationCause, TraitEngine};
|
||||
use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable};
|
||||
use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts};
|
||||
use rustc_middle::ty::visit::TypeVisitable;
|
||||
use rustc_middle::ty::{
|
||||
self, OpaqueHiddenType, OpaqueTypeKey, TyCtxt, TypeFoldable, TypeVisitable,
|
||||
self, OpaqueHiddenType, OpaqueTypeKey, ToPredicate, Ty, TyCtxt, TypeFoldable,
|
||||
};
|
||||
use rustc_trait_selection::opaque_types::InferCtxtExt;
|
||||
use rustc_span::Span;
|
||||
use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
|
||||
use rustc_trait_selection::traits::TraitEngineExt as _;
|
||||
|
||||
use super::RegionInferenceContext;
|
||||
|
||||
|
@ -173,3 +182,474 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub trait InferCtxtExt<'tcx> {
|
||||
fn infer_opaque_definition_from_instantiation(
|
||||
&self,
|
||||
opaque_type_key: OpaqueTypeKey<'tcx>,
|
||||
instantiated_ty: OpaqueHiddenType<'tcx>,
|
||||
origin: OpaqueTyOrigin,
|
||||
) -> Ty<'tcx>;
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||
/// Given the fully resolved, instantiated type for an opaque
|
||||
/// type, i.e., the value of an inference variable like C1 or C2
|
||||
/// (*), computes the "definition type" for an opaque type
|
||||
/// definition -- that is, the inferred value of `Foo1<'x>` or
|
||||
/// `Foo2<'x>` that we would conceptually use in its definition:
|
||||
/// ```ignore (illustrative)
|
||||
/// type Foo1<'x> = impl Bar<'x> = AAA; // <-- this type AAA
|
||||
/// type Foo2<'x> = impl Bar<'x> = BBB; // <-- or this type BBB
|
||||
/// fn foo<'a, 'b>(..) -> (Foo1<'a>, Foo2<'b>) { .. }
|
||||
/// ```
|
||||
/// Note that these values are defined in terms of a distinct set of
|
||||
/// generic parameters (`'x` instead of `'a`) from C1 or C2. The main
|
||||
/// purpose of this function is to do that translation.
|
||||
///
|
||||
/// (*) C1 and C2 were introduced in the comments on
|
||||
/// `register_member_constraints`. Read that comment for more context.
|
||||
///
|
||||
/// # Parameters
|
||||
///
|
||||
/// - `def_id`, the `impl Trait` type
|
||||
/// - `substs`, the substs used to instantiate this opaque type
|
||||
/// - `instantiated_ty`, the inferred type C1 -- fully resolved, lifted version of
|
||||
/// `opaque_defn.concrete_ty`
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
fn infer_opaque_definition_from_instantiation(
|
||||
&self,
|
||||
opaque_type_key: OpaqueTypeKey<'tcx>,
|
||||
instantiated_ty: OpaqueHiddenType<'tcx>,
|
||||
origin: OpaqueTyOrigin,
|
||||
) -> Ty<'tcx> {
|
||||
if self.is_tainted_by_errors() {
|
||||
return self.tcx.ty_error();
|
||||
}
|
||||
|
||||
let OpaqueTypeKey { def_id, substs } = opaque_type_key;
|
||||
|
||||
// Use substs to build up a reverse map from regions to their
|
||||
// identity mappings. This is necessary because of `impl
|
||||
// Trait` lifetimes are computed by replacing existing
|
||||
// lifetimes with 'static and remapping only those used in the
|
||||
// `impl Trait` return type, resulting in the parameters
|
||||
// shifting.
|
||||
let id_substs = InternalSubsts::identity_for_item(self.tcx, def_id);
|
||||
debug!(?id_substs);
|
||||
let map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>> =
|
||||
substs.iter().enumerate().map(|(index, subst)| (subst, id_substs[index])).collect();
|
||||
debug!("map = {:#?}", map);
|
||||
|
||||
// Convert the type from the function into a type valid outside
|
||||
// the function, by replacing invalid regions with 'static,
|
||||
// after producing an error for each of them.
|
||||
let definition_ty = instantiated_ty.ty.fold_with(&mut ReverseMapper::new(
|
||||
self.tcx,
|
||||
def_id,
|
||||
map,
|
||||
instantiated_ty.ty,
|
||||
instantiated_ty.span,
|
||||
));
|
||||
debug!(?definition_ty);
|
||||
|
||||
if !check_opaque_type_parameter_valid(
|
||||
self.tcx,
|
||||
opaque_type_key,
|
||||
origin,
|
||||
instantiated_ty.span,
|
||||
) {
|
||||
return self.tcx.ty_error();
|
||||
}
|
||||
|
||||
// Only check this for TAIT. RPIT already supports `src/test/ui/impl-trait/nested-return-type2.rs`
|
||||
// on stable and we'd break that.
|
||||
if let OpaqueTyOrigin::TyAlias = origin {
|
||||
// This logic duplicates most of `check_opaque_meets_bounds`.
|
||||
// FIXME(oli-obk): Also do region checks here and then consider removing `check_opaque_meets_bounds` entirely.
|
||||
let param_env = self.tcx.param_env(def_id);
|
||||
let body_id = self.tcx.local_def_id_to_hir_id(def_id.as_local().unwrap());
|
||||
self.tcx.infer_ctxt().enter(move |infcx| {
|
||||
// Require the hidden type to be well-formed with only the generics of the opaque type.
|
||||
// Defining use functions may have more bounds than the opaque type, which is ok, as long as the
|
||||
// hidden type is well formed even without those bounds.
|
||||
let predicate =
|
||||
ty::Binder::dummy(ty::PredicateKind::WellFormed(definition_ty.into()))
|
||||
.to_predicate(infcx.tcx);
|
||||
let mut fulfillment_cx = <dyn TraitEngine<'tcx>>::new(infcx.tcx);
|
||||
|
||||
// Require that the hidden type actually fulfills all the bounds of the opaque type, even without
|
||||
// the bounds that the function supplies.
|
||||
match infcx.register_hidden_type(
|
||||
OpaqueTypeKey { def_id, substs: id_substs },
|
||||
ObligationCause::misc(instantiated_ty.span, body_id),
|
||||
param_env,
|
||||
definition_ty,
|
||||
origin,
|
||||
) {
|
||||
Ok(infer_ok) => {
|
||||
for obligation in infer_ok.obligations {
|
||||
fulfillment_cx.register_predicate_obligation(&infcx, obligation);
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
infcx
|
||||
.report_mismatched_types(
|
||||
&ObligationCause::misc(instantiated_ty.span, body_id),
|
||||
self.tcx.mk_opaque(def_id, id_substs),
|
||||
definition_ty,
|
||||
err,
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
|
||||
fulfillment_cx.register_predicate_obligation(
|
||||
&infcx,
|
||||
Obligation::misc(instantiated_ty.span, body_id, param_env, predicate),
|
||||
);
|
||||
|
||||
// Check that all obligations are satisfied by the implementation's
|
||||
// version.
|
||||
let errors = fulfillment_cx.select_all_or_error(&infcx);
|
||||
|
||||
let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
|
||||
|
||||
if errors.is_empty() {
|
||||
definition_ty
|
||||
} else {
|
||||
infcx.report_fulfillment_errors(&errors, None, false);
|
||||
self.tcx.ty_error()
|
||||
}
|
||||
})
|
||||
} else {
|
||||
definition_ty
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_opaque_type_parameter_valid(
|
||||
tcx: TyCtxt<'_>,
|
||||
opaque_type_key: OpaqueTypeKey<'_>,
|
||||
origin: OpaqueTyOrigin,
|
||||
span: Span,
|
||||
) -> bool {
|
||||
match origin {
|
||||
// No need to check return position impl trait (RPIT)
|
||||
// because for type and const parameters they are correct
|
||||
// by construction: we convert
|
||||
//
|
||||
// fn foo<P0..Pn>() -> impl Trait
|
||||
//
|
||||
// into
|
||||
//
|
||||
// type Foo<P0...Pn>
|
||||
// fn foo<P0..Pn>() -> Foo<P0...Pn>.
|
||||
//
|
||||
// For lifetime parameters we convert
|
||||
//
|
||||
// fn foo<'l0..'ln>() -> impl Trait<'l0..'lm>
|
||||
//
|
||||
// into
|
||||
//
|
||||
// type foo::<'p0..'pn>::Foo<'q0..'qm>
|
||||
// fn foo<l0..'ln>() -> foo::<'static..'static>::Foo<'l0..'lm>.
|
||||
//
|
||||
// which would error here on all of the `'static` args.
|
||||
OpaqueTyOrigin::FnReturn(..) | OpaqueTyOrigin::AsyncFn(..) => return true,
|
||||
// Check these
|
||||
OpaqueTyOrigin::TyAlias => {}
|
||||
}
|
||||
let opaque_generics = tcx.generics_of(opaque_type_key.def_id);
|
||||
let mut seen_params: FxHashMap<_, Vec<_>> = FxHashMap::default();
|
||||
for (i, arg) in opaque_type_key.substs.iter().enumerate() {
|
||||
let arg_is_param = match arg.unpack() {
|
||||
GenericArgKind::Type(ty) => matches!(ty.kind(), ty::Param(_)),
|
||||
GenericArgKind::Lifetime(lt) if lt.is_static() => {
|
||||
tcx.sess
|
||||
.struct_span_err(span, "non-defining opaque type use in defining scope")
|
||||
.span_label(
|
||||
tcx.def_span(opaque_generics.param_at(i, tcx).def_id),
|
||||
"cannot use static lifetime; use a bound lifetime \
|
||||
instead or remove the lifetime parameter from the \
|
||||
opaque type",
|
||||
)
|
||||
.emit();
|
||||
return false;
|
||||
}
|
||||
GenericArgKind::Lifetime(lt) => {
|
||||
matches!(*lt, ty::ReEarlyBound(_) | ty::ReFree(_))
|
||||
}
|
||||
GenericArgKind::Const(ct) => matches!(ct.kind(), ty::ConstKind::Param(_)),
|
||||
};
|
||||
|
||||
if arg_is_param {
|
||||
seen_params.entry(arg).or_default().push(i);
|
||||
} else {
|
||||
// Prevent `fn foo() -> Foo<u32>` from being defining.
|
||||
let opaque_param = opaque_generics.param_at(i, tcx);
|
||||
tcx.sess
|
||||
.struct_span_err(span, "non-defining opaque type use in defining scope")
|
||||
.span_note(
|
||||
tcx.def_span(opaque_param.def_id),
|
||||
&format!(
|
||||
"used non-generic {} `{}` for generic parameter",
|
||||
opaque_param.kind.descr(),
|
||||
arg,
|
||||
),
|
||||
)
|
||||
.emit();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (_, indices) in seen_params {
|
||||
if indices.len() > 1 {
|
||||
let descr = opaque_generics.param_at(indices[0], tcx).kind.descr();
|
||||
let spans: Vec<_> = indices
|
||||
.into_iter()
|
||||
.map(|i| tcx.def_span(opaque_generics.param_at(i, tcx).def_id))
|
||||
.collect();
|
||||
tcx.sess
|
||||
.struct_span_err(span, "non-defining opaque type use in defining scope")
|
||||
.span_note(spans, &format!("{} used multiple times", descr))
|
||||
.emit();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
struct ReverseMapper<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
|
||||
opaque_type_def_id: DefId,
|
||||
map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>>,
|
||||
map_missing_regions_to_empty: bool,
|
||||
|
||||
/// initially `Some`, set to `None` once error has been reported
|
||||
hidden_ty: Option<Ty<'tcx>>,
|
||||
|
||||
/// Span of function being checked.
|
||||
span: Span,
|
||||
}
|
||||
|
||||
impl<'tcx> ReverseMapper<'tcx> {
|
||||
fn new(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
opaque_type_def_id: DefId,
|
||||
map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>>,
|
||||
hidden_ty: Ty<'tcx>,
|
||||
span: Span,
|
||||
) -> Self {
|
||||
Self {
|
||||
tcx,
|
||||
opaque_type_def_id,
|
||||
map,
|
||||
map_missing_regions_to_empty: false,
|
||||
hidden_ty: Some(hidden_ty),
|
||||
span,
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_kind_mapping_missing_regions_to_empty(
|
||||
&mut self,
|
||||
kind: GenericArg<'tcx>,
|
||||
) -> GenericArg<'tcx> {
|
||||
assert!(!self.map_missing_regions_to_empty);
|
||||
self.map_missing_regions_to_empty = true;
|
||||
let kind = kind.fold_with(self);
|
||||
self.map_missing_regions_to_empty = false;
|
||||
kind
|
||||
}
|
||||
|
||||
fn fold_kind_normally(&mut self, kind: GenericArg<'tcx>) -> GenericArg<'tcx> {
|
||||
assert!(!self.map_missing_regions_to_empty);
|
||||
kind.fold_with(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TypeFolder<'tcx> for ReverseMapper<'tcx> {
|
||||
fn tcx(&self) -> TyCtxt<'tcx> {
|
||||
self.tcx
|
||||
}
|
||||
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
|
||||
match *r {
|
||||
// Ignore bound regions and `'static` regions that appear in the
|
||||
// type, we only need to remap regions that reference lifetimes
|
||||
// from the function declaration.
|
||||
// This would ignore `'r` in a type like `for<'r> fn(&'r u32)`.
|
||||
ty::ReLateBound(..) | ty::ReStatic => return r,
|
||||
|
||||
// If regions have been erased (by writeback), don't try to unerase
|
||||
// them.
|
||||
ty::ReErased => return r,
|
||||
|
||||
// The regions that we expect from borrow checking.
|
||||
ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReEmpty(ty::UniverseIndex::ROOT) => {}
|
||||
|
||||
ty::ReEmpty(_) | ty::RePlaceholder(_) | ty::ReVar(_) => {
|
||||
// All of the regions in the type should either have been
|
||||
// erased by writeback, or mapped back to named regions by
|
||||
// borrow checking.
|
||||
bug!("unexpected region kind in opaque type: {:?}", r);
|
||||
}
|
||||
}
|
||||
|
||||
let generics = self.tcx().generics_of(self.opaque_type_def_id);
|
||||
match self.map.get(&r.into()).map(|k| k.unpack()) {
|
||||
Some(GenericArgKind::Lifetime(r1)) => r1,
|
||||
Some(u) => panic!("region mapped to unexpected kind: {:?}", u),
|
||||
None if self.map_missing_regions_to_empty => self.tcx.lifetimes.re_root_empty,
|
||||
None if generics.parent.is_some() => {
|
||||
if let Some(hidden_ty) = self.hidden_ty.take() {
|
||||
unexpected_hidden_region_diagnostic(
|
||||
self.tcx,
|
||||
self.tcx.def_span(self.opaque_type_def_id),
|
||||
hidden_ty,
|
||||
r,
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
self.tcx.lifetimes.re_root_empty
|
||||
}
|
||||
None => {
|
||||
self.tcx
|
||||
.sess
|
||||
.struct_span_err(self.span, "non-defining opaque type use in defining scope")
|
||||
.span_label(
|
||||
self.span,
|
||||
format!(
|
||||
"lifetime `{}` is part of concrete type but not used in \
|
||||
parameter list of the `impl Trait` type alias",
|
||||
r
|
||||
),
|
||||
)
|
||||
.emit();
|
||||
|
||||
self.tcx().lifetimes.re_static
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||
match *ty.kind() {
|
||||
ty::Closure(def_id, substs) => {
|
||||
// I am a horrible monster and I pray for death. When
|
||||
// we encounter a closure here, it is always a closure
|
||||
// from within the function that we are currently
|
||||
// type-checking -- one that is now being encapsulated
|
||||
// in an opaque type. Ideally, we would
|
||||
// go through the types/lifetimes that it references
|
||||
// and treat them just like we would any other type,
|
||||
// which means we would error out if we find any
|
||||
// reference to a type/region that is not in the
|
||||
// "reverse map".
|
||||
//
|
||||
// **However,** in the case of closures, there is a
|
||||
// somewhat subtle (read: hacky) consideration. The
|
||||
// problem is that our closure types currently include
|
||||
// all the lifetime parameters declared on the
|
||||
// enclosing function, even if they are unused by the
|
||||
// closure itself. We can't readily filter them out,
|
||||
// so here we replace those values with `'empty`. This
|
||||
// can't really make a difference to the rest of the
|
||||
// compiler; those regions are ignored for the
|
||||
// outlives relation, and hence don't affect trait
|
||||
// selection or auto traits, and they are erased
|
||||
// during codegen.
|
||||
|
||||
let generics = self.tcx.generics_of(def_id);
|
||||
let substs = self.tcx.mk_substs(substs.iter().enumerate().map(|(index, kind)| {
|
||||
if index < generics.parent_count {
|
||||
// Accommodate missing regions in the parent kinds...
|
||||
self.fold_kind_mapping_missing_regions_to_empty(kind)
|
||||
} else {
|
||||
// ...but not elsewhere.
|
||||
self.fold_kind_normally(kind)
|
||||
}
|
||||
}));
|
||||
|
||||
self.tcx.mk_closure(def_id, substs)
|
||||
}
|
||||
|
||||
ty::Generator(def_id, substs, movability) => {
|
||||
let generics = self.tcx.generics_of(def_id);
|
||||
let substs = self.tcx.mk_substs(substs.iter().enumerate().map(|(index, kind)| {
|
||||
if index < generics.parent_count {
|
||||
// Accommodate missing regions in the parent kinds...
|
||||
self.fold_kind_mapping_missing_regions_to_empty(kind)
|
||||
} else {
|
||||
// ...but not elsewhere.
|
||||
self.fold_kind_normally(kind)
|
||||
}
|
||||
}));
|
||||
|
||||
self.tcx.mk_generator(def_id, substs, movability)
|
||||
}
|
||||
|
||||
ty::Param(param) => {
|
||||
// Look it up in the substitution list.
|
||||
match self.map.get(&ty.into()).map(|k| k.unpack()) {
|
||||
// Found it in the substitution list; replace with the parameter from the
|
||||
// opaque type.
|
||||
Some(GenericArgKind::Type(t1)) => t1,
|
||||
Some(u) => panic!("type mapped to unexpected kind: {:?}", u),
|
||||
None => {
|
||||
debug!(?param, ?self.map);
|
||||
self.tcx
|
||||
.sess
|
||||
.struct_span_err(
|
||||
self.span,
|
||||
&format!(
|
||||
"type parameter `{}` is part of concrete type but not \
|
||||
used in parameter list for the `impl Trait` type alias",
|
||||
ty
|
||||
),
|
||||
)
|
||||
.emit();
|
||||
|
||||
self.tcx().ty_error()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_ => ty.super_fold_with(self),
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
|
||||
trace!("checking const {:?}", ct);
|
||||
// Find a const parameter
|
||||
match ct.kind() {
|
||||
ty::ConstKind::Param(..) => {
|
||||
// Look it up in the substitution list.
|
||||
match self.map.get(&ct.into()).map(|k| k.unpack()) {
|
||||
// Found it in the substitution list, replace with the parameter from the
|
||||
// opaque type.
|
||||
Some(GenericArgKind::Const(c1)) => c1,
|
||||
Some(u) => panic!("const mapped to unexpected kind: {:?}", u),
|
||||
None => {
|
||||
self.tcx
|
||||
.sess
|
||||
.struct_span_err(
|
||||
self.span,
|
||||
&format!(
|
||||
"const parameter `{}` is part of concrete type but not \
|
||||
used in parameter list for the `impl Trait` type alias",
|
||||
ct
|
||||
),
|
||||
)
|
||||
.emit();
|
||||
|
||||
self.tcx().const_error(ct.ty())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_ => ct,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -503,7 +503,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
|
|||
|
||||
let root_empty = self
|
||||
.infcx
|
||||
.next_nll_region_var(NllRegionVariableOrigin::RootEmptyRegion)
|
||||
.next_nll_region_var(NllRegionVariableOrigin::Existential { from_forall: true })
|
||||
.to_region_vid();
|
||||
|
||||
UniversalRegions {
|
||||
|
|
|
@ -63,7 +63,7 @@ impl HumanReadableErrorType {
|
|||
bundle: Option<Lrc<FluentBundle>>,
|
||||
fallback_bundle: LazyFallbackBundle,
|
||||
teach: bool,
|
||||
terminal_width: Option<usize>,
|
||||
diagnostic_width: Option<usize>,
|
||||
macro_backtrace: bool,
|
||||
) -> EmitterWriter {
|
||||
let (short, color_config) = self.unzip();
|
||||
|
@ -76,7 +76,7 @@ impl HumanReadableErrorType {
|
|||
short,
|
||||
teach,
|
||||
color,
|
||||
terminal_width,
|
||||
diagnostic_width,
|
||||
macro_backtrace,
|
||||
)
|
||||
}
|
||||
|
@ -710,7 +710,7 @@ pub struct EmitterWriter {
|
|||
short_message: bool,
|
||||
teach: bool,
|
||||
ui_testing: bool,
|
||||
terminal_width: Option<usize>,
|
||||
diagnostic_width: Option<usize>,
|
||||
|
||||
macro_backtrace: bool,
|
||||
}
|
||||
|
@ -730,7 +730,7 @@ impl EmitterWriter {
|
|||
fallback_bundle: LazyFallbackBundle,
|
||||
short_message: bool,
|
||||
teach: bool,
|
||||
terminal_width: Option<usize>,
|
||||
diagnostic_width: Option<usize>,
|
||||
macro_backtrace: bool,
|
||||
) -> EmitterWriter {
|
||||
let dst = Destination::from_stderr(color_config);
|
||||
|
@ -742,7 +742,7 @@ impl EmitterWriter {
|
|||
short_message,
|
||||
teach,
|
||||
ui_testing: false,
|
||||
terminal_width,
|
||||
diagnostic_width,
|
||||
macro_backtrace,
|
||||
}
|
||||
}
|
||||
|
@ -755,7 +755,7 @@ impl EmitterWriter {
|
|||
short_message: bool,
|
||||
teach: bool,
|
||||
colored: bool,
|
||||
terminal_width: Option<usize>,
|
||||
diagnostic_width: Option<usize>,
|
||||
macro_backtrace: bool,
|
||||
) -> EmitterWriter {
|
||||
EmitterWriter {
|
||||
|
@ -766,7 +766,7 @@ impl EmitterWriter {
|
|||
short_message,
|
||||
teach,
|
||||
ui_testing: false,
|
||||
terminal_width,
|
||||
diagnostic_width,
|
||||
macro_backtrace,
|
||||
}
|
||||
}
|
||||
|
@ -1615,7 +1615,7 @@ impl EmitterWriter {
|
|||
width_offset + annotated_file.multiline_depth + 1
|
||||
};
|
||||
|
||||
let column_width = if let Some(width) = self.terminal_width {
|
||||
let column_width = if let Some(width) = self.diagnostic_width {
|
||||
width.saturating_sub(code_offset)
|
||||
} else if self.ui_testing {
|
||||
DEFAULT_COLUMN_WIDTH
|
||||
|
|
|
@ -42,7 +42,7 @@ pub struct JsonEmitter {
|
|||
pretty: bool,
|
||||
ui_testing: bool,
|
||||
json_rendered: HumanReadableErrorType,
|
||||
terminal_width: Option<usize>,
|
||||
diagnostic_width: Option<usize>,
|
||||
macro_backtrace: bool,
|
||||
}
|
||||
|
||||
|
@ -54,7 +54,7 @@ impl JsonEmitter {
|
|||
fallback_bundle: LazyFallbackBundle,
|
||||
pretty: bool,
|
||||
json_rendered: HumanReadableErrorType,
|
||||
terminal_width: Option<usize>,
|
||||
diagnostic_width: Option<usize>,
|
||||
macro_backtrace: bool,
|
||||
) -> JsonEmitter {
|
||||
JsonEmitter {
|
||||
|
@ -66,7 +66,7 @@ impl JsonEmitter {
|
|||
pretty,
|
||||
ui_testing: false,
|
||||
json_rendered,
|
||||
terminal_width,
|
||||
diagnostic_width,
|
||||
macro_backtrace,
|
||||
}
|
||||
}
|
||||
|
@ -76,7 +76,7 @@ impl JsonEmitter {
|
|||
json_rendered: HumanReadableErrorType,
|
||||
fluent_bundle: Option<Lrc<FluentBundle>>,
|
||||
fallback_bundle: LazyFallbackBundle,
|
||||
terminal_width: Option<usize>,
|
||||
diagnostic_width: Option<usize>,
|
||||
macro_backtrace: bool,
|
||||
) -> JsonEmitter {
|
||||
let file_path_mapping = FilePathMapping::empty();
|
||||
|
@ -87,7 +87,7 @@ impl JsonEmitter {
|
|||
fallback_bundle,
|
||||
pretty,
|
||||
json_rendered,
|
||||
terminal_width,
|
||||
diagnostic_width,
|
||||
macro_backtrace,
|
||||
)
|
||||
}
|
||||
|
@ -100,7 +100,7 @@ impl JsonEmitter {
|
|||
fallback_bundle: LazyFallbackBundle,
|
||||
pretty: bool,
|
||||
json_rendered: HumanReadableErrorType,
|
||||
terminal_width: Option<usize>,
|
||||
diagnostic_width: Option<usize>,
|
||||
macro_backtrace: bool,
|
||||
) -> JsonEmitter {
|
||||
JsonEmitter {
|
||||
|
@ -112,7 +112,7 @@ impl JsonEmitter {
|
|||
pretty,
|
||||
ui_testing: false,
|
||||
json_rendered,
|
||||
terminal_width,
|
||||
diagnostic_width,
|
||||
macro_backtrace,
|
||||
}
|
||||
}
|
||||
|
@ -345,7 +345,7 @@ impl Diagnostic {
|
|||
je.fluent_bundle.clone(),
|
||||
je.fallback_bundle.clone(),
|
||||
false,
|
||||
je.terminal_width,
|
||||
je.diagnostic_width,
|
||||
je.macro_backtrace,
|
||||
)
|
||||
.ui_testing(je.ui_testing)
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
//! and use that to decide when one free region outlives another, and so forth.
|
||||
|
||||
use rustc_data_structures::transitive_relation::TransitiveRelation;
|
||||
use rustc_middle::ty::{self, Lift, Region, TyCtxt};
|
||||
use rustc_middle::ty::{Lift, Region, TyCtxt};
|
||||
|
||||
/// Combines a `FreeRegionMap` and a `TyCtxt`.
|
||||
///
|
||||
|
@ -49,7 +49,7 @@ impl<'tcx> FreeRegionMap<'tcx> {
|
|||
// (with the exception that `'static: 'x` is not notable)
|
||||
pub fn relate_regions(&mut self, sub: Region<'tcx>, sup: Region<'tcx>) {
|
||||
debug!("relate_regions(sub={:?}, sup={:?})", sub, sup);
|
||||
if self.is_free_or_static(sub) && self.is_free(sup) {
|
||||
if sub.is_free_or_static() && sup.is_free() {
|
||||
self.relation.add(sub, sup)
|
||||
}
|
||||
}
|
||||
|
@ -68,7 +68,7 @@ impl<'tcx> FreeRegionMap<'tcx> {
|
|||
r_a: Region<'tcx>,
|
||||
r_b: Region<'tcx>,
|
||||
) -> bool {
|
||||
assert!(self.is_free_or_static(r_a) && self.is_free_or_static(r_b));
|
||||
assert!(r_a.is_free_or_static() && r_b.is_free_or_static());
|
||||
let re_static = tcx.lifetimes.re_static;
|
||||
if self.check_relation(re_static, r_b) {
|
||||
// `'a <= 'static` is always true, and not stored in the
|
||||
|
@ -85,20 +85,6 @@ impl<'tcx> FreeRegionMap<'tcx> {
|
|||
r_a == r_b || self.relation.contains(r_a, r_b)
|
||||
}
|
||||
|
||||
/// True for free regions other than `'static`.
|
||||
pub fn is_free(&self, r: Region<'_>) -> bool {
|
||||
matches!(*r, ty::ReEarlyBound(_) | ty::ReFree(_))
|
||||
}
|
||||
|
||||
/// True if `r` is a free region or static of the sort that this
|
||||
/// free region map can be used with.
|
||||
pub fn is_free_or_static(&self, r: Region<'_>) -> bool {
|
||||
match *r {
|
||||
ty::ReStatic => true,
|
||||
_ => self.is_free(r),
|
||||
}
|
||||
}
|
||||
|
||||
/// Computes the least-upper-bound of two free regions. In some
|
||||
/// cases, this is more conservative than necessary, in order to
|
||||
/// avoid making arbitrary choices. See
|
||||
|
@ -110,8 +96,8 @@ impl<'tcx> FreeRegionMap<'tcx> {
|
|||
r_b: Region<'tcx>,
|
||||
) -> Region<'tcx> {
|
||||
debug!("lub_free_regions(r_a={:?}, r_b={:?})", r_a, r_b);
|
||||
assert!(self.is_free(r_a));
|
||||
assert!(self.is_free(r_b));
|
||||
assert!(r_a.is_free());
|
||||
assert!(r_b.is_free());
|
||||
let result = if r_a == r_b {
|
||||
r_a
|
||||
} else {
|
||||
|
|
|
@ -47,7 +47,6 @@ pub(crate) fn resolve<'tcx>(
|
|||
#[derive(Clone)]
|
||||
pub struct LexicalRegionResolutions<'tcx> {
|
||||
pub(crate) values: IndexVec<RegionVid, VarValue<'tcx>>,
|
||||
pub(crate) error_region: ty::Region<'tcx>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
|
@ -140,7 +139,6 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
|
|||
/// empty region. The `expansion` phase will grow this larger.
|
||||
fn construct_var_data(&self, tcx: TyCtxt<'tcx>) -> LexicalRegionResolutions<'tcx> {
|
||||
LexicalRegionResolutions {
|
||||
error_region: tcx.lifetimes.re_static,
|
||||
values: IndexVec::from_fn_n(
|
||||
|vid| {
|
||||
let vid_universe = self.var_infos[vid].universe;
|
||||
|
@ -310,7 +308,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
|
|||
|
||||
// Check for the case where we know that `'b: 'static` -- in that case,
|
||||
// `a <= b` for all `a`.
|
||||
let b_free_or_static = self.region_rels.free_regions.is_free_or_static(b);
|
||||
let b_free_or_static = b.is_free_or_static();
|
||||
if b_free_or_static && sub_free_regions(tcx.lifetimes.re_static, b) {
|
||||
return true;
|
||||
}
|
||||
|
@ -320,7 +318,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
|
|||
// `lub` relationship defined below, since sometimes the "lub"
|
||||
// is actually the `postdom_upper_bound` (see
|
||||
// `TransitiveRelation` for more details).
|
||||
let a_free_or_static = self.region_rels.free_regions.is_free_or_static(a);
|
||||
let a_free_or_static = a.is_free_or_static();
|
||||
if a_free_or_static && b_free_or_static {
|
||||
return sub_free_regions(a, b);
|
||||
}
|
||||
|
@ -864,10 +862,7 @@ impl<'tcx> LexicalRegionResolutions<'tcx> {
|
|||
where
|
||||
T: TypeFoldable<'tcx>,
|
||||
{
|
||||
tcx.fold_regions(value, |r, _db| match *r {
|
||||
ty::ReVar(rid) => self.resolve_var(rid),
|
||||
_ => r,
|
||||
})
|
||||
tcx.fold_regions(value, |r, _db| self.resolve_region(tcx, r))
|
||||
}
|
||||
|
||||
fn value(&self, rid: RegionVid) -> &VarValue<'tcx> {
|
||||
|
@ -878,12 +873,19 @@ impl<'tcx> LexicalRegionResolutions<'tcx> {
|
|||
&mut self.values[rid]
|
||||
}
|
||||
|
||||
pub fn resolve_var(&self, rid: RegionVid) -> ty::Region<'tcx> {
|
||||
let result = match self.values[rid] {
|
||||
VarValue::Value(r) => r,
|
||||
VarValue::ErrorValue => self.error_region,
|
||||
pub(crate) fn resolve_region(
|
||||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
r: ty::Region<'tcx>,
|
||||
) -> ty::Region<'tcx> {
|
||||
let result = match *r {
|
||||
ty::ReVar(rid) => match self.values[rid] {
|
||||
VarValue::Value(r) => r,
|
||||
VarValue::ErrorValue => tcx.lifetimes.re_static,
|
||||
},
|
||||
_ => r,
|
||||
};
|
||||
debug!("resolve_var({:?}) = {:?}", rid, result);
|
||||
debug!("resolve_region({:?}) = {:?}", r, result);
|
||||
result
|
||||
}
|
||||
}
|
||||
|
|
|
@ -466,9 +466,6 @@ pub enum NllRegionVariableOrigin {
|
|||
/// from a `for<'a> T` binder). Meant to represent "any region".
|
||||
Placeholder(ty::PlaceholderRegion),
|
||||
|
||||
/// The variable we create to represent `'empty(U0)`.
|
||||
RootEmptyRegion,
|
||||
|
||||
Existential {
|
||||
/// If this is true, then this variable was created to represent a lifetime
|
||||
/// bound in a `for` binder. For example, it might have been created to
|
||||
|
@ -1250,7 +1247,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
};
|
||||
|
||||
let lexical_region_resolutions = LexicalRegionResolutions {
|
||||
error_region: self.tcx.lifetimes.re_static,
|
||||
values: rustc_index::vec::IndexVec::from_elem_n(
|
||||
crate::infer::lexical_region_resolve::VarValue::Value(self.tcx.lifetimes.re_erased),
|
||||
var_infos.len(),
|
||||
|
|
|
@ -206,13 +206,13 @@ impl<'a, 'tcx> FallibleTypeFolder<'tcx> for FullTypeResolver<'a, 'tcx> {
|
|||
|
||||
fn try_fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
|
||||
match *r {
|
||||
ty::ReVar(rid) => Ok(self
|
||||
ty::ReVar(_) => Ok(self
|
||||
.infcx
|
||||
.lexical_region_resolutions
|
||||
.borrow()
|
||||
.as_ref()
|
||||
.expect("region resolution not performed")
|
||||
.resolve_var(rid)),
|
||||
.resolve_region(self.infcx.tcx, r)),
|
||||
_ => Ok(r),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -689,7 +689,6 @@ fn test_debugging_options_tracking_hash() {
|
|||
untracked!(span_debug, true);
|
||||
untracked!(span_free_formats, true);
|
||||
untracked!(temps_dir, Some(String::from("abc")));
|
||||
untracked!(terminal_width, Some(80));
|
||||
untracked!(threads, 99);
|
||||
untracked!(time, true);
|
||||
untracked!(time_llvm_passes, true);
|
||||
|
|
|
@ -1048,6 +1048,8 @@ impl BasicBlock {
|
|||
///////////////////////////////////////////////////////////////////////////
|
||||
// BasicBlockData
|
||||
|
||||
/// Data for a basic block, including a list of its statements.
|
||||
///
|
||||
/// See [`BasicBlock`] for documentation on what basic blocks are at a high level.
|
||||
#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
|
||||
pub struct BasicBlockData<'tcx> {
|
||||
|
@ -1079,7 +1081,7 @@ impl<'tcx> BasicBlockData<'tcx> {
|
|||
/// Accessor for terminator.
|
||||
///
|
||||
/// Terminator may not be None after construction of the basic block is complete. This accessor
|
||||
/// provides a convenience way to reach the terminator.
|
||||
/// provides a convenient way to reach the terminator.
|
||||
#[inline]
|
||||
pub fn terminator(&self) -> &Terminator<'tcx> {
|
||||
self.terminator.as_ref().expect("invalid terminator state")
|
||||
|
@ -1286,6 +1288,7 @@ impl<O: fmt::Debug> fmt::Debug for AssertKind<O> {
|
|||
///////////////////////////////////////////////////////////////////////////
|
||||
// Statements
|
||||
|
||||
/// A statement in a basic block, including information about its source code.
|
||||
#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
|
||||
pub struct Statement<'tcx> {
|
||||
pub source_info: SourceInfo,
|
||||
|
|
|
@ -1570,6 +1570,19 @@ impl<'tcx> Region<'tcx> {
|
|||
_ => bug!("free_region_binding_scope invoked on inappropriate region: {:?}", self),
|
||||
}
|
||||
}
|
||||
|
||||
/// True for free regions other than `'static`.
|
||||
pub fn is_free(self) -> bool {
|
||||
matches!(*self, ty::ReEarlyBound(_) | ty::ReFree(_))
|
||||
}
|
||||
|
||||
/// True if `self` is a free region or static.
|
||||
pub fn is_free_or_static(self) -> bool {
|
||||
match *self {
|
||||
ty::ReStatic => true,
|
||||
_ => self.is_free(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Type utilities
|
||||
|
|
|
@ -726,6 +726,7 @@ impl Default for Options {
|
|||
prints: Vec::new(),
|
||||
cg: Default::default(),
|
||||
error_format: ErrorOutputType::default(),
|
||||
diagnostic_width: None,
|
||||
externs: Externs(BTreeMap::new()),
|
||||
crate_name: None,
|
||||
libs: Vec::new(),
|
||||
|
@ -1427,6 +1428,12 @@ pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
|
|||
never = never colorize output",
|
||||
"auto|always|never",
|
||||
),
|
||||
opt::opt_s(
|
||||
"",
|
||||
"diagnostic-width",
|
||||
"Inform rustc of the width of the output so that diagnostics can be truncated to fit",
|
||||
"WIDTH",
|
||||
),
|
||||
opt::multi_s(
|
||||
"",
|
||||
"remap-path-prefix",
|
||||
|
@ -2202,6 +2209,10 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
|
|||
|
||||
let error_format = parse_error_format(matches, color, json_rendered);
|
||||
|
||||
let diagnostic_width = matches.opt_get("diagnostic-width").unwrap_or_else(|_| {
|
||||
early_error(error_format, "`--diagnostic-width` must be an positive integer");
|
||||
});
|
||||
|
||||
let unparsed_crate_types = matches.opt_strs("crate-type");
|
||||
let crate_types = parse_crate_types_from_list(unparsed_crate_types)
|
||||
.unwrap_or_else(|e| early_error(error_format, &e));
|
||||
|
@ -2474,6 +2485,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
|
|||
prints,
|
||||
cg,
|
||||
error_format,
|
||||
diagnostic_width,
|
||||
externs,
|
||||
unstable_features: UnstableFeatures::from_environment(crate_name.as_deref()),
|
||||
crate_name,
|
||||
|
|
|
@ -170,6 +170,7 @@ top_level_options!(
|
|||
|
||||
test: bool [TRACKED],
|
||||
error_format: ErrorOutputType [UNTRACKED],
|
||||
diagnostic_width: Option<usize> [UNTRACKED],
|
||||
|
||||
/// If `Some`, enable incremental compilation, using the given
|
||||
/// directory to store intermediate results.
|
||||
|
@ -1388,6 +1389,8 @@ options! {
|
|||
"panic strategy for out-of-memory handling"),
|
||||
osx_rpath_install_name: bool = (false, parse_bool, [TRACKED],
|
||||
"pass `-install_name @rpath/...` to the macOS linker (default: no)"),
|
||||
diagnostic_width: Option<usize> = (None, parse_opt_number, [UNTRACKED],
|
||||
"set the current output width for diagnostic truncation"),
|
||||
panic_abort_tests: bool = (false, parse_bool, [TRACKED],
|
||||
"support compiling tests with panic=abort (default: no)"),
|
||||
panic_in_drop: PanicStrategy = (PanicStrategy::Unwind, parse_panic_strategy, [TRACKED],
|
||||
|
@ -1514,8 +1517,6 @@ options! {
|
|||
"show extended diagnostic help (default: no)"),
|
||||
temps_dir: Option<String> = (None, parse_opt_string, [UNTRACKED],
|
||||
"the directory the intermediate files are written to"),
|
||||
terminal_width: Option<usize> = (None, parse_opt_number, [UNTRACKED],
|
||||
"set the current terminal width"),
|
||||
// Diagnostics are considered side-effects of a query (see `QuerySideEffects`) and are saved
|
||||
// alongside query results and changes to translation options can affect diagnostics - so
|
||||
// translation options should be tracked.
|
||||
|
|
|
@ -1162,7 +1162,7 @@ fn default_emitter(
|
|||
fallback_bundle,
|
||||
short,
|
||||
sopts.debugging_opts.teach,
|
||||
sopts.debugging_opts.terminal_width,
|
||||
sopts.diagnostic_width,
|
||||
macro_backtrace,
|
||||
),
|
||||
Some(dst) => EmitterWriter::new(
|
||||
|
@ -1173,7 +1173,7 @@ fn default_emitter(
|
|||
short,
|
||||
false, // no teach messages when writing to a buffer
|
||||
false, // no colors when writing to a buffer
|
||||
None, // no terminal width
|
||||
None, // no diagnostic width
|
||||
macro_backtrace,
|
||||
),
|
||||
};
|
||||
|
@ -1188,7 +1188,7 @@ fn default_emitter(
|
|||
fallback_bundle,
|
||||
pretty,
|
||||
json_rendered,
|
||||
sopts.debugging_opts.terminal_width,
|
||||
sopts.diagnostic_width,
|
||||
macro_backtrace,
|
||||
)
|
||||
.ui_testing(sopts.debugging_opts.ui_testing),
|
||||
|
@ -1202,7 +1202,7 @@ fn default_emitter(
|
|||
fallback_bundle,
|
||||
pretty,
|
||||
json_rendered,
|
||||
sopts.debugging_opts.terminal_width,
|
||||
sopts.diagnostic_width,
|
||||
macro_backtrace,
|
||||
)
|
||||
.ui_testing(sopts.debugging_opts.ui_testing),
|
||||
|
|
|
@ -37,5 +37,4 @@ extern crate smallvec;
|
|||
|
||||
pub mod autoderef;
|
||||
pub mod infer;
|
||||
pub mod opaque_types;
|
||||
pub mod traits;
|
||||
|
|
|
@ -1,545 +0,0 @@
|
|||
use crate::traits;
|
||||
use crate::traits::error_reporting::InferCtxtExt as _;
|
||||
use crate::traits::TraitEngineExt as _;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::OpaqueTyOrigin;
|
||||
use rustc_infer::infer::error_reporting::unexpected_hidden_region_diagnostic;
|
||||
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt as _};
|
||||
use rustc_infer::traits::{Obligation, ObligationCause, TraitEngine};
|
||||
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
|
||||
use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts};
|
||||
use rustc_middle::ty::visit::TypeVisitable;
|
||||
use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey, ToPredicate, Ty, TyCtxt};
|
||||
use rustc_span::Span;
|
||||
|
||||
pub trait InferCtxtExt<'tcx> {
|
||||
fn infer_opaque_definition_from_instantiation(
|
||||
&self,
|
||||
opaque_type_key: OpaqueTypeKey<'tcx>,
|
||||
instantiated_ty: OpaqueHiddenType<'tcx>,
|
||||
origin: OpaqueTyOrigin,
|
||||
) -> Ty<'tcx>;
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||
/// Given the fully resolved, instantiated type for an opaque
|
||||
/// type, i.e., the value of an inference variable like C1 or C2
|
||||
/// (*), computes the "definition type" for an opaque type
|
||||
/// definition -- that is, the inferred value of `Foo1<'x>` or
|
||||
/// `Foo2<'x>` that we would conceptually use in its definition:
|
||||
/// ```ignore (illustrative)
|
||||
/// type Foo1<'x> = impl Bar<'x> = AAA; // <-- this type AAA
|
||||
/// type Foo2<'x> = impl Bar<'x> = BBB; // <-- or this type BBB
|
||||
/// fn foo<'a, 'b>(..) -> (Foo1<'a>, Foo2<'b>) { .. }
|
||||
/// ```
|
||||
/// Note that these values are defined in terms of a distinct set of
|
||||
/// generic parameters (`'x` instead of `'a`) from C1 or C2. The main
|
||||
/// purpose of this function is to do that translation.
|
||||
///
|
||||
/// (*) C1 and C2 were introduced in the comments on
|
||||
/// `register_member_constraints`. Read that comment for more context.
|
||||
///
|
||||
/// # Parameters
|
||||
///
|
||||
/// - `def_id`, the `impl Trait` type
|
||||
/// - `substs`, the substs used to instantiate this opaque type
|
||||
/// - `instantiated_ty`, the inferred type C1 -- fully resolved, lifted version of
|
||||
/// `opaque_defn.concrete_ty`
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
fn infer_opaque_definition_from_instantiation(
|
||||
&self,
|
||||
opaque_type_key: OpaqueTypeKey<'tcx>,
|
||||
instantiated_ty: OpaqueHiddenType<'tcx>,
|
||||
origin: OpaqueTyOrigin,
|
||||
) -> Ty<'tcx> {
|
||||
if self.is_tainted_by_errors() {
|
||||
return self.tcx.ty_error();
|
||||
}
|
||||
|
||||
let OpaqueTypeKey { def_id, substs } = opaque_type_key;
|
||||
|
||||
// Use substs to build up a reverse map from regions to their
|
||||
// identity mappings. This is necessary because of `impl
|
||||
// Trait` lifetimes are computed by replacing existing
|
||||
// lifetimes with 'static and remapping only those used in the
|
||||
// `impl Trait` return type, resulting in the parameters
|
||||
// shifting.
|
||||
let id_substs = InternalSubsts::identity_for_item(self.tcx, def_id);
|
||||
debug!(?id_substs);
|
||||
let map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>> =
|
||||
substs.iter().enumerate().map(|(index, subst)| (subst, id_substs[index])).collect();
|
||||
debug!("map = {:#?}", map);
|
||||
|
||||
// Convert the type from the function into a type valid outside
|
||||
// the function, by replacing invalid regions with 'static,
|
||||
// after producing an error for each of them.
|
||||
let definition_ty = instantiated_ty.ty.fold_with(&mut ReverseMapper::new(
|
||||
self.tcx,
|
||||
def_id,
|
||||
map,
|
||||
instantiated_ty.ty,
|
||||
instantiated_ty.span,
|
||||
));
|
||||
debug!(?definition_ty);
|
||||
|
||||
if !check_opaque_type_parameter_valid(
|
||||
self.tcx,
|
||||
opaque_type_key,
|
||||
origin,
|
||||
instantiated_ty.span,
|
||||
) {
|
||||
return self.tcx.ty_error();
|
||||
}
|
||||
|
||||
// Only check this for TAIT. RPIT already supports `src/test/ui/impl-trait/nested-return-type2.rs`
|
||||
// on stable and we'd break that.
|
||||
if let OpaqueTyOrigin::TyAlias = origin {
|
||||
// This logic duplicates most of `check_opaque_meets_bounds`.
|
||||
// FIXME(oli-obk): Also do region checks here and then consider removing `check_opaque_meets_bounds` entirely.
|
||||
let param_env = self.tcx.param_env(def_id);
|
||||
let body_id = self.tcx.local_def_id_to_hir_id(def_id.as_local().unwrap());
|
||||
self.tcx.infer_ctxt().enter(move |infcx| {
|
||||
// Require the hidden type to be well-formed with only the generics of the opaque type.
|
||||
// Defining use functions may have more bounds than the opaque type, which is ok, as long as the
|
||||
// hidden type is well formed even without those bounds.
|
||||
let predicate =
|
||||
ty::Binder::dummy(ty::PredicateKind::WellFormed(definition_ty.into()))
|
||||
.to_predicate(infcx.tcx);
|
||||
let mut fulfillment_cx = <dyn TraitEngine<'tcx>>::new(infcx.tcx);
|
||||
|
||||
// Require that the hidden type actually fulfills all the bounds of the opaque type, even without
|
||||
// the bounds that the function supplies.
|
||||
match infcx.register_hidden_type(
|
||||
OpaqueTypeKey { def_id, substs: id_substs },
|
||||
ObligationCause::misc(instantiated_ty.span, body_id),
|
||||
param_env,
|
||||
definition_ty,
|
||||
origin,
|
||||
) {
|
||||
Ok(infer_ok) => {
|
||||
for obligation in infer_ok.obligations {
|
||||
fulfillment_cx.register_predicate_obligation(&infcx, obligation);
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
infcx
|
||||
.report_mismatched_types(
|
||||
&ObligationCause::misc(instantiated_ty.span, body_id),
|
||||
self.tcx.mk_opaque(def_id, id_substs),
|
||||
definition_ty,
|
||||
err,
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
|
||||
fulfillment_cx.register_predicate_obligation(
|
||||
&infcx,
|
||||
Obligation::misc(instantiated_ty.span, body_id, param_env, predicate),
|
||||
);
|
||||
|
||||
// Check that all obligations are satisfied by the implementation's
|
||||
// version.
|
||||
let errors = fulfillment_cx.select_all_or_error(&infcx);
|
||||
|
||||
let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
|
||||
|
||||
if errors.is_empty() {
|
||||
definition_ty
|
||||
} else {
|
||||
infcx.report_fulfillment_errors(&errors, None, false);
|
||||
self.tcx.ty_error()
|
||||
}
|
||||
})
|
||||
} else {
|
||||
definition_ty
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_opaque_type_parameter_valid(
|
||||
tcx: TyCtxt<'_>,
|
||||
opaque_type_key: OpaqueTypeKey<'_>,
|
||||
origin: OpaqueTyOrigin,
|
||||
span: Span,
|
||||
) -> bool {
|
||||
match origin {
|
||||
// No need to check return position impl trait (RPIT)
|
||||
// because for type and const parameters they are correct
|
||||
// by construction: we convert
|
||||
//
|
||||
// fn foo<P0..Pn>() -> impl Trait
|
||||
//
|
||||
// into
|
||||
//
|
||||
// type Foo<P0...Pn>
|
||||
// fn foo<P0..Pn>() -> Foo<P0...Pn>.
|
||||
//
|
||||
// For lifetime parameters we convert
|
||||
//
|
||||
// fn foo<'l0..'ln>() -> impl Trait<'l0..'lm>
|
||||
//
|
||||
// into
|
||||
//
|
||||
// type foo::<'p0..'pn>::Foo<'q0..'qm>
|
||||
// fn foo<l0..'ln>() -> foo::<'static..'static>::Foo<'l0..'lm>.
|
||||
//
|
||||
// which would error here on all of the `'static` args.
|
||||
OpaqueTyOrigin::FnReturn(..) | OpaqueTyOrigin::AsyncFn(..) => return true,
|
||||
// Check these
|
||||
OpaqueTyOrigin::TyAlias => {}
|
||||
}
|
||||
let opaque_generics = tcx.generics_of(opaque_type_key.def_id);
|
||||
let mut seen_params: FxHashMap<_, Vec<_>> = FxHashMap::default();
|
||||
for (i, arg) in opaque_type_key.substs.iter().enumerate() {
|
||||
let arg_is_param = match arg.unpack() {
|
||||
GenericArgKind::Type(ty) => matches!(ty.kind(), ty::Param(_)),
|
||||
GenericArgKind::Lifetime(lt) if lt.is_static() => {
|
||||
tcx.sess
|
||||
.struct_span_err(span, "non-defining opaque type use in defining scope")
|
||||
.span_label(
|
||||
tcx.def_span(opaque_generics.param_at(i, tcx).def_id),
|
||||
"cannot use static lifetime; use a bound lifetime \
|
||||
instead or remove the lifetime parameter from the \
|
||||
opaque type",
|
||||
)
|
||||
.emit();
|
||||
return false;
|
||||
}
|
||||
GenericArgKind::Lifetime(lt) => {
|
||||
matches!(*lt, ty::ReEarlyBound(_) | ty::ReFree(_))
|
||||
}
|
||||
GenericArgKind::Const(ct) => matches!(ct.kind(), ty::ConstKind::Param(_)),
|
||||
};
|
||||
|
||||
if arg_is_param {
|
||||
seen_params.entry(arg).or_default().push(i);
|
||||
} else {
|
||||
// Prevent `fn foo() -> Foo<u32>` from being defining.
|
||||
let opaque_param = opaque_generics.param_at(i, tcx);
|
||||
tcx.sess
|
||||
.struct_span_err(span, "non-defining opaque type use in defining scope")
|
||||
.span_note(
|
||||
tcx.def_span(opaque_param.def_id),
|
||||
&format!(
|
||||
"used non-generic {} `{}` for generic parameter",
|
||||
opaque_param.kind.descr(),
|
||||
arg,
|
||||
),
|
||||
)
|
||||
.emit();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (_, indices) in seen_params {
|
||||
if indices.len() > 1 {
|
||||
let descr = opaque_generics.param_at(indices[0], tcx).kind.descr();
|
||||
let spans: Vec<_> = indices
|
||||
.into_iter()
|
||||
.map(|i| tcx.def_span(opaque_generics.param_at(i, tcx).def_id))
|
||||
.collect();
|
||||
tcx.sess
|
||||
.struct_span_err(span, "non-defining opaque type use in defining scope")
|
||||
.span_note(spans, &format!("{} used multiple times", descr))
|
||||
.emit();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
struct ReverseMapper<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
|
||||
opaque_type_def_id: DefId,
|
||||
map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>>,
|
||||
map_missing_regions_to_empty: bool,
|
||||
|
||||
/// initially `Some`, set to `None` once error has been reported
|
||||
hidden_ty: Option<Ty<'tcx>>,
|
||||
|
||||
/// Span of function being checked.
|
||||
span: Span,
|
||||
}
|
||||
|
||||
impl<'tcx> ReverseMapper<'tcx> {
|
||||
fn new(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
opaque_type_def_id: DefId,
|
||||
map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>>,
|
||||
hidden_ty: Ty<'tcx>,
|
||||
span: Span,
|
||||
) -> Self {
|
||||
Self {
|
||||
tcx,
|
||||
opaque_type_def_id,
|
||||
map,
|
||||
map_missing_regions_to_empty: false,
|
||||
hidden_ty: Some(hidden_ty),
|
||||
span,
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_kind_mapping_missing_regions_to_empty(
|
||||
&mut self,
|
||||
kind: GenericArg<'tcx>,
|
||||
) -> GenericArg<'tcx> {
|
||||
assert!(!self.map_missing_regions_to_empty);
|
||||
self.map_missing_regions_to_empty = true;
|
||||
let kind = kind.fold_with(self);
|
||||
self.map_missing_regions_to_empty = false;
|
||||
kind
|
||||
}
|
||||
|
||||
fn fold_kind_normally(&mut self, kind: GenericArg<'tcx>) -> GenericArg<'tcx> {
|
||||
assert!(!self.map_missing_regions_to_empty);
|
||||
kind.fold_with(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TypeFolder<'tcx> for ReverseMapper<'tcx> {
|
||||
fn tcx(&self) -> TyCtxt<'tcx> {
|
||||
self.tcx
|
||||
}
|
||||
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
|
||||
match *r {
|
||||
// Ignore bound regions and `'static` regions that appear in the
|
||||
// type, we only need to remap regions that reference lifetimes
|
||||
// from the function declaration.
|
||||
// This would ignore `'r` in a type like `for<'r> fn(&'r u32)`.
|
||||
ty::ReLateBound(..) | ty::ReStatic => return r,
|
||||
|
||||
// If regions have been erased (by writeback), don't try to unerase
|
||||
// them.
|
||||
ty::ReErased => return r,
|
||||
|
||||
// The regions that we expect from borrow checking.
|
||||
ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReEmpty(ty::UniverseIndex::ROOT) => {}
|
||||
|
||||
ty::ReEmpty(_) | ty::RePlaceholder(_) | ty::ReVar(_) => {
|
||||
// All of the regions in the type should either have been
|
||||
// erased by writeback, or mapped back to named regions by
|
||||
// borrow checking.
|
||||
bug!("unexpected region kind in opaque type: {:?}", r);
|
||||
}
|
||||
}
|
||||
|
||||
let generics = self.tcx().generics_of(self.opaque_type_def_id);
|
||||
match self.map.get(&r.into()).map(|k| k.unpack()) {
|
||||
Some(GenericArgKind::Lifetime(r1)) => r1,
|
||||
Some(u) => panic!("region mapped to unexpected kind: {:?}", u),
|
||||
None if self.map_missing_regions_to_empty => self.tcx.lifetimes.re_root_empty,
|
||||
None if generics.parent.is_some() => {
|
||||
if let Some(hidden_ty) = self.hidden_ty.take() {
|
||||
unexpected_hidden_region_diagnostic(
|
||||
self.tcx,
|
||||
self.tcx.def_span(self.opaque_type_def_id),
|
||||
hidden_ty,
|
||||
r,
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
self.tcx.lifetimes.re_root_empty
|
||||
}
|
||||
None => {
|
||||
self.tcx
|
||||
.sess
|
||||
.struct_span_err(self.span, "non-defining opaque type use in defining scope")
|
||||
.span_label(
|
||||
self.span,
|
||||
format!(
|
||||
"lifetime `{}` is part of concrete type but not used in \
|
||||
parameter list of the `impl Trait` type alias",
|
||||
r
|
||||
),
|
||||
)
|
||||
.emit();
|
||||
|
||||
self.tcx().lifetimes.re_static
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||
match *ty.kind() {
|
||||
ty::Closure(def_id, substs) => {
|
||||
// I am a horrible monster and I pray for death. When
|
||||
// we encounter a closure here, it is always a closure
|
||||
// from within the function that we are currently
|
||||
// type-checking -- one that is now being encapsulated
|
||||
// in an opaque type. Ideally, we would
|
||||
// go through the types/lifetimes that it references
|
||||
// and treat them just like we would any other type,
|
||||
// which means we would error out if we find any
|
||||
// reference to a type/region that is not in the
|
||||
// "reverse map".
|
||||
//
|
||||
// **However,** in the case of closures, there is a
|
||||
// somewhat subtle (read: hacky) consideration. The
|
||||
// problem is that our closure types currently include
|
||||
// all the lifetime parameters declared on the
|
||||
// enclosing function, even if they are unused by the
|
||||
// closure itself. We can't readily filter them out,
|
||||
// so here we replace those values with `'empty`. This
|
||||
// can't really make a difference to the rest of the
|
||||
// compiler; those regions are ignored for the
|
||||
// outlives relation, and hence don't affect trait
|
||||
// selection or auto traits, and they are erased
|
||||
// during codegen.
|
||||
|
||||
let generics = self.tcx.generics_of(def_id);
|
||||
let substs = self.tcx.mk_substs(substs.iter().enumerate().map(|(index, kind)| {
|
||||
if index < generics.parent_count {
|
||||
// Accommodate missing regions in the parent kinds...
|
||||
self.fold_kind_mapping_missing_regions_to_empty(kind)
|
||||
} else {
|
||||
// ...but not elsewhere.
|
||||
self.fold_kind_normally(kind)
|
||||
}
|
||||
}));
|
||||
|
||||
self.tcx.mk_closure(def_id, substs)
|
||||
}
|
||||
|
||||
ty::Generator(def_id, substs, movability) => {
|
||||
let generics = self.tcx.generics_of(def_id);
|
||||
let substs = self.tcx.mk_substs(substs.iter().enumerate().map(|(index, kind)| {
|
||||
if index < generics.parent_count {
|
||||
// Accommodate missing regions in the parent kinds...
|
||||
self.fold_kind_mapping_missing_regions_to_empty(kind)
|
||||
} else {
|
||||
// ...but not elsewhere.
|
||||
self.fold_kind_normally(kind)
|
||||
}
|
||||
}));
|
||||
|
||||
self.tcx.mk_generator(def_id, substs, movability)
|
||||
}
|
||||
|
||||
ty::Param(param) => {
|
||||
// Look it up in the substitution list.
|
||||
match self.map.get(&ty.into()).map(|k| k.unpack()) {
|
||||
// Found it in the substitution list; replace with the parameter from the
|
||||
// opaque type.
|
||||
Some(GenericArgKind::Type(t1)) => t1,
|
||||
Some(u) => panic!("type mapped to unexpected kind: {:?}", u),
|
||||
None => {
|
||||
debug!(?param, ?self.map);
|
||||
self.tcx
|
||||
.sess
|
||||
.struct_span_err(
|
||||
self.span,
|
||||
&format!(
|
||||
"type parameter `{}` is part of concrete type but not \
|
||||
used in parameter list for the `impl Trait` type alias",
|
||||
ty
|
||||
),
|
||||
)
|
||||
.emit();
|
||||
|
||||
self.tcx().ty_error()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_ => ty.super_fold_with(self),
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
|
||||
trace!("checking const {:?}", ct);
|
||||
// Find a const parameter
|
||||
match ct.kind() {
|
||||
ty::ConstKind::Param(..) => {
|
||||
// Look it up in the substitution list.
|
||||
match self.map.get(&ct.into()).map(|k| k.unpack()) {
|
||||
// Found it in the substitution list, replace with the parameter from the
|
||||
// opaque type.
|
||||
Some(GenericArgKind::Const(c1)) => c1,
|
||||
Some(u) => panic!("const mapped to unexpected kind: {:?}", u),
|
||||
None => {
|
||||
self.tcx
|
||||
.sess
|
||||
.struct_span_err(
|
||||
self.span,
|
||||
&format!(
|
||||
"const parameter `{}` is part of concrete type but not \
|
||||
used in parameter list for the `impl Trait` type alias",
|
||||
ct
|
||||
),
|
||||
)
|
||||
.emit();
|
||||
|
||||
self.tcx().const_error(ct.ty())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_ => ct,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Given a set of predicates that apply to an object type, returns
|
||||
/// the region bounds that the (erased) `Self` type must
|
||||
/// outlive. Precisely *because* the `Self` type is erased, the
|
||||
/// parameter `erased_self_ty` must be supplied to indicate what type
|
||||
/// has been used to represent `Self` in the predicates
|
||||
/// themselves. This should really be a unique type; `FreshTy(0)` is a
|
||||
/// popular choice.
|
||||
///
|
||||
/// N.B., in some cases, particularly around higher-ranked bounds,
|
||||
/// this function returns a kind of conservative approximation.
|
||||
/// That is, all regions returned by this function are definitely
|
||||
/// required, but there may be other region bounds that are not
|
||||
/// returned, as well as requirements like `for<'a> T: 'a`.
|
||||
///
|
||||
/// Requires that trait definitions have been processed so that we can
|
||||
/// elaborate predicates and walk supertraits.
|
||||
#[instrument(skip(tcx, predicates), level = "debug")]
|
||||
pub(crate) fn required_region_bounds<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
erased_self_ty: Ty<'tcx>,
|
||||
predicates: impl Iterator<Item = ty::Predicate<'tcx>>,
|
||||
) -> Vec<ty::Region<'tcx>> {
|
||||
assert!(!erased_self_ty.has_escaping_bound_vars());
|
||||
|
||||
traits::elaborate_predicates(tcx, predicates)
|
||||
.filter_map(|obligation| {
|
||||
debug!(?obligation);
|
||||
match obligation.predicate.kind().skip_binder() {
|
||||
ty::PredicateKind::Projection(..)
|
||||
| ty::PredicateKind::Trait(..)
|
||||
| ty::PredicateKind::Subtype(..)
|
||||
| ty::PredicateKind::Coerce(..)
|
||||
| ty::PredicateKind::WellFormed(..)
|
||||
| ty::PredicateKind::ObjectSafe(..)
|
||||
| ty::PredicateKind::ClosureKind(..)
|
||||
| ty::PredicateKind::RegionOutlives(..)
|
||||
| ty::PredicateKind::ConstEvaluatable(..)
|
||||
| ty::PredicateKind::ConstEquate(..)
|
||||
| ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
|
||||
ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ref t, ref r)) => {
|
||||
// Search for a bound of the form `erased_self_ty
|
||||
// : 'a`, but be wary of something like `for<'a>
|
||||
// erased_self_ty : 'a` (we interpret a
|
||||
// higher-ranked bound like that as 'static,
|
||||
// though at present the code in `fulfill.rs`
|
||||
// considers such bounds to be unsatisfiable, so
|
||||
// it's kind of a moot point since you could never
|
||||
// construct such an object, but this seems
|
||||
// correct even if that code changes).
|
||||
if t == &erased_self_ty && !r.has_escaping_bound_vars() {
|
||||
Some(*r)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
|
@ -1,5 +1,4 @@
|
|||
use crate::infer::InferCtxt;
|
||||
use crate::opaque_types::required_region_bounds;
|
||||
use crate::traits;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::DefId;
|
||||
|
@ -810,3 +809,63 @@ pub fn object_region_bounds<'tcx>(
|
|||
|
||||
required_region_bounds(tcx, open_ty, predicates)
|
||||
}
|
||||
|
||||
/// Given a set of predicates that apply to an object type, returns
|
||||
/// the region bounds that the (erased) `Self` type must
|
||||
/// outlive. Precisely *because* the `Self` type is erased, the
|
||||
/// parameter `erased_self_ty` must be supplied to indicate what type
|
||||
/// has been used to represent `Self` in the predicates
|
||||
/// themselves. This should really be a unique type; `FreshTy(0)` is a
|
||||
/// popular choice.
|
||||
///
|
||||
/// N.B., in some cases, particularly around higher-ranked bounds,
|
||||
/// this function returns a kind of conservative approximation.
|
||||
/// That is, all regions returned by this function are definitely
|
||||
/// required, but there may be other region bounds that are not
|
||||
/// returned, as well as requirements like `for<'a> T: 'a`.
|
||||
///
|
||||
/// Requires that trait definitions have been processed so that we can
|
||||
/// elaborate predicates and walk supertraits.
|
||||
#[instrument(skip(tcx, predicates), level = "debug")]
|
||||
pub(crate) fn required_region_bounds<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
erased_self_ty: Ty<'tcx>,
|
||||
predicates: impl Iterator<Item = ty::Predicate<'tcx>>,
|
||||
) -> Vec<ty::Region<'tcx>> {
|
||||
assert!(!erased_self_ty.has_escaping_bound_vars());
|
||||
|
||||
traits::elaborate_predicates(tcx, predicates)
|
||||
.filter_map(|obligation| {
|
||||
debug!(?obligation);
|
||||
match obligation.predicate.kind().skip_binder() {
|
||||
ty::PredicateKind::Projection(..)
|
||||
| ty::PredicateKind::Trait(..)
|
||||
| ty::PredicateKind::Subtype(..)
|
||||
| ty::PredicateKind::Coerce(..)
|
||||
| ty::PredicateKind::WellFormed(..)
|
||||
| ty::PredicateKind::ObjectSafe(..)
|
||||
| ty::PredicateKind::ClosureKind(..)
|
||||
| ty::PredicateKind::RegionOutlives(..)
|
||||
| ty::PredicateKind::ConstEvaluatable(..)
|
||||
| ty::PredicateKind::ConstEquate(..)
|
||||
| ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
|
||||
ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ref t, ref r)) => {
|
||||
// Search for a bound of the form `erased_self_ty
|
||||
// : 'a`, but be wary of something like `for<'a>
|
||||
// erased_self_ty : 'a` (we interpret a
|
||||
// higher-ranked bound like that as 'static,
|
||||
// though at present the code in `fulfill.rs`
|
||||
// considers such bounds to be unsatisfiable, so
|
||||
// it's kind of a moot point since you could never
|
||||
// construct such an object, but this seems
|
||||
// correct even if that code changes).
|
||||
if t == &erased_self_ty && !r.has_escaping_bound_vars() {
|
||||
Some(*r)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
|
|
@ -13,8 +13,6 @@ use crate::future::Future;
|
|||
/// on all futures.
|
||||
///
|
||||
/// ```no_run
|
||||
/// #![feature(into_future)]
|
||||
///
|
||||
/// use std::future::IntoFuture;
|
||||
///
|
||||
/// # async fn foo() {
|
||||
|
@ -33,8 +31,6 @@ use crate::future::Future;
|
|||
/// multiple times before being `.await`ed.
|
||||
///
|
||||
/// ```rust
|
||||
/// #![feature(into_future)]
|
||||
///
|
||||
/// use std::future::{ready, Ready, IntoFuture};
|
||||
///
|
||||
/// /// Eventually multiply two numbers
|
||||
|
@ -91,8 +87,6 @@ use crate::future::Future;
|
|||
/// `IntoFuture::into_future` to obtain an instance of `Future`:
|
||||
///
|
||||
/// ```rust
|
||||
/// #![feature(into_future)]
|
||||
///
|
||||
/// use std::future::IntoFuture;
|
||||
///
|
||||
/// /// Convert the output of a future to a string.
|
||||
|
@ -104,14 +98,14 @@ use crate::future::Future;
|
|||
/// format!("{:?}", fut.await)
|
||||
/// }
|
||||
/// ```
|
||||
#[unstable(feature = "into_future", issue = "67644")]
|
||||
#[stable(feature = "into_future", since = "1.64.0")]
|
||||
pub trait IntoFuture {
|
||||
/// The output that the future will produce on completion.
|
||||
#[unstable(feature = "into_future", issue = "67644")]
|
||||
#[stable(feature = "into_future", since = "1.64.0")]
|
||||
type Output;
|
||||
|
||||
/// Which kind of future are we turning this into?
|
||||
#[unstable(feature = "into_future", issue = "67644")]
|
||||
#[stable(feature = "into_future", since = "1.64.0")]
|
||||
type IntoFuture: Future<Output = Self::Output>;
|
||||
|
||||
/// Creates a future from a value.
|
||||
|
@ -121,8 +115,6 @@ pub trait IntoFuture {
|
|||
/// Basic usage:
|
||||
///
|
||||
/// ```no_run
|
||||
/// #![feature(into_future)]
|
||||
///
|
||||
/// use std::future::IntoFuture;
|
||||
///
|
||||
/// # async fn foo() {
|
||||
|
@ -131,12 +123,12 @@ pub trait IntoFuture {
|
|||
/// assert_eq!("meow", fut.await);
|
||||
/// # }
|
||||
/// ```
|
||||
#[unstable(feature = "into_future", issue = "67644")]
|
||||
#[stable(feature = "into_future", since = "1.64.0")]
|
||||
#[lang = "into_future"]
|
||||
fn into_future(self) -> Self::IntoFuture;
|
||||
}
|
||||
|
||||
#[unstable(feature = "into_future", issue = "67644")]
|
||||
#[stable(feature = "into_future", since = "1.64.0")]
|
||||
impl<F: Future> IntoFuture for F {
|
||||
type Output = F::Output;
|
||||
type IntoFuture = F;
|
||||
|
|
|
@ -29,7 +29,7 @@ pub use self::future::Future;
|
|||
#[unstable(feature = "future_join", issue = "91642")]
|
||||
pub use self::join::join;
|
||||
|
||||
#[unstable(feature = "into_future", issue = "67644")]
|
||||
#[stable(feature = "into_future", since = "1.64.0")]
|
||||
pub use into_future::IntoFuture;
|
||||
|
||||
#[stable(feature = "future_readiness_fns", since = "1.48.0")]
|
||||
|
|
|
@ -949,6 +949,7 @@ impl<'a> Builder<'a> {
|
|||
}
|
||||
|
||||
pub(crate) fn download_component(&self, url: &str, dest_path: &Path, help_on_error: &str) {
|
||||
self.verbose(&format!("download {url}"));
|
||||
// Use a temporary file in case we crash while downloading, to avoid a corrupt download in cache/.
|
||||
let tempfile = self.tempdir().join(dest_path.file_name().unwrap());
|
||||
// While bootstrap itself only supports http and https downloads, downstream forks might
|
||||
|
|
|
@ -1558,7 +1558,7 @@ fn download_ci_rustc(builder: &Builder<'_>, commit: &str) {
|
|||
builder.fix_bin_or_dylib(&bin_root.join("bin").join("rustc"));
|
||||
builder.fix_bin_or_dylib(&bin_root.join("bin").join("rustdoc"));
|
||||
let lib_dir = bin_root.join("lib");
|
||||
for lib in t!(fs::read_dir(lib_dir)) {
|
||||
for lib in t!(fs::read_dir(&lib_dir), lib_dir.display().to_string()) {
|
||||
let lib = t!(lib);
|
||||
if lib.path().extension() == Some(OsStr::new("so")) {
|
||||
builder.fix_bin_or_dylib(&lib.path());
|
||||
|
@ -1634,6 +1634,7 @@ fn download_component(
|
|||
}
|
||||
Some(sha256)
|
||||
} else if tarball.exists() {
|
||||
builder.unpack(&tarball, &bin_root, prefix);
|
||||
return;
|
||||
} else {
|
||||
None
|
||||
|
|
|
@ -73,6 +73,8 @@ pub(crate) struct Options {
|
|||
pub(crate) proc_macro_crate: bool,
|
||||
/// How to format errors and warnings.
|
||||
pub(crate) error_format: ErrorOutputType,
|
||||
/// Width of output buffer to truncate errors appropriately.
|
||||
pub(crate) diagnostic_width: Option<usize>,
|
||||
/// Library search paths to hand to the compiler.
|
||||
pub(crate) libs: Vec<SearchPath>,
|
||||
/// Library search paths strings to hand to the compiler.
|
||||
|
@ -331,11 +333,12 @@ impl Options {
|
|||
let config::JsonConfig { json_rendered, json_unused_externs, .. } =
|
||||
config::parse_json(matches);
|
||||
let error_format = config::parse_error_format(matches, color, json_rendered);
|
||||
let diagnostic_width = matches.opt_get("diagnostic-width").unwrap_or_default();
|
||||
|
||||
let codegen_options = CodegenOptions::build(matches, error_format);
|
||||
let debugging_opts = DebuggingOptions::build(matches, error_format);
|
||||
|
||||
let diag = new_handler(error_format, None, &debugging_opts);
|
||||
let diag = new_handler(error_format, None, diagnostic_width, &debugging_opts);
|
||||
|
||||
// check for deprecated options
|
||||
check_deprecated_options(matches, &diag);
|
||||
|
@ -699,6 +702,7 @@ impl Options {
|
|||
input,
|
||||
proc_macro_crate,
|
||||
error_format,
|
||||
diagnostic_width,
|
||||
libs,
|
||||
lib_strs,
|
||||
externs,
|
||||
|
|
|
@ -154,6 +154,7 @@ impl<'tcx> DocContext<'tcx> {
|
|||
pub(crate) fn new_handler(
|
||||
error_format: ErrorOutputType,
|
||||
source_map: Option<Lrc<source_map::SourceMap>>,
|
||||
diagnostic_width: Option<usize>,
|
||||
debugging_opts: &DebuggingOptions,
|
||||
) -> rustc_errors::Handler {
|
||||
let fallback_bundle =
|
||||
|
@ -169,7 +170,7 @@ pub(crate) fn new_handler(
|
|||
fallback_bundle,
|
||||
short,
|
||||
debugging_opts.teach,
|
||||
debugging_opts.terminal_width,
|
||||
diagnostic_width,
|
||||
false,
|
||||
)
|
||||
.ui_testing(debugging_opts.ui_testing),
|
||||
|
@ -187,7 +188,7 @@ pub(crate) fn new_handler(
|
|||
fallback_bundle,
|
||||
pretty,
|
||||
json_rendered,
|
||||
debugging_opts.terminal_width,
|
||||
diagnostic_width,
|
||||
false,
|
||||
)
|
||||
.ui_testing(debugging_opts.ui_testing),
|
||||
|
@ -208,6 +209,7 @@ pub(crate) fn create_config(
|
|||
crate_name,
|
||||
proc_macro_crate,
|
||||
error_format,
|
||||
diagnostic_width,
|
||||
libs,
|
||||
externs,
|
||||
mut cfgs,
|
||||
|
@ -266,6 +268,7 @@ pub(crate) fn create_config(
|
|||
actually_rustdoc: true,
|
||||
debugging_opts,
|
||||
error_format,
|
||||
diagnostic_width,
|
||||
edition,
|
||||
describe_lints,
|
||||
crate_name,
|
||||
|
|
|
@ -462,6 +462,14 @@ fn opts() -> Vec<RustcOptGroup> {
|
|||
"human|json|short",
|
||||
)
|
||||
}),
|
||||
unstable("diagnostic-width", |o| {
|
||||
o.optopt(
|
||||
"",
|
||||
"diagnostic-width",
|
||||
"Provide width of the output for truncated error messages",
|
||||
"WIDTH",
|
||||
)
|
||||
}),
|
||||
stable("json", |o| {
|
||||
o.optopt("", "json", "Configure the structure of JSON diagnostics", "CONFIG")
|
||||
}),
|
||||
|
@ -733,7 +741,12 @@ fn run_renderer<'tcx, T: formats::FormatRenderer<'tcx>>(
|
|||
}
|
||||
|
||||
fn main_options(options: config::Options) -> MainResult {
|
||||
let diag = core::new_handler(options.error_format, None, &options.debugging_opts);
|
||||
let diag = core::new_handler(
|
||||
options.error_format,
|
||||
None,
|
||||
options.diagnostic_width,
|
||||
&options.debugging_opts,
|
||||
);
|
||||
|
||||
match (options.should_test, options.markdown_input()) {
|
||||
(true, true) => return wrap_return(&diag, markdown::test(options)),
|
||||
|
|
|
@ -110,6 +110,9 @@ Options:
|
|||
never = never colorize output
|
||||
--error-format human|json|short
|
||||
How errors and other messages are produced
|
||||
--diagnostic-width WIDTH
|
||||
Provide width of the output for truncated error
|
||||
messages
|
||||
--json CONFIG Configure the structure of JSON diagnostics
|
||||
--disable-minification
|
||||
Disable minification applied on JS files
|
||||
|
|
5
src/test/rustdoc-ui/diagnostic-width.rs
Normal file
5
src/test/rustdoc-ui/diagnostic-width.rs
Normal file
|
@ -0,0 +1,5 @@
|
|||
// compile-flags: -Zunstable-options --diagnostic-width=10
|
||||
#![deny(rustdoc::bare_urls)]
|
||||
|
||||
/// This is a long line that contains a http://link.com
|
||||
pub struct Foo; //~^ ERROR
|
15
src/test/rustdoc-ui/diagnostic-width.stderr
Normal file
15
src/test/rustdoc-ui/diagnostic-width.stderr
Normal file
|
@ -0,0 +1,15 @@
|
|||
error: this URL is not a hyperlink
|
||||
--> $DIR/diagnostic-width.rs:4:41
|
||||
|
|
||||
LL | ... a http://link.com
|
||||
| ^^^^^^^^^^^^^^^ help: use an automatic link instead: `<http://link.com>`
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/diagnostic-width.rs:2:9
|
||||
|
|
||||
LL | ...ny(rustdoc::bare_url...
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
= note: bare URLs are not automatically turned into clickable links
|
||||
|
||||
error: aborting due to previous error
|
||||
|
|
@ -1,8 +1,6 @@
|
|||
// run-pass
|
||||
// aux-build: issue-72470-lib.rs
|
||||
// edition:2021
|
||||
#![feature(into_future)]
|
||||
|
||||
extern crate issue_72470_lib;
|
||||
use std::{future::{Future, IntoFuture}, pin::Pin};
|
||||
|
||||
|
|
9
src/test/ui/diagnostic-width/flag-human.rs
Normal file
9
src/test/ui/diagnostic-width/flag-human.rs
Normal file
|
@ -0,0 +1,9 @@
|
|||
// compile-flags: --diagnostic-width=20
|
||||
|
||||
// This test checks that `-Z output-width` effects the human error output by restricting it to an
|
||||
// arbitrarily low value so that the effect is visible.
|
||||
|
||||
fn main() {
|
||||
let _: () = 42;
|
||||
//~^ ERROR mismatched types
|
||||
}
|
9
src/test/ui/diagnostic-width/flag-json.rs
Normal file
9
src/test/ui/diagnostic-width/flag-json.rs
Normal file
|
@ -0,0 +1,9 @@
|
|||
// compile-flags: --diagnostic-width=20 --error-format=json
|
||||
|
||||
// This test checks that `-Z output-width` effects the JSON error output by restricting it to an
|
||||
// arbitrarily low value so that the effect is visible.
|
||||
|
||||
fn main() {
|
||||
let _: () = 42;
|
||||
//~^ ERROR arguments to this function are incorrect
|
||||
}
|
|
@ -24,7 +24,7 @@ This error occurs when an expression was used in a place where the compiler
|
|||
expected an expression of a different type. It can occur in several cases, the
|
||||
most common being when calling a function and passing an argument which has a
|
||||
different type than the matching type in the function declaration.
|
||||
"},"level":"error","spans":[{"file_name":"$DIR/flag-json.rs","byte_start":244,"byte_end":246,"line_start":7,"line_end":7,"column_start":17,"column_end":19,"is_primary":true,"text":[{"text":" let _: () = 42;","highlight_start":17,"highlight_end":19}],"label":"expected `()`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/flag-json.rs","byte_start":239,"byte_end":241,"line_start":7,"line_end":7,"column_start":12,"column_end":14,"is_primary":false,"text":[{"text":" let _: () = 42;","highlight_start":12,"highlight_end":14}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":"error[E0308]: mismatched types
|
||||
"},"level":"error","spans":[{"file_name":"$DIR/flag-json.rs","byte_start":243,"byte_end":245,"line_start":7,"line_end":7,"column_start":17,"column_end":19,"is_primary":true,"text":[{"text":" let _: () = 42;","highlight_start":17,"highlight_end":19}],"label":"expected `()`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/flag-json.rs","byte_start":238,"byte_end":240,"line_start":7,"line_end":7,"column_start":12,"column_end":14,"is_primary":false,"text":[{"text":" let _: () = 42;","highlight_start":12,"highlight_end":14}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":"error[E0308]: mismatched types
|
||||
--> $DIR/flag-json.rs:7:17
|
||||
|
|
||||
LL | ..._: () = 42;
|
|
@ -1,9 +0,0 @@
|
|||
// compile-flags: -Z terminal-width=20
|
||||
|
||||
// This test checks that `-Z terminal-width` effects the human error output by restricting it to an
|
||||
// arbitrarily low value so that the effect is visible.
|
||||
|
||||
fn main() {
|
||||
let _: () = 42;
|
||||
//~^ ERROR mismatched types
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
// compile-flags: -Z terminal-width=20 --error-format=json
|
||||
|
||||
// This test checks that `-Z terminal-width` effects the JSON error output by restricting it to an
|
||||
// arbitrarily low value so that the effect is visible.
|
||||
|
||||
fn main() {
|
||||
let _: () = 42;
|
||||
//~^ ERROR arguments to this function are incorrect
|
||||
}
|
|
@ -301,7 +301,7 @@ fn in_attributes_expansion(expr: &Expr<'_>) -> bool {
|
|||
use rustc_span::hygiene::MacroKind;
|
||||
if expr.span.from_expansion() {
|
||||
let data = expr.span.ctxt().outer_expn_data();
|
||||
matches!(data.kind, ExpnKind::Macro(MacroKind::Attr, _))
|
||||
matches!(data.kind, ExpnKind::Macro(MacroKind::Attr|MacroKind::Derive, _))
|
||||
} else {
|
||||
false
|
||||
}
|
||||
|
|
|
@ -44,6 +44,12 @@ fn in_struct_field() {
|
|||
s._underscore_field += 1;
|
||||
}
|
||||
|
||||
/// Tests that we do not lint if the struct field is used in code created with derive.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct UnderscoreInStruct {
|
||||
_foo: u32,
|
||||
}
|
||||
|
||||
/// Tests that we do not lint if the underscore is not a prefix
|
||||
fn non_prefix_underscore(some_foo: u32) -> u32 {
|
||||
some_foo + 1
|
||||
|
|
|
@ -31,7 +31,7 @@ LL | s._underscore_field += 1;
|
|||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: used binding `_i` which is prefixed with an underscore. A leading underscore signals that a binding will not be used
|
||||
--> $DIR/used_underscore_binding.rs:99:16
|
||||
--> $DIR/used_underscore_binding.rs:105:16
|
||||
|
|
||||
LL | uses_i(_i);
|
||||
| ^^
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue