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.
|
// For existential, regions, nothing to do.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1410,8 +1409,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||||
self.check_bound_universal_region(fr, placeholder, errors_buffer);
|
self.check_bound_universal_region(fr, placeholder, errors_buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
NllRegionVariableOrigin::RootEmptyRegion
|
NllRegionVariableOrigin::Existential { .. } => {
|
||||||
| NllRegionVariableOrigin::Existential { .. } => {
|
|
||||||
// nothing to check here
|
// nothing to check here
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1513,8 +1511,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||||
self.check_bound_universal_region(fr, placeholder, errors_buffer);
|
self.check_bound_universal_region(fr, placeholder, errors_buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
NllRegionVariableOrigin::RootEmptyRegion
|
NllRegionVariableOrigin::Existential { .. } => {
|
||||||
| NllRegionVariableOrigin::Existential { .. } => {
|
|
||||||
// nothing to check here
|
// nothing to check here
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1788,9 +1785,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||||
universe1.cannot_name(placeholder.universe)
|
universe1.cannot_name(placeholder.universe)
|
||||||
}
|
}
|
||||||
|
|
||||||
NllRegionVariableOrigin::RootEmptyRegion
|
NllRegionVariableOrigin::FreeRegion | NllRegionVariableOrigin::Existential { .. } => {
|
||||||
| NllRegionVariableOrigin::FreeRegion
|
false
|
||||||
| NllRegionVariableOrigin::Existential { .. } => false,
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2152,8 +2149,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||||
let blame_source = match from_region_origin {
|
let blame_source = match from_region_origin {
|
||||||
NllRegionVariableOrigin::FreeRegion
|
NllRegionVariableOrigin::FreeRegion
|
||||||
| NllRegionVariableOrigin::Existential { from_forall: false } => true,
|
| NllRegionVariableOrigin::Existential { from_forall: false } => true,
|
||||||
NllRegionVariableOrigin::RootEmptyRegion
|
NllRegionVariableOrigin::Placeholder(_)
|
||||||
| NllRegionVariableOrigin::Placeholder(_)
|
|
||||||
| NllRegionVariableOrigin::Existential { from_forall: true } => false,
|
| 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_data_structures::vec_map::VecMap;
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_hir::OpaqueTyOrigin;
|
use rustc_hir::OpaqueTyOrigin;
|
||||||
|
use rustc_infer::infer::error_reporting::unexpected_hidden_region_diagnostic;
|
||||||
use rustc_infer::infer::InferCtxt;
|
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::{
|
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;
|
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
|
let root_empty = self
|
||||||
.infcx
|
.infcx
|
||||||
.next_nll_region_var(NllRegionVariableOrigin::RootEmptyRegion)
|
.next_nll_region_var(NllRegionVariableOrigin::Existential { from_forall: true })
|
||||||
.to_region_vid();
|
.to_region_vid();
|
||||||
|
|
||||||
UniversalRegions {
|
UniversalRegions {
|
||||||
|
|
|
@ -63,7 +63,7 @@ impl HumanReadableErrorType {
|
||||||
bundle: Option<Lrc<FluentBundle>>,
|
bundle: Option<Lrc<FluentBundle>>,
|
||||||
fallback_bundle: LazyFallbackBundle,
|
fallback_bundle: LazyFallbackBundle,
|
||||||
teach: bool,
|
teach: bool,
|
||||||
terminal_width: Option<usize>,
|
diagnostic_width: Option<usize>,
|
||||||
macro_backtrace: bool,
|
macro_backtrace: bool,
|
||||||
) -> EmitterWriter {
|
) -> EmitterWriter {
|
||||||
let (short, color_config) = self.unzip();
|
let (short, color_config) = self.unzip();
|
||||||
|
@ -76,7 +76,7 @@ impl HumanReadableErrorType {
|
||||||
short,
|
short,
|
||||||
teach,
|
teach,
|
||||||
color,
|
color,
|
||||||
terminal_width,
|
diagnostic_width,
|
||||||
macro_backtrace,
|
macro_backtrace,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -710,7 +710,7 @@ pub struct EmitterWriter {
|
||||||
short_message: bool,
|
short_message: bool,
|
||||||
teach: bool,
|
teach: bool,
|
||||||
ui_testing: bool,
|
ui_testing: bool,
|
||||||
terminal_width: Option<usize>,
|
diagnostic_width: Option<usize>,
|
||||||
|
|
||||||
macro_backtrace: bool,
|
macro_backtrace: bool,
|
||||||
}
|
}
|
||||||
|
@ -730,7 +730,7 @@ impl EmitterWriter {
|
||||||
fallback_bundle: LazyFallbackBundle,
|
fallback_bundle: LazyFallbackBundle,
|
||||||
short_message: bool,
|
short_message: bool,
|
||||||
teach: bool,
|
teach: bool,
|
||||||
terminal_width: Option<usize>,
|
diagnostic_width: Option<usize>,
|
||||||
macro_backtrace: bool,
|
macro_backtrace: bool,
|
||||||
) -> EmitterWriter {
|
) -> EmitterWriter {
|
||||||
let dst = Destination::from_stderr(color_config);
|
let dst = Destination::from_stderr(color_config);
|
||||||
|
@ -742,7 +742,7 @@ impl EmitterWriter {
|
||||||
short_message,
|
short_message,
|
||||||
teach,
|
teach,
|
||||||
ui_testing: false,
|
ui_testing: false,
|
||||||
terminal_width,
|
diagnostic_width,
|
||||||
macro_backtrace,
|
macro_backtrace,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -755,7 +755,7 @@ impl EmitterWriter {
|
||||||
short_message: bool,
|
short_message: bool,
|
||||||
teach: bool,
|
teach: bool,
|
||||||
colored: bool,
|
colored: bool,
|
||||||
terminal_width: Option<usize>,
|
diagnostic_width: Option<usize>,
|
||||||
macro_backtrace: bool,
|
macro_backtrace: bool,
|
||||||
) -> EmitterWriter {
|
) -> EmitterWriter {
|
||||||
EmitterWriter {
|
EmitterWriter {
|
||||||
|
@ -766,7 +766,7 @@ impl EmitterWriter {
|
||||||
short_message,
|
short_message,
|
||||||
teach,
|
teach,
|
||||||
ui_testing: false,
|
ui_testing: false,
|
||||||
terminal_width,
|
diagnostic_width,
|
||||||
macro_backtrace,
|
macro_backtrace,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1615,7 +1615,7 @@ impl EmitterWriter {
|
||||||
width_offset + annotated_file.multiline_depth + 1
|
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)
|
width.saturating_sub(code_offset)
|
||||||
} else if self.ui_testing {
|
} else if self.ui_testing {
|
||||||
DEFAULT_COLUMN_WIDTH
|
DEFAULT_COLUMN_WIDTH
|
||||||
|
|
|
@ -42,7 +42,7 @@ pub struct JsonEmitter {
|
||||||
pretty: bool,
|
pretty: bool,
|
||||||
ui_testing: bool,
|
ui_testing: bool,
|
||||||
json_rendered: HumanReadableErrorType,
|
json_rendered: HumanReadableErrorType,
|
||||||
terminal_width: Option<usize>,
|
diagnostic_width: Option<usize>,
|
||||||
macro_backtrace: bool,
|
macro_backtrace: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ impl JsonEmitter {
|
||||||
fallback_bundle: LazyFallbackBundle,
|
fallback_bundle: LazyFallbackBundle,
|
||||||
pretty: bool,
|
pretty: bool,
|
||||||
json_rendered: HumanReadableErrorType,
|
json_rendered: HumanReadableErrorType,
|
||||||
terminal_width: Option<usize>,
|
diagnostic_width: Option<usize>,
|
||||||
macro_backtrace: bool,
|
macro_backtrace: bool,
|
||||||
) -> JsonEmitter {
|
) -> JsonEmitter {
|
||||||
JsonEmitter {
|
JsonEmitter {
|
||||||
|
@ -66,7 +66,7 @@ impl JsonEmitter {
|
||||||
pretty,
|
pretty,
|
||||||
ui_testing: false,
|
ui_testing: false,
|
||||||
json_rendered,
|
json_rendered,
|
||||||
terminal_width,
|
diagnostic_width,
|
||||||
macro_backtrace,
|
macro_backtrace,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -76,7 +76,7 @@ impl JsonEmitter {
|
||||||
json_rendered: HumanReadableErrorType,
|
json_rendered: HumanReadableErrorType,
|
||||||
fluent_bundle: Option<Lrc<FluentBundle>>,
|
fluent_bundle: Option<Lrc<FluentBundle>>,
|
||||||
fallback_bundle: LazyFallbackBundle,
|
fallback_bundle: LazyFallbackBundle,
|
||||||
terminal_width: Option<usize>,
|
diagnostic_width: Option<usize>,
|
||||||
macro_backtrace: bool,
|
macro_backtrace: bool,
|
||||||
) -> JsonEmitter {
|
) -> JsonEmitter {
|
||||||
let file_path_mapping = FilePathMapping::empty();
|
let file_path_mapping = FilePathMapping::empty();
|
||||||
|
@ -87,7 +87,7 @@ impl JsonEmitter {
|
||||||
fallback_bundle,
|
fallback_bundle,
|
||||||
pretty,
|
pretty,
|
||||||
json_rendered,
|
json_rendered,
|
||||||
terminal_width,
|
diagnostic_width,
|
||||||
macro_backtrace,
|
macro_backtrace,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -100,7 +100,7 @@ impl JsonEmitter {
|
||||||
fallback_bundle: LazyFallbackBundle,
|
fallback_bundle: LazyFallbackBundle,
|
||||||
pretty: bool,
|
pretty: bool,
|
||||||
json_rendered: HumanReadableErrorType,
|
json_rendered: HumanReadableErrorType,
|
||||||
terminal_width: Option<usize>,
|
diagnostic_width: Option<usize>,
|
||||||
macro_backtrace: bool,
|
macro_backtrace: bool,
|
||||||
) -> JsonEmitter {
|
) -> JsonEmitter {
|
||||||
JsonEmitter {
|
JsonEmitter {
|
||||||
|
@ -112,7 +112,7 @@ impl JsonEmitter {
|
||||||
pretty,
|
pretty,
|
||||||
ui_testing: false,
|
ui_testing: false,
|
||||||
json_rendered,
|
json_rendered,
|
||||||
terminal_width,
|
diagnostic_width,
|
||||||
macro_backtrace,
|
macro_backtrace,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -345,7 +345,7 @@ impl Diagnostic {
|
||||||
je.fluent_bundle.clone(),
|
je.fluent_bundle.clone(),
|
||||||
je.fallback_bundle.clone(),
|
je.fallback_bundle.clone(),
|
||||||
false,
|
false,
|
||||||
je.terminal_width,
|
je.diagnostic_width,
|
||||||
je.macro_backtrace,
|
je.macro_backtrace,
|
||||||
)
|
)
|
||||||
.ui_testing(je.ui_testing)
|
.ui_testing(je.ui_testing)
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
//! and use that to decide when one free region outlives another, and so forth.
|
//! and use that to decide when one free region outlives another, and so forth.
|
||||||
|
|
||||||
use rustc_data_structures::transitive_relation::TransitiveRelation;
|
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`.
|
/// Combines a `FreeRegionMap` and a `TyCtxt`.
|
||||||
///
|
///
|
||||||
|
@ -49,7 +49,7 @@ impl<'tcx> FreeRegionMap<'tcx> {
|
||||||
// (with the exception that `'static: 'x` is not notable)
|
// (with the exception that `'static: 'x` is not notable)
|
||||||
pub fn relate_regions(&mut self, sub: Region<'tcx>, sup: Region<'tcx>) {
|
pub fn relate_regions(&mut self, sub: Region<'tcx>, sup: Region<'tcx>) {
|
||||||
debug!("relate_regions(sub={:?}, sup={:?})", sub, sup);
|
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)
|
self.relation.add(sub, sup)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -68,7 +68,7 @@ impl<'tcx> FreeRegionMap<'tcx> {
|
||||||
r_a: Region<'tcx>,
|
r_a: Region<'tcx>,
|
||||||
r_b: Region<'tcx>,
|
r_b: Region<'tcx>,
|
||||||
) -> bool {
|
) -> 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;
|
let re_static = tcx.lifetimes.re_static;
|
||||||
if self.check_relation(re_static, r_b) {
|
if self.check_relation(re_static, r_b) {
|
||||||
// `'a <= 'static` is always true, and not stored in the
|
// `'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)
|
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
|
/// Computes the least-upper-bound of two free regions. In some
|
||||||
/// cases, this is more conservative than necessary, in order to
|
/// cases, this is more conservative than necessary, in order to
|
||||||
/// avoid making arbitrary choices. See
|
/// avoid making arbitrary choices. See
|
||||||
|
@ -110,8 +96,8 @@ impl<'tcx> FreeRegionMap<'tcx> {
|
||||||
r_b: Region<'tcx>,
|
r_b: Region<'tcx>,
|
||||||
) -> Region<'tcx> {
|
) -> Region<'tcx> {
|
||||||
debug!("lub_free_regions(r_a={:?}, r_b={:?})", r_a, r_b);
|
debug!("lub_free_regions(r_a={:?}, r_b={:?})", r_a, r_b);
|
||||||
assert!(self.is_free(r_a));
|
assert!(r_a.is_free());
|
||||||
assert!(self.is_free(r_b));
|
assert!(r_b.is_free());
|
||||||
let result = if r_a == r_b {
|
let result = if r_a == r_b {
|
||||||
r_a
|
r_a
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -47,7 +47,6 @@ pub(crate) fn resolve<'tcx>(
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct LexicalRegionResolutions<'tcx> {
|
pub struct LexicalRegionResolutions<'tcx> {
|
||||||
pub(crate) values: IndexVec<RegionVid, VarValue<'tcx>>,
|
pub(crate) values: IndexVec<RegionVid, VarValue<'tcx>>,
|
||||||
pub(crate) error_region: ty::Region<'tcx>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
@ -140,7 +139,6 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
|
||||||
/// empty region. The `expansion` phase will grow this larger.
|
/// empty region. The `expansion` phase will grow this larger.
|
||||||
fn construct_var_data(&self, tcx: TyCtxt<'tcx>) -> LexicalRegionResolutions<'tcx> {
|
fn construct_var_data(&self, tcx: TyCtxt<'tcx>) -> LexicalRegionResolutions<'tcx> {
|
||||||
LexicalRegionResolutions {
|
LexicalRegionResolutions {
|
||||||
error_region: tcx.lifetimes.re_static,
|
|
||||||
values: IndexVec::from_fn_n(
|
values: IndexVec::from_fn_n(
|
||||||
|vid| {
|
|vid| {
|
||||||
let vid_universe = self.var_infos[vid].universe;
|
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,
|
// Check for the case where we know that `'b: 'static` -- in that case,
|
||||||
// `a <= b` for all `a`.
|
// `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) {
|
if b_free_or_static && sub_free_regions(tcx.lifetimes.re_static, b) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -320,7 +318,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
|
||||||
// `lub` relationship defined below, since sometimes the "lub"
|
// `lub` relationship defined below, since sometimes the "lub"
|
||||||
// is actually the `postdom_upper_bound` (see
|
// is actually the `postdom_upper_bound` (see
|
||||||
// `TransitiveRelation` for more details).
|
// `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 {
|
if a_free_or_static && b_free_or_static {
|
||||||
return sub_free_regions(a, b);
|
return sub_free_regions(a, b);
|
||||||
}
|
}
|
||||||
|
@ -864,10 +862,7 @@ impl<'tcx> LexicalRegionResolutions<'tcx> {
|
||||||
where
|
where
|
||||||
T: TypeFoldable<'tcx>,
|
T: TypeFoldable<'tcx>,
|
||||||
{
|
{
|
||||||
tcx.fold_regions(value, |r, _db| match *r {
|
tcx.fold_regions(value, |r, _db| self.resolve_region(tcx, r))
|
||||||
ty::ReVar(rid) => self.resolve_var(rid),
|
|
||||||
_ => r,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn value(&self, rid: RegionVid) -> &VarValue<'tcx> {
|
fn value(&self, rid: RegionVid) -> &VarValue<'tcx> {
|
||||||
|
@ -878,12 +873,19 @@ impl<'tcx> LexicalRegionResolutions<'tcx> {
|
||||||
&mut self.values[rid]
|
&mut self.values[rid]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resolve_var(&self, rid: RegionVid) -> ty::Region<'tcx> {
|
pub(crate) fn resolve_region(
|
||||||
let result = match self.values[rid] {
|
&self,
|
||||||
VarValue::Value(r) => r,
|
tcx: TyCtxt<'tcx>,
|
||||||
VarValue::ErrorValue => self.error_region,
|
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
|
result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -466,9 +466,6 @@ pub enum NllRegionVariableOrigin {
|
||||||
/// from a `for<'a> T` binder). Meant to represent "any region".
|
/// from a `for<'a> T` binder). Meant to represent "any region".
|
||||||
Placeholder(ty::PlaceholderRegion),
|
Placeholder(ty::PlaceholderRegion),
|
||||||
|
|
||||||
/// The variable we create to represent `'empty(U0)`.
|
|
||||||
RootEmptyRegion,
|
|
||||||
|
|
||||||
Existential {
|
Existential {
|
||||||
/// If this is true, then this variable was created to represent a lifetime
|
/// 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
|
/// 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 {
|
let lexical_region_resolutions = LexicalRegionResolutions {
|
||||||
error_region: self.tcx.lifetimes.re_static,
|
|
||||||
values: rustc_index::vec::IndexVec::from_elem_n(
|
values: rustc_index::vec::IndexVec::from_elem_n(
|
||||||
crate::infer::lexical_region_resolve::VarValue::Value(self.tcx.lifetimes.re_erased),
|
crate::infer::lexical_region_resolve::VarValue::Value(self.tcx.lifetimes.re_erased),
|
||||||
var_infos.len(),
|
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> {
|
fn try_fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
|
||||||
match *r {
|
match *r {
|
||||||
ty::ReVar(rid) => Ok(self
|
ty::ReVar(_) => Ok(self
|
||||||
.infcx
|
.infcx
|
||||||
.lexical_region_resolutions
|
.lexical_region_resolutions
|
||||||
.borrow()
|
.borrow()
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.expect("region resolution not performed")
|
.expect("region resolution not performed")
|
||||||
.resolve_var(rid)),
|
.resolve_region(self.infcx.tcx, r)),
|
||||||
_ => Ok(r),
|
_ => Ok(r),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -689,7 +689,6 @@ fn test_debugging_options_tracking_hash() {
|
||||||
untracked!(span_debug, true);
|
untracked!(span_debug, true);
|
||||||
untracked!(span_free_formats, true);
|
untracked!(span_free_formats, true);
|
||||||
untracked!(temps_dir, Some(String::from("abc")));
|
untracked!(temps_dir, Some(String::from("abc")));
|
||||||
untracked!(terminal_width, Some(80));
|
|
||||||
untracked!(threads, 99);
|
untracked!(threads, 99);
|
||||||
untracked!(time, true);
|
untracked!(time, true);
|
||||||
untracked!(time_llvm_passes, true);
|
untracked!(time_llvm_passes, true);
|
||||||
|
|
|
@ -1048,6 +1048,8 @@ impl BasicBlock {
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
// BasicBlockData
|
// 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.
|
/// See [`BasicBlock`] for documentation on what basic blocks are at a high level.
|
||||||
#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
|
#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
|
||||||
pub struct BasicBlockData<'tcx> {
|
pub struct BasicBlockData<'tcx> {
|
||||||
|
@ -1079,7 +1081,7 @@ impl<'tcx> BasicBlockData<'tcx> {
|
||||||
/// Accessor for terminator.
|
/// Accessor for terminator.
|
||||||
///
|
///
|
||||||
/// Terminator may not be None after construction of the basic block is complete. This accessor
|
/// 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]
|
#[inline]
|
||||||
pub fn terminator(&self) -> &Terminator<'tcx> {
|
pub fn terminator(&self) -> &Terminator<'tcx> {
|
||||||
self.terminator.as_ref().expect("invalid terminator state")
|
self.terminator.as_ref().expect("invalid terminator state")
|
||||||
|
@ -1286,6 +1288,7 @@ impl<O: fmt::Debug> fmt::Debug for AssertKind<O> {
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
// Statements
|
// Statements
|
||||||
|
|
||||||
|
/// A statement in a basic block, including information about its source code.
|
||||||
#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
|
#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
|
||||||
pub struct Statement<'tcx> {
|
pub struct Statement<'tcx> {
|
||||||
pub source_info: SourceInfo,
|
pub source_info: SourceInfo,
|
||||||
|
|
|
@ -1570,6 +1570,19 @@ impl<'tcx> Region<'tcx> {
|
||||||
_ => bug!("free_region_binding_scope invoked on inappropriate region: {:?}", self),
|
_ => 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
|
/// Type utilities
|
||||||
|
|
|
@ -726,6 +726,7 @@ impl Default for Options {
|
||||||
prints: Vec::new(),
|
prints: Vec::new(),
|
||||||
cg: Default::default(),
|
cg: Default::default(),
|
||||||
error_format: ErrorOutputType::default(),
|
error_format: ErrorOutputType::default(),
|
||||||
|
diagnostic_width: None,
|
||||||
externs: Externs(BTreeMap::new()),
|
externs: Externs(BTreeMap::new()),
|
||||||
crate_name: None,
|
crate_name: None,
|
||||||
libs: Vec::new(),
|
libs: Vec::new(),
|
||||||
|
@ -1427,6 +1428,12 @@ pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
|
||||||
never = never colorize output",
|
never = never colorize output",
|
||||||
"auto|always|never",
|
"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(
|
opt::multi_s(
|
||||||
"",
|
"",
|
||||||
"remap-path-prefix",
|
"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 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 unparsed_crate_types = matches.opt_strs("crate-type");
|
||||||
let crate_types = parse_crate_types_from_list(unparsed_crate_types)
|
let crate_types = parse_crate_types_from_list(unparsed_crate_types)
|
||||||
.unwrap_or_else(|e| early_error(error_format, &e));
|
.unwrap_or_else(|e| early_error(error_format, &e));
|
||||||
|
@ -2474,6 +2485,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
|
||||||
prints,
|
prints,
|
||||||
cg,
|
cg,
|
||||||
error_format,
|
error_format,
|
||||||
|
diagnostic_width,
|
||||||
externs,
|
externs,
|
||||||
unstable_features: UnstableFeatures::from_environment(crate_name.as_deref()),
|
unstable_features: UnstableFeatures::from_environment(crate_name.as_deref()),
|
||||||
crate_name,
|
crate_name,
|
||||||
|
|
|
@ -170,6 +170,7 @@ top_level_options!(
|
||||||
|
|
||||||
test: bool [TRACKED],
|
test: bool [TRACKED],
|
||||||
error_format: ErrorOutputType [UNTRACKED],
|
error_format: ErrorOutputType [UNTRACKED],
|
||||||
|
diagnostic_width: Option<usize> [UNTRACKED],
|
||||||
|
|
||||||
/// If `Some`, enable incremental compilation, using the given
|
/// If `Some`, enable incremental compilation, using the given
|
||||||
/// directory to store intermediate results.
|
/// directory to store intermediate results.
|
||||||
|
@ -1388,6 +1389,8 @@ options! {
|
||||||
"panic strategy for out-of-memory handling"),
|
"panic strategy for out-of-memory handling"),
|
||||||
osx_rpath_install_name: bool = (false, parse_bool, [TRACKED],
|
osx_rpath_install_name: bool = (false, parse_bool, [TRACKED],
|
||||||
"pass `-install_name @rpath/...` to the macOS linker (default: no)"),
|
"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],
|
panic_abort_tests: bool = (false, parse_bool, [TRACKED],
|
||||||
"support compiling tests with panic=abort (default: no)"),
|
"support compiling tests with panic=abort (default: no)"),
|
||||||
panic_in_drop: PanicStrategy = (PanicStrategy::Unwind, parse_panic_strategy, [TRACKED],
|
panic_in_drop: PanicStrategy = (PanicStrategy::Unwind, parse_panic_strategy, [TRACKED],
|
||||||
|
@ -1514,8 +1517,6 @@ options! {
|
||||||
"show extended diagnostic help (default: no)"),
|
"show extended diagnostic help (default: no)"),
|
||||||
temps_dir: Option<String> = (None, parse_opt_string, [UNTRACKED],
|
temps_dir: Option<String> = (None, parse_opt_string, [UNTRACKED],
|
||||||
"the directory the intermediate files are written to"),
|
"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
|
// 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
|
// alongside query results and changes to translation options can affect diagnostics - so
|
||||||
// translation options should be tracked.
|
// translation options should be tracked.
|
||||||
|
|
|
@ -1162,7 +1162,7 @@ fn default_emitter(
|
||||||
fallback_bundle,
|
fallback_bundle,
|
||||||
short,
|
short,
|
||||||
sopts.debugging_opts.teach,
|
sopts.debugging_opts.teach,
|
||||||
sopts.debugging_opts.terminal_width,
|
sopts.diagnostic_width,
|
||||||
macro_backtrace,
|
macro_backtrace,
|
||||||
),
|
),
|
||||||
Some(dst) => EmitterWriter::new(
|
Some(dst) => EmitterWriter::new(
|
||||||
|
@ -1173,7 +1173,7 @@ fn default_emitter(
|
||||||
short,
|
short,
|
||||||
false, // no teach messages when writing to a buffer
|
false, // no teach messages when writing to a buffer
|
||||||
false, // no colors when writing to a buffer
|
false, // no colors when writing to a buffer
|
||||||
None, // no terminal width
|
None, // no diagnostic width
|
||||||
macro_backtrace,
|
macro_backtrace,
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
@ -1188,7 +1188,7 @@ fn default_emitter(
|
||||||
fallback_bundle,
|
fallback_bundle,
|
||||||
pretty,
|
pretty,
|
||||||
json_rendered,
|
json_rendered,
|
||||||
sopts.debugging_opts.terminal_width,
|
sopts.diagnostic_width,
|
||||||
macro_backtrace,
|
macro_backtrace,
|
||||||
)
|
)
|
||||||
.ui_testing(sopts.debugging_opts.ui_testing),
|
.ui_testing(sopts.debugging_opts.ui_testing),
|
||||||
|
@ -1202,7 +1202,7 @@ fn default_emitter(
|
||||||
fallback_bundle,
|
fallback_bundle,
|
||||||
pretty,
|
pretty,
|
||||||
json_rendered,
|
json_rendered,
|
||||||
sopts.debugging_opts.terminal_width,
|
sopts.diagnostic_width,
|
||||||
macro_backtrace,
|
macro_backtrace,
|
||||||
)
|
)
|
||||||
.ui_testing(sopts.debugging_opts.ui_testing),
|
.ui_testing(sopts.debugging_opts.ui_testing),
|
||||||
|
|
|
@ -37,5 +37,4 @@ extern crate smallvec;
|
||||||
|
|
||||||
pub mod autoderef;
|
pub mod autoderef;
|
||||||
pub mod infer;
|
pub mod infer;
|
||||||
pub mod opaque_types;
|
|
||||||
pub mod traits;
|
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::infer::InferCtxt;
|
||||||
use crate::opaque_types::required_region_bounds;
|
|
||||||
use crate::traits;
|
use crate::traits;
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
|
@ -810,3 +809,63 @@ pub fn object_region_bounds<'tcx>(
|
||||||
|
|
||||||
required_region_bounds(tcx, open_ty, predicates)
|
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.
|
/// on all futures.
|
||||||
///
|
///
|
||||||
/// ```no_run
|
/// ```no_run
|
||||||
/// #![feature(into_future)]
|
|
||||||
///
|
|
||||||
/// use std::future::IntoFuture;
|
/// use std::future::IntoFuture;
|
||||||
///
|
///
|
||||||
/// # async fn foo() {
|
/// # async fn foo() {
|
||||||
|
@ -33,8 +31,6 @@ use crate::future::Future;
|
||||||
/// multiple times before being `.await`ed.
|
/// multiple times before being `.await`ed.
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// #![feature(into_future)]
|
|
||||||
///
|
|
||||||
/// use std::future::{ready, Ready, IntoFuture};
|
/// use std::future::{ready, Ready, IntoFuture};
|
||||||
///
|
///
|
||||||
/// /// Eventually multiply two numbers
|
/// /// Eventually multiply two numbers
|
||||||
|
@ -91,8 +87,6 @@ use crate::future::Future;
|
||||||
/// `IntoFuture::into_future` to obtain an instance of `Future`:
|
/// `IntoFuture::into_future` to obtain an instance of `Future`:
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// #![feature(into_future)]
|
|
||||||
///
|
|
||||||
/// use std::future::IntoFuture;
|
/// use std::future::IntoFuture;
|
||||||
///
|
///
|
||||||
/// /// Convert the output of a future to a string.
|
/// /// Convert the output of a future to a string.
|
||||||
|
@ -104,14 +98,14 @@ use crate::future::Future;
|
||||||
/// format!("{:?}", fut.await)
|
/// format!("{:?}", fut.await)
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
#[unstable(feature = "into_future", issue = "67644")]
|
#[stable(feature = "into_future", since = "1.64.0")]
|
||||||
pub trait IntoFuture {
|
pub trait IntoFuture {
|
||||||
/// The output that the future will produce on completion.
|
/// 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;
|
type Output;
|
||||||
|
|
||||||
/// Which kind of future are we turning this into?
|
/// 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>;
|
type IntoFuture: Future<Output = Self::Output>;
|
||||||
|
|
||||||
/// Creates a future from a value.
|
/// Creates a future from a value.
|
||||||
|
@ -121,8 +115,6 @@ pub trait IntoFuture {
|
||||||
/// Basic usage:
|
/// Basic usage:
|
||||||
///
|
///
|
||||||
/// ```no_run
|
/// ```no_run
|
||||||
/// #![feature(into_future)]
|
|
||||||
///
|
|
||||||
/// use std::future::IntoFuture;
|
/// use std::future::IntoFuture;
|
||||||
///
|
///
|
||||||
/// # async fn foo() {
|
/// # async fn foo() {
|
||||||
|
@ -131,12 +123,12 @@ pub trait IntoFuture {
|
||||||
/// assert_eq!("meow", fut.await);
|
/// assert_eq!("meow", fut.await);
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
#[unstable(feature = "into_future", issue = "67644")]
|
#[stable(feature = "into_future", since = "1.64.0")]
|
||||||
#[lang = "into_future"]
|
#[lang = "into_future"]
|
||||||
fn into_future(self) -> Self::IntoFuture;
|
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 {
|
impl<F: Future> IntoFuture for F {
|
||||||
type Output = F::Output;
|
type Output = F::Output;
|
||||||
type IntoFuture = F;
|
type IntoFuture = F;
|
||||||
|
|
|
@ -29,7 +29,7 @@ pub use self::future::Future;
|
||||||
#[unstable(feature = "future_join", issue = "91642")]
|
#[unstable(feature = "future_join", issue = "91642")]
|
||||||
pub use self::join::join;
|
pub use self::join::join;
|
||||||
|
|
||||||
#[unstable(feature = "into_future", issue = "67644")]
|
#[stable(feature = "into_future", since = "1.64.0")]
|
||||||
pub use into_future::IntoFuture;
|
pub use into_future::IntoFuture;
|
||||||
|
|
||||||
#[stable(feature = "future_readiness_fns", since = "1.48.0")]
|
#[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) {
|
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/.
|
// 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());
|
let tempfile = self.tempdir().join(dest_path.file_name().unwrap());
|
||||||
// While bootstrap itself only supports http and https downloads, downstream forks might
|
// 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("rustc"));
|
||||||
builder.fix_bin_or_dylib(&bin_root.join("bin").join("rustdoc"));
|
builder.fix_bin_or_dylib(&bin_root.join("bin").join("rustdoc"));
|
||||||
let lib_dir = bin_root.join("lib");
|
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);
|
let lib = t!(lib);
|
||||||
if lib.path().extension() == Some(OsStr::new("so")) {
|
if lib.path().extension() == Some(OsStr::new("so")) {
|
||||||
builder.fix_bin_or_dylib(&lib.path());
|
builder.fix_bin_or_dylib(&lib.path());
|
||||||
|
@ -1634,6 +1634,7 @@ fn download_component(
|
||||||
}
|
}
|
||||||
Some(sha256)
|
Some(sha256)
|
||||||
} else if tarball.exists() {
|
} else if tarball.exists() {
|
||||||
|
builder.unpack(&tarball, &bin_root, prefix);
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
|
|
@ -73,6 +73,8 @@ pub(crate) struct Options {
|
||||||
pub(crate) proc_macro_crate: bool,
|
pub(crate) proc_macro_crate: bool,
|
||||||
/// How to format errors and warnings.
|
/// How to format errors and warnings.
|
||||||
pub(crate) error_format: ErrorOutputType,
|
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.
|
/// Library search paths to hand to the compiler.
|
||||||
pub(crate) libs: Vec<SearchPath>,
|
pub(crate) libs: Vec<SearchPath>,
|
||||||
/// Library search paths strings to hand to the compiler.
|
/// Library search paths strings to hand to the compiler.
|
||||||
|
@ -331,11 +333,12 @@ impl Options {
|
||||||
let config::JsonConfig { json_rendered, json_unused_externs, .. } =
|
let config::JsonConfig { json_rendered, json_unused_externs, .. } =
|
||||||
config::parse_json(matches);
|
config::parse_json(matches);
|
||||||
let error_format = config::parse_error_format(matches, color, json_rendered);
|
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 codegen_options = CodegenOptions::build(matches, error_format);
|
||||||
let debugging_opts = DebuggingOptions::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 for deprecated options
|
||||||
check_deprecated_options(matches, &diag);
|
check_deprecated_options(matches, &diag);
|
||||||
|
@ -699,6 +702,7 @@ impl Options {
|
||||||
input,
|
input,
|
||||||
proc_macro_crate,
|
proc_macro_crate,
|
||||||
error_format,
|
error_format,
|
||||||
|
diagnostic_width,
|
||||||
libs,
|
libs,
|
||||||
lib_strs,
|
lib_strs,
|
||||||
externs,
|
externs,
|
||||||
|
|
|
@ -154,6 +154,7 @@ impl<'tcx> DocContext<'tcx> {
|
||||||
pub(crate) fn new_handler(
|
pub(crate) fn new_handler(
|
||||||
error_format: ErrorOutputType,
|
error_format: ErrorOutputType,
|
||||||
source_map: Option<Lrc<source_map::SourceMap>>,
|
source_map: Option<Lrc<source_map::SourceMap>>,
|
||||||
|
diagnostic_width: Option<usize>,
|
||||||
debugging_opts: &DebuggingOptions,
|
debugging_opts: &DebuggingOptions,
|
||||||
) -> rustc_errors::Handler {
|
) -> rustc_errors::Handler {
|
||||||
let fallback_bundle =
|
let fallback_bundle =
|
||||||
|
@ -169,7 +170,7 @@ pub(crate) fn new_handler(
|
||||||
fallback_bundle,
|
fallback_bundle,
|
||||||
short,
|
short,
|
||||||
debugging_opts.teach,
|
debugging_opts.teach,
|
||||||
debugging_opts.terminal_width,
|
diagnostic_width,
|
||||||
false,
|
false,
|
||||||
)
|
)
|
||||||
.ui_testing(debugging_opts.ui_testing),
|
.ui_testing(debugging_opts.ui_testing),
|
||||||
|
@ -187,7 +188,7 @@ pub(crate) fn new_handler(
|
||||||
fallback_bundle,
|
fallback_bundle,
|
||||||
pretty,
|
pretty,
|
||||||
json_rendered,
|
json_rendered,
|
||||||
debugging_opts.terminal_width,
|
diagnostic_width,
|
||||||
false,
|
false,
|
||||||
)
|
)
|
||||||
.ui_testing(debugging_opts.ui_testing),
|
.ui_testing(debugging_opts.ui_testing),
|
||||||
|
@ -208,6 +209,7 @@ pub(crate) fn create_config(
|
||||||
crate_name,
|
crate_name,
|
||||||
proc_macro_crate,
|
proc_macro_crate,
|
||||||
error_format,
|
error_format,
|
||||||
|
diagnostic_width,
|
||||||
libs,
|
libs,
|
||||||
externs,
|
externs,
|
||||||
mut cfgs,
|
mut cfgs,
|
||||||
|
@ -266,6 +268,7 @@ pub(crate) fn create_config(
|
||||||
actually_rustdoc: true,
|
actually_rustdoc: true,
|
||||||
debugging_opts,
|
debugging_opts,
|
||||||
error_format,
|
error_format,
|
||||||
|
diagnostic_width,
|
||||||
edition,
|
edition,
|
||||||
describe_lints,
|
describe_lints,
|
||||||
crate_name,
|
crate_name,
|
||||||
|
|
|
@ -462,6 +462,14 @@ fn opts() -> Vec<RustcOptGroup> {
|
||||||
"human|json|short",
|
"human|json|short",
|
||||||
)
|
)
|
||||||
}),
|
}),
|
||||||
|
unstable("diagnostic-width", |o| {
|
||||||
|
o.optopt(
|
||||||
|
"",
|
||||||
|
"diagnostic-width",
|
||||||
|
"Provide width of the output for truncated error messages",
|
||||||
|
"WIDTH",
|
||||||
|
)
|
||||||
|
}),
|
||||||
stable("json", |o| {
|
stable("json", |o| {
|
||||||
o.optopt("", "json", "Configure the structure of JSON diagnostics", "CONFIG")
|
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 {
|
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()) {
|
match (options.should_test, options.markdown_input()) {
|
||||||
(true, true) => return wrap_return(&diag, markdown::test(options)),
|
(true, true) => return wrap_return(&diag, markdown::test(options)),
|
||||||
|
|
|
@ -110,6 +110,9 @@ Options:
|
||||||
never = never colorize output
|
never = never colorize output
|
||||||
--error-format human|json|short
|
--error-format human|json|short
|
||||||
How errors and other messages are produced
|
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
|
--json CONFIG Configure the structure of JSON diagnostics
|
||||||
--disable-minification
|
--disable-minification
|
||||||
Disable minification applied on JS files
|
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
|
// run-pass
|
||||||
// aux-build: issue-72470-lib.rs
|
// aux-build: issue-72470-lib.rs
|
||||||
// edition:2021
|
// edition:2021
|
||||||
#![feature(into_future)]
|
|
||||||
|
|
||||||
extern crate issue_72470_lib;
|
extern crate issue_72470_lib;
|
||||||
use std::{future::{Future, IntoFuture}, pin::Pin};
|
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
|
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
|
most common being when calling a function and passing an argument which has a
|
||||||
different type than the matching type in the function declaration.
|
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
|
--> $DIR/flag-json.rs:7:17
|
||||||
|
|
|
|
||||||
LL | ..._: () = 42;
|
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;
|
use rustc_span::hygiene::MacroKind;
|
||||||
if expr.span.from_expansion() {
|
if expr.span.from_expansion() {
|
||||||
let data = expr.span.ctxt().outer_expn_data();
|
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 {
|
} else {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,6 +44,12 @@ fn in_struct_field() {
|
||||||
s._underscore_field += 1;
|
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
|
/// Tests that we do not lint if the underscore is not a prefix
|
||||||
fn non_prefix_underscore(some_foo: u32) -> u32 {
|
fn non_prefix_underscore(some_foo: u32) -> u32 {
|
||||||
some_foo + 1
|
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
|
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);
|
LL | uses_i(_i);
|
||||||
| ^^
|
| ^^
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue