1
Fork 0

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:
bors 2022-07-08 07:22:33 +00:00
commit 0f97e02bdc
52 changed files with 707 additions and 665 deletions

View file

@ -495,8 +495,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
}
}
NllRegionVariableOrigin::RootEmptyRegion
| NllRegionVariableOrigin::Existential { .. } => {
NllRegionVariableOrigin::Existential { .. } => {
// For existential, regions, nothing to do.
}
}
@ -1410,8 +1409,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
self.check_bound_universal_region(fr, placeholder, errors_buffer);
}
NllRegionVariableOrigin::RootEmptyRegion
| NllRegionVariableOrigin::Existential { .. } => {
NllRegionVariableOrigin::Existential { .. } => {
// nothing to check here
}
}
@ -1513,8 +1511,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
self.check_bound_universal_region(fr, placeholder, errors_buffer);
}
NllRegionVariableOrigin::RootEmptyRegion
| NllRegionVariableOrigin::Existential { .. } => {
NllRegionVariableOrigin::Existential { .. } => {
// nothing to check here
}
}
@ -1788,9 +1785,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
universe1.cannot_name(placeholder.universe)
}
NllRegionVariableOrigin::RootEmptyRegion
| NllRegionVariableOrigin::FreeRegion
| NllRegionVariableOrigin::Existential { .. } => false,
NllRegionVariableOrigin::FreeRegion | NllRegionVariableOrigin::Existential { .. } => {
false
}
}
}
@ -2152,8 +2149,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
let blame_source = match from_region_origin {
NllRegionVariableOrigin::FreeRegion
| NllRegionVariableOrigin::Existential { from_forall: false } => true,
NllRegionVariableOrigin::RootEmptyRegion
| NllRegionVariableOrigin::Placeholder(_)
NllRegionVariableOrigin::Placeholder(_)
| NllRegionVariableOrigin::Existential { from_forall: true } => false,
};

View file

@ -1,11 +1,20 @@
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::vec_map::VecMap;
use rustc_hir::def_id::DefId;
use rustc_hir::OpaqueTyOrigin;
use rustc_infer::infer::error_reporting::unexpected_hidden_region_diagnostic;
use rustc_infer::infer::InferCtxt;
use rustc_infer::infer::TyCtxtInferExt as _;
use rustc_infer::traits::{Obligation, ObligationCause, TraitEngine};
use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable};
use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts};
use rustc_middle::ty::visit::TypeVisitable;
use rustc_middle::ty::{
self, OpaqueHiddenType, OpaqueTypeKey, TyCtxt, TypeFoldable, TypeVisitable,
self, OpaqueHiddenType, OpaqueTypeKey, ToPredicate, Ty, TyCtxt, TypeFoldable,
};
use rustc_trait_selection::opaque_types::InferCtxtExt;
use rustc_span::Span;
use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
use rustc_trait_selection::traits::TraitEngineExt as _;
use super::RegionInferenceContext;
@ -173,3 +182,474 @@ impl<'tcx> RegionInferenceContext<'tcx> {
})
}
}
pub trait InferCtxtExt<'tcx> {
fn infer_opaque_definition_from_instantiation(
&self,
opaque_type_key: OpaqueTypeKey<'tcx>,
instantiated_ty: OpaqueHiddenType<'tcx>,
origin: OpaqueTyOrigin,
) -> Ty<'tcx>;
}
impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
/// Given the fully resolved, instantiated type for an opaque
/// type, i.e., the value of an inference variable like C1 or C2
/// (*), computes the "definition type" for an opaque type
/// definition -- that is, the inferred value of `Foo1<'x>` or
/// `Foo2<'x>` that we would conceptually use in its definition:
/// ```ignore (illustrative)
/// type Foo1<'x> = impl Bar<'x> = AAA; // <-- this type AAA
/// type Foo2<'x> = impl Bar<'x> = BBB; // <-- or this type BBB
/// fn foo<'a, 'b>(..) -> (Foo1<'a>, Foo2<'b>) { .. }
/// ```
/// Note that these values are defined in terms of a distinct set of
/// generic parameters (`'x` instead of `'a`) from C1 or C2. The main
/// purpose of this function is to do that translation.
///
/// (*) C1 and C2 were introduced in the comments on
/// `register_member_constraints`. Read that comment for more context.
///
/// # Parameters
///
/// - `def_id`, the `impl Trait` type
/// - `substs`, the substs used to instantiate this opaque type
/// - `instantiated_ty`, the inferred type C1 -- fully resolved, lifted version of
/// `opaque_defn.concrete_ty`
#[instrument(level = "debug", skip(self))]
fn infer_opaque_definition_from_instantiation(
&self,
opaque_type_key: OpaqueTypeKey<'tcx>,
instantiated_ty: OpaqueHiddenType<'tcx>,
origin: OpaqueTyOrigin,
) -> Ty<'tcx> {
if self.is_tainted_by_errors() {
return self.tcx.ty_error();
}
let OpaqueTypeKey { def_id, substs } = opaque_type_key;
// Use substs to build up a reverse map from regions to their
// identity mappings. This is necessary because of `impl
// Trait` lifetimes are computed by replacing existing
// lifetimes with 'static and remapping only those used in the
// `impl Trait` return type, resulting in the parameters
// shifting.
let id_substs = InternalSubsts::identity_for_item(self.tcx, def_id);
debug!(?id_substs);
let map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>> =
substs.iter().enumerate().map(|(index, subst)| (subst, id_substs[index])).collect();
debug!("map = {:#?}", map);
// Convert the type from the function into a type valid outside
// the function, by replacing invalid regions with 'static,
// after producing an error for each of them.
let definition_ty = instantiated_ty.ty.fold_with(&mut ReverseMapper::new(
self.tcx,
def_id,
map,
instantiated_ty.ty,
instantiated_ty.span,
));
debug!(?definition_ty);
if !check_opaque_type_parameter_valid(
self.tcx,
opaque_type_key,
origin,
instantiated_ty.span,
) {
return self.tcx.ty_error();
}
// Only check this for TAIT. RPIT already supports `src/test/ui/impl-trait/nested-return-type2.rs`
// on stable and we'd break that.
if let OpaqueTyOrigin::TyAlias = origin {
// This logic duplicates most of `check_opaque_meets_bounds`.
// FIXME(oli-obk): Also do region checks here and then consider removing `check_opaque_meets_bounds` entirely.
let param_env = self.tcx.param_env(def_id);
let body_id = self.tcx.local_def_id_to_hir_id(def_id.as_local().unwrap());
self.tcx.infer_ctxt().enter(move |infcx| {
// Require the hidden type to be well-formed with only the generics of the opaque type.
// Defining use functions may have more bounds than the opaque type, which is ok, as long as the
// hidden type is well formed even without those bounds.
let predicate =
ty::Binder::dummy(ty::PredicateKind::WellFormed(definition_ty.into()))
.to_predicate(infcx.tcx);
let mut fulfillment_cx = <dyn TraitEngine<'tcx>>::new(infcx.tcx);
// Require that the hidden type actually fulfills all the bounds of the opaque type, even without
// the bounds that the function supplies.
match infcx.register_hidden_type(
OpaqueTypeKey { def_id, substs: id_substs },
ObligationCause::misc(instantiated_ty.span, body_id),
param_env,
definition_ty,
origin,
) {
Ok(infer_ok) => {
for obligation in infer_ok.obligations {
fulfillment_cx.register_predicate_obligation(&infcx, obligation);
}
}
Err(err) => {
infcx
.report_mismatched_types(
&ObligationCause::misc(instantiated_ty.span, body_id),
self.tcx.mk_opaque(def_id, id_substs),
definition_ty,
err,
)
.emit();
}
}
fulfillment_cx.register_predicate_obligation(
&infcx,
Obligation::misc(instantiated_ty.span, body_id, param_env, predicate),
);
// Check that all obligations are satisfied by the implementation's
// version.
let errors = fulfillment_cx.select_all_or_error(&infcx);
let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
if errors.is_empty() {
definition_ty
} else {
infcx.report_fulfillment_errors(&errors, None, false);
self.tcx.ty_error()
}
})
} else {
definition_ty
}
}
}
fn check_opaque_type_parameter_valid(
tcx: TyCtxt<'_>,
opaque_type_key: OpaqueTypeKey<'_>,
origin: OpaqueTyOrigin,
span: Span,
) -> bool {
match origin {
// No need to check return position impl trait (RPIT)
// because for type and const parameters they are correct
// by construction: we convert
//
// fn foo<P0..Pn>() -> impl Trait
//
// into
//
// type Foo<P0...Pn>
// fn foo<P0..Pn>() -> Foo<P0...Pn>.
//
// For lifetime parameters we convert
//
// fn foo<'l0..'ln>() -> impl Trait<'l0..'lm>
//
// into
//
// type foo::<'p0..'pn>::Foo<'q0..'qm>
// fn foo<l0..'ln>() -> foo::<'static..'static>::Foo<'l0..'lm>.
//
// which would error here on all of the `'static` args.
OpaqueTyOrigin::FnReturn(..) | OpaqueTyOrigin::AsyncFn(..) => return true,
// Check these
OpaqueTyOrigin::TyAlias => {}
}
let opaque_generics = tcx.generics_of(opaque_type_key.def_id);
let mut seen_params: FxHashMap<_, Vec<_>> = FxHashMap::default();
for (i, arg) in opaque_type_key.substs.iter().enumerate() {
let arg_is_param = match arg.unpack() {
GenericArgKind::Type(ty) => matches!(ty.kind(), ty::Param(_)),
GenericArgKind::Lifetime(lt) if lt.is_static() => {
tcx.sess
.struct_span_err(span, "non-defining opaque type use in defining scope")
.span_label(
tcx.def_span(opaque_generics.param_at(i, tcx).def_id),
"cannot use static lifetime; use a bound lifetime \
instead or remove the lifetime parameter from the \
opaque type",
)
.emit();
return false;
}
GenericArgKind::Lifetime(lt) => {
matches!(*lt, ty::ReEarlyBound(_) | ty::ReFree(_))
}
GenericArgKind::Const(ct) => matches!(ct.kind(), ty::ConstKind::Param(_)),
};
if arg_is_param {
seen_params.entry(arg).or_default().push(i);
} else {
// Prevent `fn foo() -> Foo<u32>` from being defining.
let opaque_param = opaque_generics.param_at(i, tcx);
tcx.sess
.struct_span_err(span, "non-defining opaque type use in defining scope")
.span_note(
tcx.def_span(opaque_param.def_id),
&format!(
"used non-generic {} `{}` for generic parameter",
opaque_param.kind.descr(),
arg,
),
)
.emit();
return false;
}
}
for (_, indices) in seen_params {
if indices.len() > 1 {
let descr = opaque_generics.param_at(indices[0], tcx).kind.descr();
let spans: Vec<_> = indices
.into_iter()
.map(|i| tcx.def_span(opaque_generics.param_at(i, tcx).def_id))
.collect();
tcx.sess
.struct_span_err(span, "non-defining opaque type use in defining scope")
.span_note(spans, &format!("{} used multiple times", descr))
.emit();
return false;
}
}
true
}
struct ReverseMapper<'tcx> {
tcx: TyCtxt<'tcx>,
opaque_type_def_id: DefId,
map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>>,
map_missing_regions_to_empty: bool,
/// initially `Some`, set to `None` once error has been reported
hidden_ty: Option<Ty<'tcx>>,
/// Span of function being checked.
span: Span,
}
impl<'tcx> ReverseMapper<'tcx> {
fn new(
tcx: TyCtxt<'tcx>,
opaque_type_def_id: DefId,
map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>>,
hidden_ty: Ty<'tcx>,
span: Span,
) -> Self {
Self {
tcx,
opaque_type_def_id,
map,
map_missing_regions_to_empty: false,
hidden_ty: Some(hidden_ty),
span,
}
}
fn fold_kind_mapping_missing_regions_to_empty(
&mut self,
kind: GenericArg<'tcx>,
) -> GenericArg<'tcx> {
assert!(!self.map_missing_regions_to_empty);
self.map_missing_regions_to_empty = true;
let kind = kind.fold_with(self);
self.map_missing_regions_to_empty = false;
kind
}
fn fold_kind_normally(&mut self, kind: GenericArg<'tcx>) -> GenericArg<'tcx> {
assert!(!self.map_missing_regions_to_empty);
kind.fold_with(self)
}
}
impl<'tcx> TypeFolder<'tcx> for ReverseMapper<'tcx> {
fn tcx(&self) -> TyCtxt<'tcx> {
self.tcx
}
#[instrument(skip(self), level = "debug")]
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
match *r {
// Ignore bound regions and `'static` regions that appear in the
// type, we only need to remap regions that reference lifetimes
// from the function declaration.
// This would ignore `'r` in a type like `for<'r> fn(&'r u32)`.
ty::ReLateBound(..) | ty::ReStatic => return r,
// If regions have been erased (by writeback), don't try to unerase
// them.
ty::ReErased => return r,
// The regions that we expect from borrow checking.
ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReEmpty(ty::UniverseIndex::ROOT) => {}
ty::ReEmpty(_) | ty::RePlaceholder(_) | ty::ReVar(_) => {
// All of the regions in the type should either have been
// erased by writeback, or mapped back to named regions by
// borrow checking.
bug!("unexpected region kind in opaque type: {:?}", r);
}
}
let generics = self.tcx().generics_of(self.opaque_type_def_id);
match self.map.get(&r.into()).map(|k| k.unpack()) {
Some(GenericArgKind::Lifetime(r1)) => r1,
Some(u) => panic!("region mapped to unexpected kind: {:?}", u),
None if self.map_missing_regions_to_empty => self.tcx.lifetimes.re_root_empty,
None if generics.parent.is_some() => {
if let Some(hidden_ty) = self.hidden_ty.take() {
unexpected_hidden_region_diagnostic(
self.tcx,
self.tcx.def_span(self.opaque_type_def_id),
hidden_ty,
r,
)
.emit();
}
self.tcx.lifetimes.re_root_empty
}
None => {
self.tcx
.sess
.struct_span_err(self.span, "non-defining opaque type use in defining scope")
.span_label(
self.span,
format!(
"lifetime `{}` is part of concrete type but not used in \
parameter list of the `impl Trait` type alias",
r
),
)
.emit();
self.tcx().lifetimes.re_static
}
}
}
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
match *ty.kind() {
ty::Closure(def_id, substs) => {
// I am a horrible monster and I pray for death. When
// we encounter a closure here, it is always a closure
// from within the function that we are currently
// type-checking -- one that is now being encapsulated
// in an opaque type. Ideally, we would
// go through the types/lifetimes that it references
// and treat them just like we would any other type,
// which means we would error out if we find any
// reference to a type/region that is not in the
// "reverse map".
//
// **However,** in the case of closures, there is a
// somewhat subtle (read: hacky) consideration. The
// problem is that our closure types currently include
// all the lifetime parameters declared on the
// enclosing function, even if they are unused by the
// closure itself. We can't readily filter them out,
// so here we replace those values with `'empty`. This
// can't really make a difference to the rest of the
// compiler; those regions are ignored for the
// outlives relation, and hence don't affect trait
// selection or auto traits, and they are erased
// during codegen.
let generics = self.tcx.generics_of(def_id);
let substs = self.tcx.mk_substs(substs.iter().enumerate().map(|(index, kind)| {
if index < generics.parent_count {
// Accommodate missing regions in the parent kinds...
self.fold_kind_mapping_missing_regions_to_empty(kind)
} else {
// ...but not elsewhere.
self.fold_kind_normally(kind)
}
}));
self.tcx.mk_closure(def_id, substs)
}
ty::Generator(def_id, substs, movability) => {
let generics = self.tcx.generics_of(def_id);
let substs = self.tcx.mk_substs(substs.iter().enumerate().map(|(index, kind)| {
if index < generics.parent_count {
// Accommodate missing regions in the parent kinds...
self.fold_kind_mapping_missing_regions_to_empty(kind)
} else {
// ...but not elsewhere.
self.fold_kind_normally(kind)
}
}));
self.tcx.mk_generator(def_id, substs, movability)
}
ty::Param(param) => {
// Look it up in the substitution list.
match self.map.get(&ty.into()).map(|k| k.unpack()) {
// Found it in the substitution list; replace with the parameter from the
// opaque type.
Some(GenericArgKind::Type(t1)) => t1,
Some(u) => panic!("type mapped to unexpected kind: {:?}", u),
None => {
debug!(?param, ?self.map);
self.tcx
.sess
.struct_span_err(
self.span,
&format!(
"type parameter `{}` is part of concrete type but not \
used in parameter list for the `impl Trait` type alias",
ty
),
)
.emit();
self.tcx().ty_error()
}
}
}
_ => ty.super_fold_with(self),
}
}
fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
trace!("checking const {:?}", ct);
// Find a const parameter
match ct.kind() {
ty::ConstKind::Param(..) => {
// Look it up in the substitution list.
match self.map.get(&ct.into()).map(|k| k.unpack()) {
// Found it in the substitution list, replace with the parameter from the
// opaque type.
Some(GenericArgKind::Const(c1)) => c1,
Some(u) => panic!("const mapped to unexpected kind: {:?}", u),
None => {
self.tcx
.sess
.struct_span_err(
self.span,
&format!(
"const parameter `{}` is part of concrete type but not \
used in parameter list for the `impl Trait` type alias",
ct
),
)
.emit();
self.tcx().const_error(ct.ty())
}
}
}
_ => ct,
}
}
}

View file

@ -503,7 +503,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
let root_empty = self
.infcx
.next_nll_region_var(NllRegionVariableOrigin::RootEmptyRegion)
.next_nll_region_var(NllRegionVariableOrigin::Existential { from_forall: true })
.to_region_vid();
UniversalRegions {

View file

@ -63,7 +63,7 @@ impl HumanReadableErrorType {
bundle: Option<Lrc<FluentBundle>>,
fallback_bundle: LazyFallbackBundle,
teach: bool,
terminal_width: Option<usize>,
diagnostic_width: Option<usize>,
macro_backtrace: bool,
) -> EmitterWriter {
let (short, color_config) = self.unzip();
@ -76,7 +76,7 @@ impl HumanReadableErrorType {
short,
teach,
color,
terminal_width,
diagnostic_width,
macro_backtrace,
)
}
@ -710,7 +710,7 @@ pub struct EmitterWriter {
short_message: bool,
teach: bool,
ui_testing: bool,
terminal_width: Option<usize>,
diagnostic_width: Option<usize>,
macro_backtrace: bool,
}
@ -730,7 +730,7 @@ impl EmitterWriter {
fallback_bundle: LazyFallbackBundle,
short_message: bool,
teach: bool,
terminal_width: Option<usize>,
diagnostic_width: Option<usize>,
macro_backtrace: bool,
) -> EmitterWriter {
let dst = Destination::from_stderr(color_config);
@ -742,7 +742,7 @@ impl EmitterWriter {
short_message,
teach,
ui_testing: false,
terminal_width,
diagnostic_width,
macro_backtrace,
}
}
@ -755,7 +755,7 @@ impl EmitterWriter {
short_message: bool,
teach: bool,
colored: bool,
terminal_width: Option<usize>,
diagnostic_width: Option<usize>,
macro_backtrace: bool,
) -> EmitterWriter {
EmitterWriter {
@ -766,7 +766,7 @@ impl EmitterWriter {
short_message,
teach,
ui_testing: false,
terminal_width,
diagnostic_width,
macro_backtrace,
}
}
@ -1615,7 +1615,7 @@ impl EmitterWriter {
width_offset + annotated_file.multiline_depth + 1
};
let column_width = if let Some(width) = self.terminal_width {
let column_width = if let Some(width) = self.diagnostic_width {
width.saturating_sub(code_offset)
} else if self.ui_testing {
DEFAULT_COLUMN_WIDTH

View file

@ -42,7 +42,7 @@ pub struct JsonEmitter {
pretty: bool,
ui_testing: bool,
json_rendered: HumanReadableErrorType,
terminal_width: Option<usize>,
diagnostic_width: Option<usize>,
macro_backtrace: bool,
}
@ -54,7 +54,7 @@ impl JsonEmitter {
fallback_bundle: LazyFallbackBundle,
pretty: bool,
json_rendered: HumanReadableErrorType,
terminal_width: Option<usize>,
diagnostic_width: Option<usize>,
macro_backtrace: bool,
) -> JsonEmitter {
JsonEmitter {
@ -66,7 +66,7 @@ impl JsonEmitter {
pretty,
ui_testing: false,
json_rendered,
terminal_width,
diagnostic_width,
macro_backtrace,
}
}
@ -76,7 +76,7 @@ impl JsonEmitter {
json_rendered: HumanReadableErrorType,
fluent_bundle: Option<Lrc<FluentBundle>>,
fallback_bundle: LazyFallbackBundle,
terminal_width: Option<usize>,
diagnostic_width: Option<usize>,
macro_backtrace: bool,
) -> JsonEmitter {
let file_path_mapping = FilePathMapping::empty();
@ -87,7 +87,7 @@ impl JsonEmitter {
fallback_bundle,
pretty,
json_rendered,
terminal_width,
diagnostic_width,
macro_backtrace,
)
}
@ -100,7 +100,7 @@ impl JsonEmitter {
fallback_bundle: LazyFallbackBundle,
pretty: bool,
json_rendered: HumanReadableErrorType,
terminal_width: Option<usize>,
diagnostic_width: Option<usize>,
macro_backtrace: bool,
) -> JsonEmitter {
JsonEmitter {
@ -112,7 +112,7 @@ impl JsonEmitter {
pretty,
ui_testing: false,
json_rendered,
terminal_width,
diagnostic_width,
macro_backtrace,
}
}
@ -345,7 +345,7 @@ impl Diagnostic {
je.fluent_bundle.clone(),
je.fallback_bundle.clone(),
false,
je.terminal_width,
je.diagnostic_width,
je.macro_backtrace,
)
.ui_testing(je.ui_testing)

View file

@ -4,7 +4,7 @@
//! and use that to decide when one free region outlives another, and so forth.
use rustc_data_structures::transitive_relation::TransitiveRelation;
use rustc_middle::ty::{self, Lift, Region, TyCtxt};
use rustc_middle::ty::{Lift, Region, TyCtxt};
/// Combines a `FreeRegionMap` and a `TyCtxt`.
///
@ -49,7 +49,7 @@ impl<'tcx> FreeRegionMap<'tcx> {
// (with the exception that `'static: 'x` is not notable)
pub fn relate_regions(&mut self, sub: Region<'tcx>, sup: Region<'tcx>) {
debug!("relate_regions(sub={:?}, sup={:?})", sub, sup);
if self.is_free_or_static(sub) && self.is_free(sup) {
if sub.is_free_or_static() && sup.is_free() {
self.relation.add(sub, sup)
}
}
@ -68,7 +68,7 @@ impl<'tcx> FreeRegionMap<'tcx> {
r_a: Region<'tcx>,
r_b: Region<'tcx>,
) -> bool {
assert!(self.is_free_or_static(r_a) && self.is_free_or_static(r_b));
assert!(r_a.is_free_or_static() && r_b.is_free_or_static());
let re_static = tcx.lifetimes.re_static;
if self.check_relation(re_static, r_b) {
// `'a <= 'static` is always true, and not stored in the
@ -85,20 +85,6 @@ impl<'tcx> FreeRegionMap<'tcx> {
r_a == r_b || self.relation.contains(r_a, r_b)
}
/// True for free regions other than `'static`.
pub fn is_free(&self, r: Region<'_>) -> bool {
matches!(*r, ty::ReEarlyBound(_) | ty::ReFree(_))
}
/// True if `r` is a free region or static of the sort that this
/// free region map can be used with.
pub fn is_free_or_static(&self, r: Region<'_>) -> bool {
match *r {
ty::ReStatic => true,
_ => self.is_free(r),
}
}
/// Computes the least-upper-bound of two free regions. In some
/// cases, this is more conservative than necessary, in order to
/// avoid making arbitrary choices. See
@ -110,8 +96,8 @@ impl<'tcx> FreeRegionMap<'tcx> {
r_b: Region<'tcx>,
) -> Region<'tcx> {
debug!("lub_free_regions(r_a={:?}, r_b={:?})", r_a, r_b);
assert!(self.is_free(r_a));
assert!(self.is_free(r_b));
assert!(r_a.is_free());
assert!(r_b.is_free());
let result = if r_a == r_b {
r_a
} else {

View file

@ -47,7 +47,6 @@ pub(crate) fn resolve<'tcx>(
#[derive(Clone)]
pub struct LexicalRegionResolutions<'tcx> {
pub(crate) values: IndexVec<RegionVid, VarValue<'tcx>>,
pub(crate) error_region: ty::Region<'tcx>,
}
#[derive(Copy, Clone, Debug)]
@ -140,7 +139,6 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
/// empty region. The `expansion` phase will grow this larger.
fn construct_var_data(&self, tcx: TyCtxt<'tcx>) -> LexicalRegionResolutions<'tcx> {
LexicalRegionResolutions {
error_region: tcx.lifetimes.re_static,
values: IndexVec::from_fn_n(
|vid| {
let vid_universe = self.var_infos[vid].universe;
@ -310,7 +308,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
// Check for the case where we know that `'b: 'static` -- in that case,
// `a <= b` for all `a`.
let b_free_or_static = self.region_rels.free_regions.is_free_or_static(b);
let b_free_or_static = b.is_free_or_static();
if b_free_or_static && sub_free_regions(tcx.lifetimes.re_static, b) {
return true;
}
@ -320,7 +318,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
// `lub` relationship defined below, since sometimes the "lub"
// is actually the `postdom_upper_bound` (see
// `TransitiveRelation` for more details).
let a_free_or_static = self.region_rels.free_regions.is_free_or_static(a);
let a_free_or_static = a.is_free_or_static();
if a_free_or_static && b_free_or_static {
return sub_free_regions(a, b);
}
@ -864,10 +862,7 @@ impl<'tcx> LexicalRegionResolutions<'tcx> {
where
T: TypeFoldable<'tcx>,
{
tcx.fold_regions(value, |r, _db| match *r {
ty::ReVar(rid) => self.resolve_var(rid),
_ => r,
})
tcx.fold_regions(value, |r, _db| self.resolve_region(tcx, r))
}
fn value(&self, rid: RegionVid) -> &VarValue<'tcx> {
@ -878,12 +873,19 @@ impl<'tcx> LexicalRegionResolutions<'tcx> {
&mut self.values[rid]
}
pub fn resolve_var(&self, rid: RegionVid) -> ty::Region<'tcx> {
let result = match self.values[rid] {
VarValue::Value(r) => r,
VarValue::ErrorValue => self.error_region,
pub(crate) fn resolve_region(
&self,
tcx: TyCtxt<'tcx>,
r: ty::Region<'tcx>,
) -> ty::Region<'tcx> {
let result = match *r {
ty::ReVar(rid) => match self.values[rid] {
VarValue::Value(r) => r,
VarValue::ErrorValue => tcx.lifetimes.re_static,
},
_ => r,
};
debug!("resolve_var({:?}) = {:?}", rid, result);
debug!("resolve_region({:?}) = {:?}", r, result);
result
}
}

View file

@ -466,9 +466,6 @@ pub enum NllRegionVariableOrigin {
/// from a `for<'a> T` binder). Meant to represent "any region".
Placeholder(ty::PlaceholderRegion),
/// The variable we create to represent `'empty(U0)`.
RootEmptyRegion,
Existential {
/// If this is true, then this variable was created to represent a lifetime
/// bound in a `for` binder. For example, it might have been created to
@ -1250,7 +1247,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
};
let lexical_region_resolutions = LexicalRegionResolutions {
error_region: self.tcx.lifetimes.re_static,
values: rustc_index::vec::IndexVec::from_elem_n(
crate::infer::lexical_region_resolve::VarValue::Value(self.tcx.lifetimes.re_erased),
var_infos.len(),

View file

@ -206,13 +206,13 @@ impl<'a, 'tcx> FallibleTypeFolder<'tcx> for FullTypeResolver<'a, 'tcx> {
fn try_fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
match *r {
ty::ReVar(rid) => Ok(self
ty::ReVar(_) => Ok(self
.infcx
.lexical_region_resolutions
.borrow()
.as_ref()
.expect("region resolution not performed")
.resolve_var(rid)),
.resolve_region(self.infcx.tcx, r)),
_ => Ok(r),
}
}

View file

@ -689,7 +689,6 @@ fn test_debugging_options_tracking_hash() {
untracked!(span_debug, true);
untracked!(span_free_formats, true);
untracked!(temps_dir, Some(String::from("abc")));
untracked!(terminal_width, Some(80));
untracked!(threads, 99);
untracked!(time, true);
untracked!(time_llvm_passes, true);

View file

@ -1048,6 +1048,8 @@ impl BasicBlock {
///////////////////////////////////////////////////////////////////////////
// BasicBlockData
/// Data for a basic block, including a list of its statements.
///
/// See [`BasicBlock`] for documentation on what basic blocks are at a high level.
#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
pub struct BasicBlockData<'tcx> {
@ -1079,7 +1081,7 @@ impl<'tcx> BasicBlockData<'tcx> {
/// Accessor for terminator.
///
/// Terminator may not be None after construction of the basic block is complete. This accessor
/// provides a convenience way to reach the terminator.
/// provides a convenient way to reach the terminator.
#[inline]
pub fn terminator(&self) -> &Terminator<'tcx> {
self.terminator.as_ref().expect("invalid terminator state")
@ -1286,6 +1288,7 @@ impl<O: fmt::Debug> fmt::Debug for AssertKind<O> {
///////////////////////////////////////////////////////////////////////////
// Statements
/// A statement in a basic block, including information about its source code.
#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
pub struct Statement<'tcx> {
pub source_info: SourceInfo,

View file

@ -1570,6 +1570,19 @@ impl<'tcx> Region<'tcx> {
_ => bug!("free_region_binding_scope invoked on inappropriate region: {:?}", self),
}
}
/// True for free regions other than `'static`.
pub fn is_free(self) -> bool {
matches!(*self, ty::ReEarlyBound(_) | ty::ReFree(_))
}
/// True if `self` is a free region or static.
pub fn is_free_or_static(self) -> bool {
match *self {
ty::ReStatic => true,
_ => self.is_free(),
}
}
}
/// Type utilities

View file

@ -726,6 +726,7 @@ impl Default for Options {
prints: Vec::new(),
cg: Default::default(),
error_format: ErrorOutputType::default(),
diagnostic_width: None,
externs: Externs(BTreeMap::new()),
crate_name: None,
libs: Vec::new(),
@ -1427,6 +1428,12 @@ pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
never = never colorize output",
"auto|always|never",
),
opt::opt_s(
"",
"diagnostic-width",
"Inform rustc of the width of the output so that diagnostics can be truncated to fit",
"WIDTH",
),
opt::multi_s(
"",
"remap-path-prefix",
@ -2202,6 +2209,10 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
let error_format = parse_error_format(matches, color, json_rendered);
let diagnostic_width = matches.opt_get("diagnostic-width").unwrap_or_else(|_| {
early_error(error_format, "`--diagnostic-width` must be an positive integer");
});
let unparsed_crate_types = matches.opt_strs("crate-type");
let crate_types = parse_crate_types_from_list(unparsed_crate_types)
.unwrap_or_else(|e| early_error(error_format, &e));
@ -2474,6 +2485,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
prints,
cg,
error_format,
diagnostic_width,
externs,
unstable_features: UnstableFeatures::from_environment(crate_name.as_deref()),
crate_name,

View file

@ -170,6 +170,7 @@ top_level_options!(
test: bool [TRACKED],
error_format: ErrorOutputType [UNTRACKED],
diagnostic_width: Option<usize> [UNTRACKED],
/// If `Some`, enable incremental compilation, using the given
/// directory to store intermediate results.
@ -1388,6 +1389,8 @@ options! {
"panic strategy for out-of-memory handling"),
osx_rpath_install_name: bool = (false, parse_bool, [TRACKED],
"pass `-install_name @rpath/...` to the macOS linker (default: no)"),
diagnostic_width: Option<usize> = (None, parse_opt_number, [UNTRACKED],
"set the current output width for diagnostic truncation"),
panic_abort_tests: bool = (false, parse_bool, [TRACKED],
"support compiling tests with panic=abort (default: no)"),
panic_in_drop: PanicStrategy = (PanicStrategy::Unwind, parse_panic_strategy, [TRACKED],
@ -1514,8 +1517,6 @@ options! {
"show extended diagnostic help (default: no)"),
temps_dir: Option<String> = (None, parse_opt_string, [UNTRACKED],
"the directory the intermediate files are written to"),
terminal_width: Option<usize> = (None, parse_opt_number, [UNTRACKED],
"set the current terminal width"),
// Diagnostics are considered side-effects of a query (see `QuerySideEffects`) and are saved
// alongside query results and changes to translation options can affect diagnostics - so
// translation options should be tracked.

View file

@ -1162,7 +1162,7 @@ fn default_emitter(
fallback_bundle,
short,
sopts.debugging_opts.teach,
sopts.debugging_opts.terminal_width,
sopts.diagnostic_width,
macro_backtrace,
),
Some(dst) => EmitterWriter::new(
@ -1173,7 +1173,7 @@ fn default_emitter(
short,
false, // no teach messages when writing to a buffer
false, // no colors when writing to a buffer
None, // no terminal width
None, // no diagnostic width
macro_backtrace,
),
};
@ -1188,7 +1188,7 @@ fn default_emitter(
fallback_bundle,
pretty,
json_rendered,
sopts.debugging_opts.terminal_width,
sopts.diagnostic_width,
macro_backtrace,
)
.ui_testing(sopts.debugging_opts.ui_testing),
@ -1202,7 +1202,7 @@ fn default_emitter(
fallback_bundle,
pretty,
json_rendered,
sopts.debugging_opts.terminal_width,
sopts.diagnostic_width,
macro_backtrace,
)
.ui_testing(sopts.debugging_opts.ui_testing),

View file

@ -37,5 +37,4 @@ extern crate smallvec;
pub mod autoderef;
pub mod infer;
pub mod opaque_types;
pub mod traits;

View file

@ -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()
}

View file

@ -1,5 +1,4 @@
use crate::infer::InferCtxt;
use crate::opaque_types::required_region_bounds;
use crate::traits;
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
@ -810,3 +809,63 @@ pub fn object_region_bounds<'tcx>(
required_region_bounds(tcx, open_ty, predicates)
}
/// Given a set of predicates that apply to an object type, returns
/// the region bounds that the (erased) `Self` type must
/// outlive. Precisely *because* the `Self` type is erased, the
/// parameter `erased_self_ty` must be supplied to indicate what type
/// has been used to represent `Self` in the predicates
/// themselves. This should really be a unique type; `FreshTy(0)` is a
/// popular choice.
///
/// N.B., in some cases, particularly around higher-ranked bounds,
/// this function returns a kind of conservative approximation.
/// That is, all regions returned by this function are definitely
/// required, but there may be other region bounds that are not
/// returned, as well as requirements like `for<'a> T: 'a`.
///
/// Requires that trait definitions have been processed so that we can
/// elaborate predicates and walk supertraits.
#[instrument(skip(tcx, predicates), level = "debug")]
pub(crate) fn required_region_bounds<'tcx>(
tcx: TyCtxt<'tcx>,
erased_self_ty: Ty<'tcx>,
predicates: impl Iterator<Item = ty::Predicate<'tcx>>,
) -> Vec<ty::Region<'tcx>> {
assert!(!erased_self_ty.has_escaping_bound_vars());
traits::elaborate_predicates(tcx, predicates)
.filter_map(|obligation| {
debug!(?obligation);
match obligation.predicate.kind().skip_binder() {
ty::PredicateKind::Projection(..)
| ty::PredicateKind::Trait(..)
| ty::PredicateKind::Subtype(..)
| ty::PredicateKind::Coerce(..)
| ty::PredicateKind::WellFormed(..)
| ty::PredicateKind::ObjectSafe(..)
| ty::PredicateKind::ClosureKind(..)
| ty::PredicateKind::RegionOutlives(..)
| ty::PredicateKind::ConstEvaluatable(..)
| ty::PredicateKind::ConstEquate(..)
| ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ref t, ref r)) => {
// Search for a bound of the form `erased_self_ty
// : 'a`, but be wary of something like `for<'a>
// erased_self_ty : 'a` (we interpret a
// higher-ranked bound like that as 'static,
// though at present the code in `fulfill.rs`
// considers such bounds to be unsatisfiable, so
// it's kind of a moot point since you could never
// construct such an object, but this seems
// correct even if that code changes).
if t == &erased_self_ty && !r.has_escaping_bound_vars() {
Some(*r)
} else {
None
}
}
}
})
.collect()
}

View file

@ -13,8 +13,6 @@ use crate::future::Future;
/// on all futures.
///
/// ```no_run
/// #![feature(into_future)]
///
/// use std::future::IntoFuture;
///
/// # async fn foo() {
@ -33,8 +31,6 @@ use crate::future::Future;
/// multiple times before being `.await`ed.
///
/// ```rust
/// #![feature(into_future)]
///
/// use std::future::{ready, Ready, IntoFuture};
///
/// /// Eventually multiply two numbers
@ -91,8 +87,6 @@ use crate::future::Future;
/// `IntoFuture::into_future` to obtain an instance of `Future`:
///
/// ```rust
/// #![feature(into_future)]
///
/// use std::future::IntoFuture;
///
/// /// Convert the output of a future to a string.
@ -104,14 +98,14 @@ use crate::future::Future;
/// format!("{:?}", fut.await)
/// }
/// ```
#[unstable(feature = "into_future", issue = "67644")]
#[stable(feature = "into_future", since = "1.64.0")]
pub trait IntoFuture {
/// The output that the future will produce on completion.
#[unstable(feature = "into_future", issue = "67644")]
#[stable(feature = "into_future", since = "1.64.0")]
type Output;
/// Which kind of future are we turning this into?
#[unstable(feature = "into_future", issue = "67644")]
#[stable(feature = "into_future", since = "1.64.0")]
type IntoFuture: Future<Output = Self::Output>;
/// Creates a future from a value.
@ -121,8 +115,6 @@ pub trait IntoFuture {
/// Basic usage:
///
/// ```no_run
/// #![feature(into_future)]
///
/// use std::future::IntoFuture;
///
/// # async fn foo() {
@ -131,12 +123,12 @@ pub trait IntoFuture {
/// assert_eq!("meow", fut.await);
/// # }
/// ```
#[unstable(feature = "into_future", issue = "67644")]
#[stable(feature = "into_future", since = "1.64.0")]
#[lang = "into_future"]
fn into_future(self) -> Self::IntoFuture;
}
#[unstable(feature = "into_future", issue = "67644")]
#[stable(feature = "into_future", since = "1.64.0")]
impl<F: Future> IntoFuture for F {
type Output = F::Output;
type IntoFuture = F;

View file

@ -29,7 +29,7 @@ pub use self::future::Future;
#[unstable(feature = "future_join", issue = "91642")]
pub use self::join::join;
#[unstable(feature = "into_future", issue = "67644")]
#[stable(feature = "into_future", since = "1.64.0")]
pub use into_future::IntoFuture;
#[stable(feature = "future_readiness_fns", since = "1.48.0")]

View file

@ -949,6 +949,7 @@ impl<'a> Builder<'a> {
}
pub(crate) fn download_component(&self, url: &str, dest_path: &Path, help_on_error: &str) {
self.verbose(&format!("download {url}"));
// Use a temporary file in case we crash while downloading, to avoid a corrupt download in cache/.
let tempfile = self.tempdir().join(dest_path.file_name().unwrap());
// While bootstrap itself only supports http and https downloads, downstream forks might

View file

@ -1558,7 +1558,7 @@ fn download_ci_rustc(builder: &Builder<'_>, commit: &str) {
builder.fix_bin_or_dylib(&bin_root.join("bin").join("rustc"));
builder.fix_bin_or_dylib(&bin_root.join("bin").join("rustdoc"));
let lib_dir = bin_root.join("lib");
for lib in t!(fs::read_dir(lib_dir)) {
for lib in t!(fs::read_dir(&lib_dir), lib_dir.display().to_string()) {
let lib = t!(lib);
if lib.path().extension() == Some(OsStr::new("so")) {
builder.fix_bin_or_dylib(&lib.path());
@ -1634,6 +1634,7 @@ fn download_component(
}
Some(sha256)
} else if tarball.exists() {
builder.unpack(&tarball, &bin_root, prefix);
return;
} else {
None

View file

@ -73,6 +73,8 @@ pub(crate) struct Options {
pub(crate) proc_macro_crate: bool,
/// How to format errors and warnings.
pub(crate) error_format: ErrorOutputType,
/// Width of output buffer to truncate errors appropriately.
pub(crate) diagnostic_width: Option<usize>,
/// Library search paths to hand to the compiler.
pub(crate) libs: Vec<SearchPath>,
/// Library search paths strings to hand to the compiler.
@ -331,11 +333,12 @@ impl Options {
let config::JsonConfig { json_rendered, json_unused_externs, .. } =
config::parse_json(matches);
let error_format = config::parse_error_format(matches, color, json_rendered);
let diagnostic_width = matches.opt_get("diagnostic-width").unwrap_or_default();
let codegen_options = CodegenOptions::build(matches, error_format);
let debugging_opts = DebuggingOptions::build(matches, error_format);
let diag = new_handler(error_format, None, &debugging_opts);
let diag = new_handler(error_format, None, diagnostic_width, &debugging_opts);
// check for deprecated options
check_deprecated_options(matches, &diag);
@ -699,6 +702,7 @@ impl Options {
input,
proc_macro_crate,
error_format,
diagnostic_width,
libs,
lib_strs,
externs,

View file

@ -154,6 +154,7 @@ impl<'tcx> DocContext<'tcx> {
pub(crate) fn new_handler(
error_format: ErrorOutputType,
source_map: Option<Lrc<source_map::SourceMap>>,
diagnostic_width: Option<usize>,
debugging_opts: &DebuggingOptions,
) -> rustc_errors::Handler {
let fallback_bundle =
@ -169,7 +170,7 @@ pub(crate) fn new_handler(
fallback_bundle,
short,
debugging_opts.teach,
debugging_opts.terminal_width,
diagnostic_width,
false,
)
.ui_testing(debugging_opts.ui_testing),
@ -187,7 +188,7 @@ pub(crate) fn new_handler(
fallback_bundle,
pretty,
json_rendered,
debugging_opts.terminal_width,
diagnostic_width,
false,
)
.ui_testing(debugging_opts.ui_testing),
@ -208,6 +209,7 @@ pub(crate) fn create_config(
crate_name,
proc_macro_crate,
error_format,
diagnostic_width,
libs,
externs,
mut cfgs,
@ -266,6 +268,7 @@ pub(crate) fn create_config(
actually_rustdoc: true,
debugging_opts,
error_format,
diagnostic_width,
edition,
describe_lints,
crate_name,

View file

@ -462,6 +462,14 @@ fn opts() -> Vec<RustcOptGroup> {
"human|json|short",
)
}),
unstable("diagnostic-width", |o| {
o.optopt(
"",
"diagnostic-width",
"Provide width of the output for truncated error messages",
"WIDTH",
)
}),
stable("json", |o| {
o.optopt("", "json", "Configure the structure of JSON diagnostics", "CONFIG")
}),
@ -733,7 +741,12 @@ fn run_renderer<'tcx, T: formats::FormatRenderer<'tcx>>(
}
fn main_options(options: config::Options) -> MainResult {
let diag = core::new_handler(options.error_format, None, &options.debugging_opts);
let diag = core::new_handler(
options.error_format,
None,
options.diagnostic_width,
&options.debugging_opts,
);
match (options.should_test, options.markdown_input()) {
(true, true) => return wrap_return(&diag, markdown::test(options)),

View file

@ -110,6 +110,9 @@ Options:
never = never colorize output
--error-format human|json|short
How errors and other messages are produced
--diagnostic-width WIDTH
Provide width of the output for truncated error
messages
--json CONFIG Configure the structure of JSON diagnostics
--disable-minification
Disable minification applied on JS files

View 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

View 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

View file

@ -1,8 +1,6 @@
// run-pass
// aux-build: issue-72470-lib.rs
// edition:2021
#![feature(into_future)]
extern crate issue_72470_lib;
use std::{future::{Future, IntoFuture}, pin::Pin};

View 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
}

View 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
}

View file

@ -24,7 +24,7 @@ This error occurs when an expression was used in a place where the compiler
expected an expression of a different type. It can occur in several cases, the
most common being when calling a function and passing an argument which has a
different type than the matching type in the function declaration.
"},"level":"error","spans":[{"file_name":"$DIR/flag-json.rs","byte_start":244,"byte_end":246,"line_start":7,"line_end":7,"column_start":17,"column_end":19,"is_primary":true,"text":[{"text":" let _: () = 42;","highlight_start":17,"highlight_end":19}],"label":"expected `()`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/flag-json.rs","byte_start":239,"byte_end":241,"line_start":7,"line_end":7,"column_start":12,"column_end":14,"is_primary":false,"text":[{"text":" let _: () = 42;","highlight_start":12,"highlight_end":14}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":"error[E0308]: mismatched types
"},"level":"error","spans":[{"file_name":"$DIR/flag-json.rs","byte_start":243,"byte_end":245,"line_start":7,"line_end":7,"column_start":17,"column_end":19,"is_primary":true,"text":[{"text":" let _: () = 42;","highlight_start":17,"highlight_end":19}],"label":"expected `()`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/flag-json.rs","byte_start":238,"byte_end":240,"line_start":7,"line_end":7,"column_start":12,"column_end":14,"is_primary":false,"text":[{"text":" let _: () = 42;","highlight_start":12,"highlight_end":14}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":"error[E0308]: mismatched types
--> $DIR/flag-json.rs:7:17
|
LL | ..._: () = 42;

View file

@ -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
}

View file

@ -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
}

View file

@ -301,7 +301,7 @@ fn in_attributes_expansion(expr: &Expr<'_>) -> bool {
use rustc_span::hygiene::MacroKind;
if expr.span.from_expansion() {
let data = expr.span.ctxt().outer_expn_data();
matches!(data.kind, ExpnKind::Macro(MacroKind::Attr, _))
matches!(data.kind, ExpnKind::Macro(MacroKind::Attr|MacroKind::Derive, _))
} else {
false
}

View file

@ -44,6 +44,12 @@ fn in_struct_field() {
s._underscore_field += 1;
}
/// Tests that we do not lint if the struct field is used in code created with derive.
#[derive(Clone, Debug)]
pub struct UnderscoreInStruct {
_foo: u32,
}
/// Tests that we do not lint if the underscore is not a prefix
fn non_prefix_underscore(some_foo: u32) -> u32 {
some_foo + 1

View file

@ -31,7 +31,7 @@ LL | s._underscore_field += 1;
| ^^^^^^^^^^^^^^^^^^^
error: used binding `_i` which is prefixed with an underscore. A leading underscore signals that a binding will not be used
--> $DIR/used_underscore_binding.rs:99:16
--> $DIR/used_underscore_binding.rs:105:16
|
LL | uses_i(_i);
| ^^