if i != 0 || j != lines.len() { Some((i, j)) } else { None }
}
- fn get_horizontal_trim(lines: &[&str], kind: CommentKind) -> Option<usize> {
+ fn get_horizontal_trim<'a>(lines: &'a [&str], kind: CommentKind) -> Option<String> {
let mut i = usize::MAX;
let mut first = true;
// present. However, we first need to strip the empty lines so they don't get in the middle
// when we try to compute the "horizontal trim".
let lines = if kind == CommentKind::Block {
- let mut i = 0;
+ // Whatever happens, we skip the first line.
+ let mut i = if lines[0].trim_start().starts_with('*') { 0 } else { 1 };
let mut j = lines.len();
while i < j && lines[i].trim().is_empty() {
return None;
}
}
- Some(i)
+ if lines.is_empty() { None } else { Some(lines[0][..i].into()) }
}
let data_s = data.as_str();
changes = true;
// remove a "[ \t]*\*" block from each line, if possible
for line in lines.iter_mut() {
- if horizontal + 1 < line.len() {
- *line = &line[horizontal + 1..];
+ if let Some(tmp) = line.strip_prefix(&horizontal) {
+ *line = tmp;
+ if kind == CommentKind::Block
+ && (*line == "*" || line.starts_with("* ") || line.starts_with("**"))
+ {
+ *line = &line[1..];
+ }
}
}
}
create_default_session_globals_then(|| {
let comment = "\n let a: *i32;\n *a = 5;\n";
let stripped = beautify_doc_string(Symbol::intern(comment), CommentKind::Block);
- assert_eq!(stripped.as_str(), " let a: *i32;\n *a = 5;");
+ assert_eq!(stripped.as_str(), "let a: *i32;\n*a = 5;");
})
}
assert_eq!(stripped.as_str(), "!test");
})
}
+
+#[test]
+fn test_doc_blocks() {
+ create_default_session_globals_then(|| {
+ let stripped =
+ beautify_doc_string(Symbol::intern(" # Returns\n *\n "), CommentKind::Block);
+ assert_eq!(stripped.as_str(), " # Returns\n\n");
+
+ let stripped = beautify_doc_string(
+ Symbol::intern("\n * # Returns\n *\n "),
+ CommentKind::Block,
+ );
+ assert_eq!(stripped.as_str(), " # Returns\n\n");
+
+ let stripped = beautify_doc_string(Symbol::intern("\n * a\n "), CommentKind::Block);
+ assert_eq!(stripped.as_str(), " a\n");
+ })
+}
"thiscall-unwind ABI is experimental and subject to change"
);
}
+ "cdecl-unwind" => {
+ gate_feature_post!(
+ &self,
+ c_unwind,
+ span,
+ "cdecl-unwind ABI is experimental and subject to change"
+ );
+ }
+ "fastcall-unwind" => {
+ gate_feature_post!(
+ &self,
+ c_unwind,
+ span,
+ "fastcall-unwind ABI is experimental and subject to change"
+ );
+ }
+ "vectorcall-unwind" => {
+ gate_feature_post!(
+ &self,
+ c_unwind,
+ span,
+ "vectorcall-unwind ABI is experimental and subject to change"
+ );
+ }
+ "aapcs-unwind" => {
+ gate_feature_post!(
+ &self,
+ c_unwind,
+ span,
+ "aapcs-unwind ABI is experimental and subject to change"
+ );
+ }
+ "win64-unwind" => {
+ gate_feature_post!(
+ &self,
+ c_unwind,
+ span,
+ "win64-unwind ABI is experimental and subject to change"
+ );
+ }
+ "sysv64-unwind" => {
+ gate_feature_post!(
+ &self,
+ c_unwind,
+ span,
+ "sysv64-unwind ABI is experimental and subject to change"
+ );
+ }
"wasm" => {
gate_feature_post!(
&self,
) -> &'tcx BorrowCheckResult<'tcx> {
let (input_body, promoted) = tcx.mir_promoted(def);
debug!("run query mir_borrowck: {}", tcx.def_path_str(def.did.to_def_id()));
+ let hir_owner = tcx.hir().local_def_id_to_hir_id(def.did).owner;
- let opt_closure_req = tcx.infer_ctxt().with_opaque_type_inference(def.did).enter(|infcx| {
+ let opt_closure_req = tcx.infer_ctxt().with_opaque_type_inference(hir_owner).enter(|infcx| {
let input_body: &Body<'_> = &input_body.borrow();
let promoted: &IndexVec<_, _> = &promoted.borrow();
do_mir_borrowck(&infcx, input_body, promoted, false).0
/// If `return_body_with_facts` is true, then return the body with non-erased
/// region ids on which the borrow checking was performed together with Polonius
/// facts.
-#[instrument(skip(infcx, input_body, input_promoted), level = "debug")]
+#[instrument(skip(infcx, input_body, input_promoted), fields(id=?input_body.source.with_opt_param().as_local().unwrap()), level = "debug")]
fn do_mir_borrowck<'a, 'tcx>(
infcx: &InferCtxt<'a, 'tcx>,
input_body: &Body<'tcx>,
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::vec_map::VecMap;
use rustc_hir::OpaqueTyOrigin;
-use rustc_infer::infer::opaque_types::OpaqueTypeDecl;
use rustc_infer::infer::InferCtxt;
use rustc_middle::ty::subst::GenericArgKind;
use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable};
pub(crate) fn infer_opaque_types(
&self,
infcx: &InferCtxt<'_, 'tcx>,
- opaque_ty_decls: VecMap<OpaqueTypeKey<'tcx>, OpaqueTypeDecl<'tcx>>,
+ opaque_ty_decls: VecMap<OpaqueTypeKey<'tcx>, (Ty<'tcx>, Span, OpaqueTyOrigin)>,
span: Span,
) -> VecMap<OpaqueTypeKey<'tcx>, Ty<'tcx>> {
opaque_ty_decls
.into_iter()
- .filter_map(|(opaque_type_key, decl)| {
+ .map(|(opaque_type_key, (concrete_type, decl_span, origin))| {
let substs = opaque_type_key.substs;
- let concrete_type = decl.concrete_ty;
+ // FIXME: why are the spans in decl_span often DUMMY_SP?
+ let span = decl_span.substitute_dummy(span);
debug!(?concrete_type, ?substs);
let mut subst_regions = vec![self.universal_regions.fr_static];
let universal_substs = infcx.tcx.fold_regions(substs, &mut false, |region, _| {
- let vid = self.universal_regions.to_region_vid(region);
- subst_regions.push(vid);
- self.definitions[vid].external_name.unwrap_or_else(|| {
- infcx
- .tcx
- .sess
- .delay_span_bug(span, "opaque type with non-universal region substs");
- infcx.tcx.lifetimes.re_static
- })
+ if let ty::RePlaceholder(..) = region {
+ // Higher kinded regions don't need remapping, they don't refer to anything outside of this the substs.
+ return region;
+ }
+ let vid = self.to_region_vid(region);
+ trace!(?vid);
+ let scc = self.constraint_sccs.scc(vid);
+ trace!(?scc);
+ match self.scc_values.universal_regions_outlived_by(scc).find_map(|lb| {
+ self.eval_equal(vid, lb).then_some(self.definitions[lb].external_name?)
+ }) {
+ Some(region) => {
+ let vid = self.universal_regions.to_region_vid(region);
+ subst_regions.push(vid);
+ region
+ }
+ None => {
+ subst_regions.push(vid);
+ infcx.tcx.sess.delay_span_bug(
+ span,
+ "opaque type with non-universal region substs",
+ );
+ infcx.tcx.lifetimes.re_static
+ }
+ }
});
subst_regions.sort();
span,
);
- check_opaque_type_parameter_valid(
- infcx.tcx,
+ (
opaque_type_key,
- OpaqueTypeDecl { concrete_ty: remapped_type, ..decl },
+ if check_opaque_type_parameter_valid(infcx.tcx, opaque_type_key, origin, span) {
+ remapped_type
+ } else {
+ infcx.tcx.ty_error()
+ },
)
- .then_some((opaque_type_key, remapped_type))
})
.collect()
}
fn check_opaque_type_parameter_valid(
tcx: TyCtxt<'_>,
opaque_type_key: OpaqueTypeKey<'_>,
- decl: OpaqueTypeDecl<'_>,
+ origin: OpaqueTyOrigin,
+ span: Span,
) -> bool {
- match decl.origin {
+ match origin {
// No need to check return position impl trait (RPIT)
// because for type and const parameters they are correct
// by construction: we convert
// Check these
OpaqueTyOrigin::TyAlias => {}
}
- let span = decl.definition_span;
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() {
// Return types are a bit more complex. They may contain opaque `impl Trait` types.
let mir_output_ty = body.local_decls[RETURN_PLACE].ty;
let output_span = body.local_decls[RETURN_PLACE].source_info.span;
- if let Err(terr) = self.eq_opaque_type_and_type(
- mir_output_ty,
+ if let Err(terr) = self.eq_types(
normalized_output_ty,
+ mir_output_ty,
Locations::All(output_span),
ConstraintCategory::BoringNoLocation,
) {
let user_provided_output_ty = user_provided_sig.output();
let user_provided_output_ty =
self.normalize(user_provided_output_ty, Locations::All(output_span));
- if let Err(err) = self.eq_opaque_type_and_type(
- mir_output_ty,
+ if let Err(err) = self.eq_types(
user_provided_output_ty,
+ mir_output_ty,
Locations::All(output_span),
ConstraintCategory::BoringNoLocation,
) {
use either::Either;
+use hir::OpaqueTyOrigin;
use rustc_data_structures::frozen::Frozen;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::vec_map::VecMap;
use rustc_hir::lang_items::LangItem;
use rustc_index::vec::{Idx, IndexVec};
use rustc_infer::infer::canonical::QueryRegionConstraints;
-use rustc_infer::infer::opaque_types::OpaqueTypeDecl;
use rustc_infer::infer::outlives::env::RegionBoundPairs;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::{
use rustc_trait_selection::traits::query::type_op;
use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp;
use rustc_trait_selection::traits::query::Fallible;
-use rustc_trait_selection::traits::{self, ObligationCause, PredicateObligations};
+use rustc_trait_selection::traits::{self, ObligationCause};
use rustc_const_eval::transform::{
check_consts::ConstCx, promote_consts::is_const_fn_in_array_repeat_expression,
$context.last_span,
&format!(
"broken MIR in {:?} ({:?}): {}",
- $context.body.source.def_id(),
+ $context.body().source.def_id(),
$elem,
format_args!($($message)*),
),
liveness::generate(&mut cx, body, elements, flow_inits, move_data, location_table);
translate_outlives_facts(&mut cx);
- let opaque_type_values = mem::take(&mut infcx.inner.borrow_mut().opaque_types);
+ let opaque_type_values =
+ infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
opaque_type_values
.into_iter()
- .filter_map(|(opaque_type_key, mut decl)| {
- decl.concrete_ty = infcx.resolve_vars_if_possible(decl.concrete_ty);
+ .map(|(opaque_type_key, decl)| {
+ cx.fully_perform_op(
+ Locations::All(body.span),
+ ConstraintCategory::OpaqueType,
+ CustomTypeOp::new(
+ |infcx| {
+ infcx.register_member_constraints(
+ param_env,
+ opaque_type_key,
+ decl.hidden_type.ty,
+ decl.hidden_type.span,
+ );
+ Ok(InferOk { value: (), obligations: vec![] })
+ },
+ || "opaque_type_map".to_string(),
+ ),
+ )
+ .unwrap();
+ let mut hidden_type = infcx.resolve_vars_if_possible(decl.hidden_type.ty);
trace!(
"finalized opaque type {:?} to {:#?}",
opaque_type_key,
- decl.concrete_ty.kind()
+ hidden_type.kind()
);
- if decl.concrete_ty.has_infer_types_or_consts() {
+ if hidden_type.has_infer_types_or_consts() {
infcx.tcx.sess.delay_span_bug(
- body.span,
- &format!("could not resolve {:#?}", decl.concrete_ty.kind()),
+ decl.hidden_type.span,
+ &format!("could not resolve {:#?}", hidden_type.kind()),
);
- decl.concrete_ty = infcx.tcx.ty_error();
+ hidden_type = infcx.tcx.ty_error();
}
- let concrete_is_opaque = if let ty::Opaque(def_id, _) = decl.concrete_ty.kind()
- {
- *def_id == opaque_type_key.def_id
- } else {
- false
- };
- if concrete_is_opaque {
- // We're using an opaque `impl Trait` type without
- // 'revealing' it. For example, code like this:
- //
- // type Foo = impl Debug;
- // fn foo1() -> Foo { ... }
- // fn foo2() -> Foo { foo1() }
- //
- // In `foo2`, we're not revealing the type of `Foo` - we're
- // just treating it as the opaque type.
- //
- // When this occurs, we do *not* want to try to equate
- // the concrete type with the underlying defining type
- // of the opaque type - this will always fail, since
- // the defining type of an opaque type is always
- // some other type (e.g. not itself)
- // Essentially, none of the normal obligations apply here -
- // we're just passing around some unknown opaque type,
- // without actually looking at the underlying type it
- // gets 'revealed' into
- debug!(
- "eq_opaque_type_and_type: non-defining use of {:?}",
- opaque_type_key.def_id,
- );
- None
- } else {
- Some((opaque_type_key, decl))
- }
+ (opaque_type_key, (hidden_type, decl.hidden_type.span, decl.origin))
})
.collect()
},
borrowck_context,
);
let errors_reported = {
- let mut verifier = TypeVerifier::new(&mut checker, body, promoted);
+ let mut verifier = TypeVerifier::new(&mut checker, promoted);
verifier.visit_body(&body);
verifier.errors_reported
};
/// is a problem.
struct TypeVerifier<'a, 'b, 'tcx> {
cx: &'a mut TypeChecker<'b, 'tcx>,
- body: &'b Body<'tcx>,
promoted: &'b IndexVec<Promoted, Body<'tcx>>,
last_span: Span,
errors_reported: bool,
fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
self.super_rvalue(rvalue, location);
- let rval_ty = rvalue.ty(self.body, self.tcx());
+ let rval_ty = rvalue.ty(self.body(), self.tcx());
self.sanitize_type(rvalue, rval_ty);
}
impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
fn new(
cx: &'a mut TypeChecker<'b, 'tcx>,
- body: &'b Body<'tcx>,
promoted: &'b IndexVec<Promoted, Body<'tcx>>,
) -> Self {
- TypeVerifier { body, promoted, cx, last_span: body.span, errors_reported: false }
+ TypeVerifier { promoted, last_span: cx.body.span, cx, errors_reported: false }
+ }
+
+ fn body(&self) -> &Body<'tcx> {
+ self.cx.body
}
fn tcx(&self) -> TyCtxt<'tcx> {
) -> PlaceTy<'tcx> {
debug!("sanitize_place: {:?}", place);
- let mut place_ty = PlaceTy::from_ty(self.body.local_decls[place.local].ty);
+ let mut place_ty = PlaceTy::from_ty(self.body().local_decls[place.local].ty);
for elem in place.projection.iter() {
if place_ty.variant_index.is_none() {
// checker on the promoted MIR, then transfer the constraints back to
// the main MIR, changing the locations to the provided location.
- let parent_body = mem::replace(&mut self.body, promoted_body);
+ let parent_body = mem::replace(&mut self.cx.body, promoted_body);
// Use new sets of constraints and closure bounds so that we can
// modify their locations.
self.cx.typeck_mir(promoted_body);
}
- self.body = parent_body;
+ self.cx.body = parent_body;
// Merge the outlives constraints back in, at the given location.
swap_constraints(self);
}))
}
ProjectionElem::Index(i) => {
- let index_ty = Place::from(i).ty(self.body, tcx).ty;
+ let index_ty = Place::from(i).ty(self.body(), tcx).ty;
if index_ty != tcx.types.usize {
PlaceTy::from_ty(span_mirbug_and_err!(self, i, "index by non-usize {:?}", i))
} else {
crate struct MirTypeckResults<'tcx> {
crate constraints: MirTypeckRegionConstraints<'tcx>,
crate universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
- crate opaque_type_values: VecMap<OpaqueTypeKey<'tcx>, OpaqueTypeDecl<'tcx>>,
+ crate opaque_type_values: VecMap<OpaqueTypeKey<'tcx>, (Ty<'tcx>, Span, OpaqueTyOrigin)>,
}
/// A collection of region constraints that must be satisfied for the
checker
}
+ fn body(&self) -> &Body<'tcx> {
+ self.body
+ }
+
fn unsized_feature_enabled(&self) -> bool {
let features = self.tcx().features();
features.unsized_locals || features.unsized_fn_params
}
/// Equate the inferred type and the annotated type for user type annotations
+ #[instrument(skip(self), level = "debug")]
fn check_user_type_annotations(&mut self) {
- debug!(
- "check_user_type_annotations: user_type_annotations={:?}",
- self.user_type_annotations
- );
+ debug!(?self.user_type_annotations);
for user_annotation in self.user_type_annotations {
let CanonicalUserTypeAnnotation { span, ref user_ty, inferred_ty } = *user_annotation;
let inferred_ty = self.normalize(inferred_ty, Locations::All(span));
Ok(())
}
- /// Equates a type `anon_ty` that may contain opaque types whose
- /// values are to be inferred by the MIR.
- ///
- /// The type `revealed_ty` contains the same type as `anon_ty`, but with the
- /// hidden types for impl traits revealed.
- ///
- /// # Example
- ///
- /// Consider a piece of code like
- ///
- /// ```rust
- /// type Foo<U> = impl Debug;
- ///
- /// fn foo<T: Debug>(t: T) -> Box<Foo<T>> {
- /// Box::new((t, 22_u32))
- /// }
- /// ```
- ///
- /// Here, the function signature would be something like
- /// `fn(T) -> Box<impl Debug>`. The MIR return slot would have
- /// the type with the opaque type revealed, so `Box<(T, u32)>`.
- ///
- /// In terms of our function parameters:
- ///
- /// * `anon_ty` would be `Box<Foo<T>>` where `Foo<T>` is an opaque type
- /// scoped to this function (note that it is parameterized by the
- /// generics of `foo`). Note that `anon_ty` is not just the opaque type,
- /// but the entire return type (which may contain opaque types within it).
- /// * `revealed_ty` would be `Box<(T, u32)>`
- #[instrument(skip(self), level = "debug")]
- fn eq_opaque_type_and_type(
- &mut self,
- revealed_ty: Ty<'tcx>,
- anon_ty: Ty<'tcx>,
- locations: Locations,
- category: ConstraintCategory,
- ) -> Fallible<()> {
- // Fast path for the common case.
- if !anon_ty.has_opaque_types() {
- if let Err(terr) = self.eq_types(anon_ty, revealed_ty, locations, category) {
- span_mirbug!(
- self,
- locations,
- "eq_opaque_type_and_type: `{:?}=={:?}` failed with `{:?}`",
- revealed_ty,
- anon_ty,
- terr
- );
- }
- return Ok(());
- }
-
- let param_env = self.param_env;
- let body = self.body;
- let mir_def_id = body.source.def_id().expect_local();
-
- debug!(?mir_def_id);
- self.fully_perform_op(
- locations,
- category,
- CustomTypeOp::new(
- |infcx| {
- let mut obligations = ObligationAccumulator::default();
-
- let dummy_body_id = hir::CRATE_HIR_ID;
-
- // Replace the opaque types defined by this function with
- // inference variables, creating a map. In our example above,
- // this would transform the type `Box<Foo<T>>` (where `Foo` is an opaque type)
- // to `Box<?T>`, returning an `opaque_type_map` mapping `{Foo<T> -> ?T}`.
- // (Note that the key of the map is both the def-id of `Foo` along with
- // any generic parameters.)
- let output_ty = obligations.add(infcx.instantiate_opaque_types(
- dummy_body_id,
- param_env,
- anon_ty,
- locations.span(body),
- ));
- debug!(?output_ty, ?revealed_ty);
-
- // Make sure that the inferred types are well-formed. I'm
- // not entirely sure this is needed (the HIR type check
- // didn't do this) but it seems sensible to prevent opaque
- // types hiding ill-formed types.
- obligations.obligations.push(traits::Obligation::new(
- ObligationCause::dummy(),
- param_env,
- ty::Binder::dummy(ty::PredicateKind::WellFormed(revealed_ty.into()))
- .to_predicate(infcx.tcx),
- ));
- obligations.add(
- infcx
- .at(&ObligationCause::dummy(), param_env)
- .eq(output_ty, revealed_ty)?,
- );
-
- debug!("equated");
-
- Ok(InferOk { value: (), obligations: obligations.into_vec() })
- },
- || "input_output".to_string(),
- ),
- )?;
-
- // Finally, if we instantiated the anon types successfully, we
- // have to solve any bounds (e.g., `-> impl Iterator` needs to
- // prove that `T: Iterator` where `T` is the type we
- // instantiated it with).
- let opaque_type_map = self.infcx.inner.borrow().opaque_types.clone();
- for (opaque_type_key, opaque_decl) in opaque_type_map {
- self.fully_perform_op(
- locations,
- ConstraintCategory::OpaqueType,
- CustomTypeOp::new(
- |infcx| {
- infcx.constrain_opaque_type(opaque_type_key, &opaque_decl);
- Ok(InferOk { value: (), obligations: vec![] })
- },
- || "opaque_type_map".to_string(),
- ),
- )?;
- }
- Ok(())
- }
-
fn tcx(&self) -> TyCtxt<'tcx> {
self.infcx.tcx
}
Locations::Single(self)
}
}
-
-#[derive(Debug, Default)]
-struct ObligationAccumulator<'tcx> {
- obligations: PredicateObligations<'tcx>,
-}
-
-impl<'tcx> ObligationAccumulator<'tcx> {
- fn add<T>(&mut self, value: InferOk<'tcx, T>) -> T {
- let InferOk { value, obligations } = value;
- self.obligations.extend(obligations);
- value
- }
-
- fn into_vec(self) -> PredicateObligations<'tcx> {
- self.obligations
- }
-}
use rustc_infer::infer::nll_relate::{NormalizationStrategy, TypeRelating, TypeRelatingDelegate};
-use rustc_infer::infer::NllRegionVariableOrigin;
+use rustc_infer::infer::{InferOk, NllRegionVariableOrigin};
+use rustc_infer::traits::ObligationCause;
use rustc_middle::mir::ConstraintCategory;
use rustc_middle::ty::relate::TypeRelation;
use rustc_middle::ty::{self, Const, Ty};
+use rustc_span::Span;
use rustc_trait_selection::traits::query::Fallible;
use crate::constraints::OutlivesConstraint;
use crate::diagnostics::UniverseInfo;
-use crate::type_check::{Locations, TypeChecker};
+use crate::type_check::{CustomTypeOp, Locations, TypeChecker};
impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
/// Adds sufficient constraints to ensure that `a R b` where `R` depends on `v`:
}
impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> {
+ fn span(&self) -> Span {
+ self.locations.span(self.type_checker.body)
+ }
+
fn param_env(&self) -> ty::ParamEnv<'tcx> {
self.type_checker.param_env
}
// We don't have to worry about the equality of consts during borrow checking
// as consts always have a static lifetime.
+ // FIXME(oli-obk): is this really true? We can at least have HKL and with
+ // inline consts we may have further lifetimes that may be unsound to treat as
+ // 'static.
fn const_equate(&mut self, _a: &'tcx Const<'tcx>, _b: &'tcx Const<'tcx>) {}
fn normalization() -> NormalizationStrategy {
fn forbid_inference_vars() -> bool {
true
}
+
+ fn register_opaque_type(&mut self, a: Ty<'tcx>, b: Ty<'tcx>, a_is_expected: bool) {
+ let param_env = self.param_env();
+ let span = self.span();
+ let def_id = self.type_checker.body.source.def_id().expect_local();
+ let body_id = self.type_checker.tcx().hir().local_def_id_to_hir_id(def_id);
+ let cause = ObligationCause::misc(span, body_id);
+ self.type_checker
+ .fully_perform_op(
+ self.locations,
+ self.category,
+ CustomTypeOp::new(
+ |infcx| {
+ Ok(InferOk {
+ value: (),
+ obligations: vec![infcx.opaque_ty_obligation(
+ a,
+ b,
+ a_is_expected,
+ param_env,
+ cause,
+ )],
+ })
+ },
+ || "register_opaque_type".to_string(),
+ ),
+ )
+ .unwrap();
+ }
}
self.tcx.fold_regions(value, &mut false, |_region, _depth| self.next_nll_region_var(origin))
}
+ #[instrument(level = "debug", skip(self, indices))]
fn replace_bound_regions_with_nll_infer_vars<T>(
&self,
origin: NllRegionVariableOrigin,
where
T: TypeFoldable<'tcx>,
{
- debug!(
- "replace_bound_regions_with_nll_infer_vars(value={:?}, all_outlive_scope={:?})",
- value, all_outlive_scope,
- );
let (value, _map) = self.tcx.replace_late_bound_regions(value, |br| {
- debug!("replace_bound_regions_with_nll_infer_vars: br={:?}", br);
+ debug!(?br);
let liberated_region = self.tcx.mk_region(ty::ReFree(ty::FreeRegion {
scope: all_outlive_scope.to_def_id(),
bound_region: br.kind,
}));
let region_vid = self.next_nll_region_var(origin);
indices.insert_late_bound_region(liberated_region, region_vid.to_region_vid());
- debug!(
- "replace_bound_regions_with_nll_infer_vars: liberated_region={:?} => {:?}",
- liberated_region, region_vid
- );
+ debug!(?liberated_region, ?region_vid);
region_vid
});
value
/// entries for them and store them in the indices map. This code iterates over the complete
/// set of late-bound regions and checks for any that we have not yet seen, adding them to the
/// inputs vector.
+ #[instrument(skip(self, indices))]
fn replace_late_bound_regions_with_nll_infer_vars(
&self,
mir_def_id: LocalDefId,
debug!("replace_late_bound_regions_with_nll_infer_vars: r={:?}", r);
if !indices.indices.contains_key(&r) {
let region_vid = self.next_nll_region_var(FR);
+ debug!(?region_vid);
indices.insert_late_bound_region(r, region_vid.to_region_vid());
}
});
// Create the type of `self`.
//
- // in addition, remove defaults from type params (impls cannot have them).
+ // in addition, remove defaults from generic params (impls cannot have them).
let self_params: Vec<_> = generics
.params
.iter_mut()
enum Position {
Exact(usize),
+ Capture(usize),
Named(Symbol),
}
/// * `arg_unique_types` (in simplified JSON): `[["o", "x"], ["o", "x"], ["o", "x"]]`
/// * `names` (in JSON): `{"foo": 2}`
args: Vec<P<ast::Expr>>,
+ /// The number of arguments that were added by implicit capturing.
+ num_captured_args: usize,
/// Placeholder slot numbers indexed by argument.
arg_types: Vec<Vec<usize>>,
/// Unique format specs seen for each argument.
}
impl<'a, 'b> Context<'a, 'b> {
+ /// The number of arguments that were explicitly given.
+ fn num_args(&self) -> usize {
+ self.args.len() - self.num_captured_args
+ }
+
fn resolve_name_inplace(&self, p: &mut parse::Piece<'_>) {
// NOTE: the `unwrap_or` branch is needed in case of invalid format
// arguments, e.g., `format_args!("{foo}")`.
}
fn describe_num_args(&self) -> Cow<'_, str> {
- match self.args.len() {
+ match self.num_args() {
0 => "no arguments were given".into(),
1 => "there is 1 argument".into(),
x => format!("there are {} arguments", x).into(),
let count = self.pieces.len()
+ self.arg_with_formatting.iter().filter(|fmt| fmt.precision_span.is_some()).count();
- if self.names.is_empty() && !numbered_position_args && count != self.args.len() {
+ if self.names.is_empty() && !numbered_position_args && count != self.num_args() {
e = self.ecx.struct_span_err(
sp,
&format!(
if let Some(span) = fmt.precision_span {
let span = self.fmtsp.from_inner(span);
match fmt.precision {
- parse::CountIsParam(pos) if pos > self.args.len() => {
+ parse::CountIsParam(pos) if pos > self.num_args() => {
e.span_label(
span,
&format!(
if let Some(span) = fmt.width_span {
let span = self.fmtsp.from_inner(span);
match fmt.width {
- parse::CountIsParam(pos) if pos > self.args.len() => {
+ parse::CountIsParam(pos) if pos > self.num_args() => {
e.span_label(
span,
&format!(
/// Actually verifies and tracks a given format placeholder
/// (a.k.a. argument).
fn verify_arg_type(&mut self, arg: Position, ty: ArgumentType) {
+ if let Exact(arg) = arg {
+ if arg >= self.num_args() {
+ self.invalid_refs.push((arg, self.curpiece));
+ return;
+ }
+ }
+
match arg {
- Exact(arg) => {
- if self.args.len() <= arg {
- self.invalid_refs.push((arg, self.curpiece));
- return;
- }
+ Exact(arg) | Capture(arg) => {
match ty {
Placeholder(_) => {
// record every (position, type) combination only once
match self.names.get(&name) {
Some(&idx) => {
// Treat as positional arg.
- self.verify_arg_type(Exact(idx), ty)
+ self.verify_arg_type(Capture(idx), ty)
}
None => {
// For the moment capturing variables from format strings expanded from macros is
} else {
self.fmtsp
};
+ self.num_captured_args += 1;
self.args.push(self.ecx.expr_ident(span, Ident::new(name, span)));
self.names.insert(name, idx);
- self.verify_arg_type(Exact(idx), ty)
+ self.verify_arg_type(Capture(idx), ty)
} else {
let msg = format!("there is no argument named `{}`", name);
let sp = if self.is_literal {
let mut cx = Context {
ecx,
args,
+ num_captured_args: 0,
arg_types,
arg_unique_types,
names,
// Allow using `#[global_allocator]` on an item statement
// FIXME - if we get deref patterns, use them to reduce duplication here
- let (item, is_stmt) = match &item {
+ let (item, is_stmt, ty_span) = match &item {
Annotatable::Item(item) => match item.kind {
- ItemKind::Static(..) => (item, false),
+ ItemKind::Static(ref ty, ..) => (item, false, ecx.with_def_site_ctxt(ty.span)),
_ => return not_static(),
},
Annotatable::Stmt(stmt) => match &stmt.kind {
StmtKind::Item(item_) => match item_.kind {
- ItemKind::Static(..) => (item_, true),
+ ItemKind::Static(ref ty, ..) => (item_, true, ecx.with_def_site_ctxt(ty.span)),
_ => return not_static(),
},
_ => return not_static(),
// Generate a bunch of new items using the AllocFnFactory
let span = ecx.with_def_site_ctxt(item.span);
- let f = AllocFnFactory { span, kind: AllocatorKind::Global, global: item.ident, cx: ecx };
+ let f =
+ AllocFnFactory { span, ty_span, kind: AllocatorKind::Global, global: item.ident, cx: ecx };
// Generate item statements for the allocator methods.
let stmts = ALLOCATOR_METHODS.iter().map(|method| f.allocator_fn(method)).collect();
// Generate anonymous constant serving as container for the allocator methods.
- let const_ty = ecx.ty(span, TyKind::Tup(Vec::new()));
+ let const_ty = ecx.ty(ty_span, TyKind::Tup(Vec::new()));
let const_body = ecx.expr_block(ecx.block(span, stmts));
let const_item = ecx.item_const(span, Ident::new(kw::Underscore, span), const_ty, const_body);
let const_item = if is_stmt {
struct AllocFnFactory<'a, 'b> {
span: Span,
+ ty_span: Span,
kind: AllocatorKind,
global: Ident,
cx: &'b ExtCtxt<'a>,
self.attrs(),
kind,
);
- self.cx.stmt_item(self.span, item)
+ self.cx.stmt_item(self.ty_span, item)
}
fn call_allocator(&self, method: Symbol, mut args: Vec<P<Expr>>) -> P<Expr> {
let method = self.cx.std_path(&[sym::alloc, sym::GlobalAlloc, method]);
- let method = self.cx.expr_path(self.cx.path(self.span, method));
- let allocator = self.cx.path_ident(self.span, self.global);
+ let method = self.cx.expr_path(self.cx.path(self.ty_span, method));
+ let allocator = self.cx.path_ident(self.ty_span, self.global);
let allocator = self.cx.expr_path(allocator);
- let allocator = self.cx.expr_addr_of(self.span, allocator);
+ let allocator = self.cx.expr_addr_of(self.ty_span, allocator);
args.insert(0, allocator);
- self.cx.expr_call(self.span, method, args)
+ self.cx.expr_call(self.ty_span, method, args)
}
fn attrs(&self) -> Vec<Attribute> {
"ignore",
cx.expr_bool(sp, should_ignore(&cx.sess, &item)),
),
- // allow_fail: true | false
- field(
- "allow_fail",
- cx.expr_bool(sp, should_fail(&cx.sess, &item)),
- ),
// compile_fail: true | false
field("compile_fail", cx.expr_bool(sp, false)),
// no_run: true | false
sess.contains_name(&i.attrs, sym::ignore)
}
-fn should_fail(sess: &Session, i: &ast::Item) -> bool {
- sess.contains_name(&i.attrs, sym::allow_fail)
-}
-
fn should_panic(cx: &ExtCtxt<'_>, i: &ast::Item) -> ShouldPanic {
match cx.sess.find_by_name(&i.attrs, sym::should_panic) {
Some(attr) => {
use rustc_middle::ty::cast::CastTy;
use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts};
use rustc_middle::ty::{self, adjustment::PointerCast, Instance, InstanceDef, Ty, TyCtxt};
-use rustc_middle::ty::{Binder, TraitPredicate, TraitRef};
+use rustc_middle::ty::{Binder, TraitPredicate, TraitRef, TypeFoldable};
use rustc_mir_dataflow::{self, Analysis};
use rustc_span::{sym, Span, Symbol};
use rustc_trait_selection::traits::SelectionContext;
location: Location,
) -> bool {
let ty = ccx.body.local_decls[local].ty;
- if !NeedsDrop::in_any_value_of_ty(ccx, ty) {
+ // Peeking into opaque types causes cycles if the current function declares said opaque
+ // type. Thus we avoid short circuiting on the type and instead run the more expensive
+ // analysis that looks at the actual usage within this function
+ if !ty.has_opaque_types() && !NeedsDrop::in_any_value_of_ty(ccx, ty) {
return false;
}
location: Location,
) -> bool {
let ty = ccx.body.local_decls[local].ty;
- if !HasMutInterior::in_any_value_of_ty(ccx, ty) {
+ // Peeking into opaque types causes cycles if the current function declares said opaque
+ // type. Thus we avoid short circuiting on the type and instead run the more expensive
+ // analysis that looks at the actual usage within this function
+ if !ty.has_opaque_types() && !HasMutInterior::in_any_value_of_ty(ccx, ty) {
return false;
}
// If we know that all values of the return type are structurally matchable, there's no
// need to run dataflow.
- _ if !CustomEq::in_any_value_of_ty(ccx, ccx.body.return_ty()) => false,
+ // Opaque types do not participate in const generics or pattern matching, so we can safely count them out.
+ _ if ccx.body.return_ty().has_opaque_types()
+ || !CustomEq::in_any_value_of_ty(ccx, ccx.body.return_ty()) =>
+ {
+ false
+ }
hir::ConstContext::Const | hir::ConstContext::Static(_) => {
let mut cursor = FlowSensitiveAnalysis::new(CustomEq, ccx)
| ty::PredicateKind::Projection(_)
| ty::PredicateKind::ConstEvaluatable(..)
| ty::PredicateKind::ConstEquate(..)
+ | ty::PredicateKind::OpaqueType(..)
| ty::PredicateKind::TypeWellFormedFromEnv(..) => continue,
ty::PredicateKind::ObjectSafe(_) => {
bug!("object safe predicate on function: {:#?}", predicate)
}
// Normalize lifetimes away on both sides, then compare.
- let param_env = param_env.with_reveal_all_normalized(tcx);
let normalize = |ty: Ty<'tcx>| {
tcx.normalize_erasing_regions(
param_env,
return true;
}
// Normalize projections and things like that.
- // FIXME: We need to reveal_all, as some optimizations change types in ways
- // that require unfolding opaque types.
- let param_env = self.param_env.with_reveal_all_normalized(self.tcx);
+ let param_env = self.param_env;
let src = self.tcx.normalize_erasing_regions(param_env, src);
let dest = self.tcx.normalize_erasing_regions(param_env, dest);
}
}
+ /// Removes the entry from the map and returns the removed value
+ pub fn remove(&mut self, k: &K) -> Option<V> {
+ self.0.iter().position(|(k2, _)| k2 == k).map(|pos| self.0.remove(pos).1)
+ }
+
/// Gets a reference to the value in the entry.
pub fn get<Q: ?Sized>(&self, k: &Q) -> Option<&V>
where
self.0.iter().find(|(key, _)| k == key.borrow()).map(|elem| &elem.1)
}
+ /// Gets a mutable reference to the value in the entry.
+ pub fn get_mut<Q: ?Sized>(&mut self, k: &Q) -> Option<&mut V>
+ where
+ K: Borrow<Q>,
+ Q: Eq,
+ {
+ self.0.iter_mut().find(|(key, _)| k == key.borrow()).map(|elem| &mut elem.1)
+ }
+
/// Returns the any value corresponding to the supplied predicate filter.
///
/// The supplied predicate will be applied to each (key, value) pair and it will return a
// This should return just one element, otherwise it's a bug
assert!(
filter.next().is_none(),
- "Collection {:?} should have just one matching element",
+ "Collection {:#?} should have just one matching element",
self
);
Some(value)
(incomplete, adt_const_params, "1.56.0", Some(44580), None),
/// Allows defining an `#[alloc_error_handler]`.
(active, alloc_error_handler, "1.29.0", Some(51540), None),
- /// Allows a test to fail without failing the whole suite.
- (active, allow_fail, "1.19.0", Some(46488), None),
/// Allows explicit discriminants on non-unit enum variants.
(active, arbitrary_enum_discriminant, "1.37.0", Some(60553), None),
/// Allows trait methods with arbitrary self types.
/// Allows using and casting function pointers in a `const fn`.
(active, const_fn_fn_ptr_basics, "1.48.0", Some(57563), None),
/// Allows trait bounds in `const fn`.
- (active, const_fn_trait_bound, "1.53.0", Some(57563), None),
+ (active, const_fn_trait_bound, "1.53.0", Some(93706), None),
/// Allows `for _ in _` loops in const contexts.
(active, const_for, "1.56.0", Some(87575), None),
/// Allows argument and return position `impl Trait` in a `const fn`.
},
// Testing:
- gated!(allow_fail, Normal, template!(Word), WarnFollowing, experimental!(allow_fail)),
gated!(
test_runner, CrateLevel, template!(List: "path"), ErrorFollowing, custom_test_frameworks,
"custom test frameworks are an unstable feature",
(removed, advanced_slice_patterns, "1.0.0", Some(62254), None,
Some("merged into `#![feature(slice_patterns)]`")),
(removed, allocator, "1.0.0", None, None, None),
+ /// Allows a test to fail without failing the whole suite.
+ (removed, allow_fail, "1.19.0", Some(46488), None, Some("removed due to no clear use cases")),
(removed, await_macro, "1.38.0", Some(50547), None,
Some("subsumed by `.await` syntax")),
/// Allows comparing raw pointers during const eval.
pub infcx: &'a InferCtxt<'a, 'tcx>,
pub cause: &'a ObligationCause<'tcx>,
pub param_env: ty::ParamEnv<'tcx>,
+ /// Whether we should define opaque types
+ /// or just treat them opaquely.
+ /// Currently only used to prevent predicate
+ /// matching from matching anything against opaque
+ /// types.
+ pub define_opaque_types: bool,
}
pub struct Trace<'a, 'tcx> {
cause: &'a ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
) -> At<'a, 'tcx> {
- At { infcx: self, cause, param_env }
+ At { infcx: self, cause, param_env, define_opaque_types: true }
}
}
}
impl<'a, 'tcx> At<'a, 'tcx> {
+ pub fn define_opaque_types(self, define_opaque_types: bool) -> Self {
+ Self { define_opaque_types, ..self }
+ }
+
/// Hacky routine for equating two impl headers in coherence.
pub fn eq_impl_headers(
self,
{
let Trace { at, trace, a_is_expected } = self;
at.infcx.commit_if_ok(|_| {
- let mut fields = at.infcx.combine_fields(trace, at.param_env);
+ let mut fields = at.infcx.combine_fields(trace, at.param_env, at.define_opaque_types);
fields
.sub(a_is_expected)
.relate(a, b)
{
let Trace { at, trace, a_is_expected } = self;
at.infcx.commit_if_ok(|_| {
- let mut fields = at.infcx.combine_fields(trace, at.param_env);
+ let mut fields = at.infcx.combine_fields(trace, at.param_env, at.define_opaque_types);
fields
.equate(a_is_expected)
.relate(a, b)
{
let Trace { at, trace, a_is_expected } = self;
at.infcx.commit_if_ok(|_| {
- let mut fields = at.infcx.combine_fields(trace, at.param_env);
+ let mut fields = at.infcx.combine_fields(trace, at.param_env, at.define_opaque_types);
fields
.lub(a_is_expected)
.relate(a, b)
{
let Trace { at, trace, a_is_expected } = self;
at.infcx.commit_if_ok(|_| {
- let mut fields = at.infcx.combine_fields(trace, at.param_env);
+ let mut fields = at.infcx.combine_fields(trace, at.param_env, at.define_opaque_types);
fields
.glb(a_is_expected)
.relate(a, b)
a: Self,
b: Self,
) -> TypeTrace<'tcx> {
- TypeTrace { cause: cause.clone(), values: Types(ExpectedFound::new(a_is_expected, a, b)) }
+ TypeTrace {
+ cause: cause.clone(),
+ values: Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())),
+ }
}
}
a: Self,
b: Self,
) -> TypeTrace<'tcx> {
- TypeTrace { cause: cause.clone(), values: Consts(ExpectedFound::new(a_is_expected, a, b)) }
+ TypeTrace {
+ cause: cause.clone(),
+ values: Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())),
+ }
}
}
impl<'tcx> ToTrace<'tcx> for ty::Term<'tcx> {
fn to_trace(
- tcx: TyCtxt<'tcx>,
+ _: TyCtxt<'tcx>,
cause: &ObligationCause<'tcx>,
a_is_expected: bool,
a: Self,
b: Self,
) -> TypeTrace<'tcx> {
- match (a, b) {
- (ty::Term::Ty(a), ty::Term::Ty(b)) => {
- ToTrace::to_trace(tcx, cause, a_is_expected, a, b)
- }
- (ty::Term::Const(a), ty::Term::Const(b)) => {
- ToTrace::to_trace(tcx, cause, a_is_expected, a, b)
- }
- (_, _) => todo!(),
- }
+ TypeTrace { cause: cause.clone(), values: Terms(ExpectedFound::new(a_is_expected, a, b)) }
}
}
let b_ty = tcx.mk_projection(b.item_def_id, b.substs);
TypeTrace {
cause: cause.clone(),
- values: Types(ExpectedFound::new(a_is_expected, a_ty, b_ty)),
+ values: Terms(ExpectedFound::new(a_is_expected, a_ty.into(), b_ty.into())),
}
}
}
use rustc_middle::ty::relate::TypeRelation;
use rustc_middle::ty::subst::{GenericArg, GenericArgKind};
use rustc_middle::ty::{self, BoundVar, Const, ToPredicate, Ty, TyCtxt};
+use rustc_span::Span;
use std::fmt::Debug;
use std::iter;
var_values: inference_vars,
region_constraints: QueryRegionConstraints::default(),
certainty: Certainty::Proven, // Ambiguities are OK!
+ opaque_types: vec![],
value: answer,
})
}
let certainty =
if ambig_errors.is_empty() { Certainty::Proven } else { Certainty::Ambiguous };
+ let opaque_types = self.take_opaque_types_for_query_response();
+
Ok(QueryResponse {
var_values: inference_vars,
region_constraints,
certainty,
value: answer,
+ opaque_types,
})
}
+ fn take_opaque_types_for_query_response(&self) -> Vec<(Ty<'tcx>, Ty<'tcx>)> {
+ self.inner
+ .borrow_mut()
+ .opaque_type_storage
+ .take_opaque_types()
+ .into_iter()
+ .map(|(k, v)| (self.tcx.mk_opaque(k.def_id, k.substs), v.hidden_type.ty))
+ .collect()
+ }
+
/// Given the (canonicalized) result to a canonical query,
/// instantiates the result so it can be used, plugging in the
/// values from the canonical query. (Note that the result may
where
R: Debug + TypeFoldable<'tcx>,
{
- let result_subst =
- self.query_response_substitution_guess(cause, original_values, query_response);
+ let InferOk { value: result_subst, mut obligations } = self
+ .query_response_substitution_guess(cause, param_env, original_values, query_response)?;
// Compute `QueryOutlivesConstraint` values that unify each of
// the original values `v_o` that was canonicalized into a
// variable...
- let mut obligations = vec![];
for (index, original_value) in original_values.var_values.iter().enumerate() {
// ...with the value `v_r` of that variable from the query.
original_values, query_response,
);
- let result_subst =
- self.query_response_substitution_guess(cause, original_values, query_response);
+ let mut value = self.query_response_substitution_guess(
+ cause,
+ param_env,
+ original_values,
+ query_response,
+ )?;
- let obligations = self
- .unify_query_response_substitution_guess(
+ value.obligations.extend(
+ self.unify_query_response_substitution_guess(
cause,
param_env,
original_values,
- &result_subst,
+ &value.value,
query_response,
)?
- .into_obligations();
+ .into_obligations(),
+ );
- Ok(InferOk { value: result_subst, obligations })
+ Ok(value)
}
/// Given the original values and the (canonicalized) result from
fn query_response_substitution_guess<R>(
&self,
cause: &ObligationCause<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
original_values: &OriginalQueryValues<'tcx>,
query_response: &Canonical<'tcx, QueryResponse<'tcx, R>>,
- ) -> CanonicalVarValues<'tcx>
+ ) -> InferResult<'tcx, CanonicalVarValues<'tcx>>
where
R: Debug + TypeFoldable<'tcx>,
{
.collect(),
};
- result_subst
+ let mut obligations = vec![];
+
+ // Carry all newly resolved opaque types to the caller's scope
+ for &(a, b) in &query_response.value.opaque_types {
+ let a = substitute_value(self.tcx, &result_subst, a);
+ let b = substitute_value(self.tcx, &result_subst, b);
+ obligations.extend(self.handle_opaque_type(a, b, cause, param_env)?.obligations);
+ }
+
+ Ok(InferOk { value: result_subst, obligations })
}
/// Given a "guess" at the values for the canonical variables in
}
impl<'tcx> TypeRelatingDelegate<'tcx> for QueryTypeRelatingDelegate<'_, 'tcx> {
+ fn span(&self) -> Span {
+ self.cause.span
+ }
+
fn param_env(&self) -> ty::ParamEnv<'tcx> {
self.param_env
}
fn forbid_inference_vars() -> bool {
true
}
+
+ fn register_opaque_type(&mut self, a: Ty<'tcx>, b: Ty<'tcx>, a_is_expected: bool) {
+ self.obligations.push(self.infcx.opaque_ty_obligation(
+ a,
+ b,
+ a_is_expected,
+ self.param_env,
+ self.cause.clone(),
+ ));
+ }
}
pub cause: Option<ty::relate::Cause>,
pub param_env: ty::ParamEnv<'tcx>,
pub obligations: PredicateObligations<'tcx>,
+ /// Whether we should define opaque types
+ /// or just treat them opaquely.
+ /// Currently only used to prevent predicate
+ /// matching from matching anything against opaque
+ /// types.
+ pub define_opaque_types: bool,
}
#[derive(Copy, Clone, Debug)]
/// will first instantiate `b_vid` with a *generalized* version
/// of `a_ty`. Generalization introduces other inference
/// variables wherever subtyping could occur.
+ #[instrument(skip(self), level = "debug")]
pub fn instantiate(
&mut self,
a_ty: Ty<'tcx>,
// Get the actual variable that b_vid has been inferred to
debug_assert!(self.infcx.inner.borrow_mut().type_variables().probe(b_vid).is_unknown());
- debug!("instantiate(a_ty={:?} dir={:?} b_vid={:?})", a_ty, dir, b_vid);
-
// Generalize type of `a_ty` appropriately depending on the
// direction. As an example, assume:
//
// variables. (Down below, we will relate `a_ty <: b_ty`,
// adding constraints like `'x: '?2` and `?1 <: ?3`.)
let Generalization { ty: b_ty, needs_wf } = self.generalize(a_ty, b_vid, dir)?;
- debug!(
- "instantiate(a_ty={:?}, dir={:?}, b_vid={:?}, generalized b_ty={:?})",
- a_ty, dir, b_vid, b_ty
- );
+ debug!(?b_ty);
self.infcx.inner.borrow_mut().type_variables().instantiate(b_vid, b_ty);
if needs_wf {
/// Preconditions:
///
/// - `for_vid` is a "root vid"
+ #[instrument(skip(self), level = "trace")]
fn generalize(
&self,
ty: Ty<'tcx>,
for_vid: ty::TyVid,
dir: RelationDir,
) -> RelateResult<'tcx, Generalization<'tcx>> {
- debug!("generalize(ty={:?}, for_vid={:?}, dir={:?}", ty, for_vid, dir);
// Determine the ambient variance within which `ty` appears.
// The surrounding equation is:
//
RelationDir::SupertypeOf => ty::Contravariant,
};
- debug!("generalize: ambient_variance = {:?}", ambient_variance);
+ trace!(?ambient_variance);
let for_universe = match self.infcx.inner.borrow_mut().type_variables().probe(for_vid) {
v @ TypeVariableValue::Known { .. } => {
TypeVariableValue::Unknown { universe } => universe,
};
- debug!("generalize: for_universe = {:?}", for_universe);
- debug!("generalize: trace = {:?}", self.trace);
+ trace!(?for_universe);
+ trace!(?self.trace);
let mut generalize = Generalizer {
infcx: self.infcx,
let ty = match generalize.relate(ty, ty) {
Ok(ty) => ty,
Err(e) => {
- debug!("generalize: failure {:?}", e);
+ debug!(?e, "failure");
return Err(e);
}
};
let needs_wf = generalize.needs_wf;
- debug!("generalize: success {{ {:?}, {:?} }}", ty, needs_wf);
+ trace!(?ty, ?needs_wf, "success");
Ok(Generalization { ty, needs_wf })
}
self.relate(a, b)
}
+ #[instrument(skip(self), level = "debug")]
fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
- debug!("{}.tys({:?}, {:?})", self.tag(), a, b);
if a == b {
return Ok(a);
}
+ trace!(a = ?a.kind(), b = ?b.kind());
+
let infcx = self.fields.infcx;
+
let a = infcx.inner.borrow_mut().type_variables().replace_if_possible(a);
let b = infcx.inner.borrow_mut().type_variables().replace_if_possible(b);
- debug!("{}.tys: replacements ({:?}, {:?})", self.tag(), a, b);
-
match (a.kind(), b.kind()) {
(&ty::Infer(TyVar(a_id)), &ty::Infer(TyVar(b_id))) => {
infcx.inner.borrow_mut().type_variables().equate(a_id, b_id);
self.fields.instantiate(a, RelationDir::EqTo, b_id, self.a_is_expected)?;
}
+ (&ty::Opaque(a_def_id, _), &ty::Opaque(b_def_id, _)) if a_def_id == b_def_id => {
+ self.fields.infcx.super_combine_tys(self, a, b)?;
+ }
+ (&ty::Opaque(did, ..), _) | (_, &ty::Opaque(did, ..))
+ if self.fields.define_opaque_types && did.is_local() =>
+ {
+ self.fields.obligations.push(infcx.opaque_ty_obligation(
+ a,
+ b,
+ self.a_is_expected(),
+ self.param_env(),
+ self.fields.trace.cause.clone(),
+ ));
+ }
+
_ => {
self.fields.infcx.super_combine_tys(self, a, b)?;
}
None => (None, Mismatch::Fixed("type"), false),
Some(values) => {
let (is_simple_error, exp_found) = match values {
- ValuePairs::Types(exp_found) => {
- let is_simple_err =
- exp_found.expected.is_simple_text() && exp_found.found.is_simple_text();
- OpaqueTypesVisitor::visit_expected_found(
- self.tcx,
- exp_found.expected,
- exp_found.found,
- span,
- )
- .report(diag);
+ ValuePairs::Terms(infer::ExpectedFound {
+ expected: ty::Term::Ty(expected),
+ found: ty::Term::Ty(found),
+ }) => {
+ let is_simple_err = expected.is_simple_text() && found.is_simple_text();
+ OpaqueTypesVisitor::visit_expected_found(self.tcx, expected, found, span)
+ .report(diag);
- (is_simple_err, Mismatch::Variable(exp_found))
+ (
+ is_simple_err,
+ Mismatch::Variable(infer::ExpectedFound { expected, found }),
+ )
}
ValuePairs::TraitRefs(_) => (false, Mismatch::Fixed("trait")),
_ => (false, Mismatch::Fixed("type")),
};
if let Some((sp, msg)) = secondary_span {
if swap_secondary_and_primary {
- let terr = if let Some(infer::ValuePairs::Types(infer::ExpectedFound {
+ let terr = if let Some(infer::ValuePairs::Terms(infer::ExpectedFound {
expected,
..
})) = values
}
FailureCode::Error0308(failure_str) => {
let mut err = struct_span_err!(self.tcx.sess, span, E0308, "{}", failure_str);
- if let ValuePairs::Types(ty::error::ExpectedFound { expected, found }) =
- trace.values
- {
+ if let Some((expected, found)) = trace.values.ty() {
match (expected.kind(), found.kind()) {
(ty::Tuple(_), ty::Tuple(_)) => {}
// If a tuple of length one was expected and the found expression has
// parentheses around it, perhaps the user meant to write `(expr,)` to
// build a tuple (issue #86100)
- (ty::Tuple(_), _) if expected.tuple_fields().count() == 1 => {
- if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span) {
- if let Some(code) =
- code.strip_prefix('(').and_then(|s| s.strip_suffix(')'))
- {
- err.span_suggestion(
- span,
- "use a trailing comma to create a tuple with one element",
- format!("({},)", code),
- Applicability::MaybeIncorrect,
- );
- }
- }
+ (ty::Tuple(_), _) => {
+ self.emit_tuple_wrap_err(&mut err, span, found, expected)
}
// If a character was expected and the found expression is a string literal
// containing a single character, perhaps the user meant to write `'c'` to
if let Some(code) =
code.strip_prefix('"').and_then(|s| s.strip_suffix('"'))
{
- if code.chars().nth(1).is_none() {
+ if code.chars().count() == 1 {
err.span_suggestion(
span,
"if you meant to write a `char` literal, use single quotes",
diag
}
+ fn emit_tuple_wrap_err(
+ &self,
+ err: &mut DiagnosticBuilder<'tcx>,
+ span: Span,
+ found: Ty<'tcx>,
+ expected: Ty<'tcx>,
+ ) {
+ let [expected_tup_elem] = &expected.tuple_fields().collect::<Vec<_>>()[..]
+ else { return };
+
+ if !same_type_modulo_infer(expected_tup_elem, found) {
+ return;
+ }
+
+ let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span)
+ else { return };
+
+ let msg = "use a trailing comma to create a tuple with one element";
+ if code.starts_with('(') && code.ends_with(')') {
+ let before_close = span.hi() - BytePos::from_u32(1);
+ err.span_suggestion(
+ span.with_hi(before_close).shrink_to_hi(),
+ msg,
+ ",".into(),
+ Applicability::MachineApplicable,
+ );
+ } else {
+ err.multipart_suggestion(
+ msg,
+ vec![(span.shrink_to_lo(), "(".into()), (span.shrink_to_hi(), ",)".into())],
+ Applicability::MachineApplicable,
+ );
+ }
+ }
+
fn values_str(
&self,
values: ValuePairs<'tcx>,
) -> Option<(DiagnosticStyledString, DiagnosticStyledString)> {
match values {
- infer::Types(exp_found) => self.expected_found_str_ty(exp_found),
infer::Regions(exp_found) => self.expected_found_str(exp_found),
- infer::Consts(exp_found) => self.expected_found_str(exp_found),
+ infer::Terms(exp_found) => self.expected_found_str_term(exp_found),
infer::TraitRefs(exp_found) => {
let pretty_exp_found = ty::error::ExpectedFound {
expected: exp_found.expected.print_only_trait_path(),
}
}
- fn expected_found_str_ty(
+ fn expected_found_str_term(
&self,
- exp_found: ty::error::ExpectedFound<Ty<'tcx>>,
+ exp_found: ty::error::ExpectedFound<ty::Term<'tcx>>,
) -> Option<(DiagnosticStyledString, DiagnosticStyledString)> {
let exp_found = self.resolve_vars_if_possible(exp_found);
if exp_found.references_error() {
return None;
}
- Some(self.cmp(exp_found.expected, exp_found.found))
+ Some(match (exp_found.expected, exp_found.found) {
+ (ty::Term::Ty(expected), ty::Term::Ty(found)) => self.cmp(expected, found),
+ (expected, found) => (
+ DiagnosticStyledString::highlighted(expected.to_string()),
+ DiagnosticStyledString::highlighted(found.to_string()),
+ ),
+ })
}
/// Returns a string of the form "expected `{}`, found `{}`".
use crate::infer::error_reporting::nice_region_error::NiceRegionError;
use crate::infer::lexical_region_resolve::RegionResolutionError;
-use crate::infer::{SubregionOrigin, Subtype, ValuePairs};
+use crate::infer::{SubregionOrigin, Subtype};
use crate::traits::ObligationCauseCode::CompareImplMethodObligation;
use rustc_errors::ErrorReported;
use rustc_hir as hir;
{
if let (&Subtype(ref sup_trace), &Subtype(ref sub_trace)) = (&sup_origin, &sub_origin) {
if let (
- ValuePairs::Types(sub_expected_found),
- ValuePairs::Types(sup_expected_found),
+ sub_expected_found @ Some((sub_expected, sub_found)),
+ sup_expected_found @ Some(_),
CompareImplMethodObligation { trait_item_def_id, .. },
- ) = (&sub_trace.values, &sup_trace.values, sub_trace.cause.code())
+ ) = (&sub_trace.values.ty(), &sup_trace.values.ty(), sub_trace.cause.code())
{
if sup_expected_found == sub_expected_found {
self.emit_err(
var_origin.span(),
- sub_expected_found.expected,
- sub_expected_found.found,
+ sub_expected,
+ sub_found,
*trait_item_def_id,
);
return Some(ErrorReported);
use super::Subtype;
use crate::infer::combine::ConstEquateRelation;
-use crate::traits::ObligationCause;
+use crate::traits::{ObligationCause, PredicateObligation};
use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation};
use rustc_middle::ty::{self, Ty, TyCtxt};
&self.fields.trace.cause
}
+ fn add_obligations(&mut self, obligations: Vec<PredicateObligation<'tcx>>) {
+ self.fields.obligations.extend(obligations)
+ }
+
fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> {
let mut sub = self.fields.sub(self.a_is_expected);
sub.relate(v, a)?;
sub.relate(v, b)?;
Ok(())
}
+
+ fn define_opaque_types(&self) -> bool {
+ self.fields.define_opaque_types
+ }
}
impl<'tcx> ConstEquateRelation<'tcx> for Glb<'_, '_, 'tcx> {
use super::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use super::InferCtxt;
-use crate::traits::ObligationCause;
+use crate::traits::{ObligationCause, PredicateObligation};
use rustc_middle::ty::relate::{RelateResult, TypeRelation};
use rustc_middle::ty::TyVar;
use rustc_middle::ty::{self, Ty};
fn cause(&self) -> &ObligationCause<'tcx>;
+ fn add_obligations(&mut self, obligations: Vec<PredicateObligation<'tcx>>);
+
+ fn define_opaque_types(&self) -> bool;
+
// Relates the type `v` to `a` and `b` such that `v` represents
// the LUB/GLB of `a` and `b` as appropriate.
//
fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()>;
}
+#[instrument(skip(this), level = "debug")]
pub fn super_lattice_tys<'a, 'tcx: 'a, L>(
this: &mut L,
a: Ty<'tcx>,
where
L: LatticeDir<'a, 'tcx>,
{
- debug!("{}.lattice_tys({:?}, {:?})", this.tag(), a, b);
+ debug!("{}", this.tag());
if a == b {
return Ok(a);
}
let infcx = this.infcx();
+
let a = infcx.inner.borrow_mut().type_variables().replace_if_possible(a);
let b = infcx.inner.borrow_mut().type_variables().replace_if_possible(b);
+
match (a.kind(), b.kind()) {
// If one side is known to be a variable and one is not,
// create a variable (`v`) to represent the LUB. Make sure to
Ok(v)
}
+ (&ty::Opaque(a_def_id, _), &ty::Opaque(b_def_id, _)) if a_def_id == b_def_id => {
+ infcx.super_combine_tys(this, a, b)
+ }
+ (&ty::Opaque(did, ..), _) | (_, &ty::Opaque(did, ..))
+ if this.define_opaque_types() && did.is_local() =>
+ {
+ this.add_obligations(vec![infcx.opaque_ty_obligation(
+ a,
+ b,
+ this.a_is_expected(),
+ this.param_env(),
+ this.cause().clone(),
+ )]);
+ Ok(a)
+ }
+
_ => infcx.super_combine_tys(this, a, b),
}
}
use super::Subtype;
use crate::infer::combine::ConstEquateRelation;
-use crate::traits::ObligationCause;
+use crate::traits::{ObligationCause, PredicateObligation};
use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation};
use rustc_middle::ty::{self, Ty, TyCtxt};
&self.fields.trace.cause
}
+ fn add_obligations(&mut self, obligations: Vec<PredicateObligation<'tcx>>) {
+ self.fields.obligations.extend(obligations)
+ }
+
fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> {
let mut sub = self.fields.sub(self.a_is_expected);
sub.relate(a, v)?;
sub.relate(b, v)?;
Ok(())
}
+
+ fn define_opaque_types(&self) -> bool {
+ self.fields.define_opaque_types
+ }
}
pub use self::SubregionOrigin::*;
pub use self::ValuePairs::*;
-use self::opaque_types::OpaqueTypeMap;
+use self::opaque_types::OpaqueTypeStorage;
pub(crate) use self::undo_log::{InferCtxtUndoLogs, Snapshot, UndoLog};
use crate::traits::{self, ObligationCause, PredicateObligations, TraitEngine};
undo_log: InferCtxtUndoLogs<'tcx>,
- // Opaque types found in explicit return types and their
- // associated fresh inference variable. Writeback resolves these
- // variables to get the concrete type, which can be used to
- // 'de-opaque' OpaqueTypeDecl outside of type inference.
- pub opaque_types: OpaqueTypeMap<'tcx>,
-
- /// A map from inference variables created from opaque
- /// type instantiations (`ty::Infer`) to the actual opaque
- /// type (`ty::Opaque`). Used during fallback to map unconstrained
- /// opaque type inference variables to their corresponding
- /// opaque type.
- pub opaque_types_vars: FxHashMap<Ty<'tcx>, Ty<'tcx>>,
+ /// Caches for opaque type inference.
+ pub opaque_type_storage: OpaqueTypeStorage<'tcx>,
}
impl<'tcx> InferCtxtInner<'tcx> {
float_unification_storage: ut::UnificationTableStorage::new(),
region_constraint_storage: Some(RegionConstraintStorage::new()),
region_obligations: vec![],
- opaque_types: Default::default(),
- opaque_types_vars: Default::default(),
+ opaque_type_storage: Default::default(),
}
}
self.type_variable_storage.with_log(&mut self.undo_log)
}
+ #[inline]
+ pub fn opaque_types(&mut self) -> opaque_types::OpaqueTypeTable<'_, 'tcx> {
+ self.opaque_type_storage.with_log(&mut self.undo_log)
+ }
+
#[inline]
fn int_unification_table(
&mut self,
/// to the outside until the end up in an `InferCtxt` for typeck or borrowck.
pub defining_use_anchor: Option<LocalDefId>,
+ /// Used by WF-checking to not have to figure out hidden types itself, but
+ /// to just invoke type_of to get the already computed hidden type from typeck.
+ pub reveal_defining_opaque_types: bool,
+
/// During type-checking/inference of a body, `in_progress_typeck_results`
/// contains a reference to the typeck results being built up, which are
/// used for reading closure kinds/signatures as they are inferred,
/// See the `error_reporting` module for more details.
#[derive(Clone, Copy, Debug, PartialEq, Eq, TypeFoldable)]
pub enum ValuePairs<'tcx> {
- Types(ExpectedFound<Ty<'tcx>>),
Regions(ExpectedFound<ty::Region<'tcx>>),
- Consts(ExpectedFound<&'tcx ty::Const<'tcx>>),
+ Terms(ExpectedFound<ty::Term<'tcx>>),
TraitRefs(ExpectedFound<ty::TraitRef<'tcx>>),
PolyTraitRefs(ExpectedFound<ty::PolyTraitRef<'tcx>>),
}
+impl<'tcx> ValuePairs<'tcx> {
+ pub fn ty(&self) -> Option<(Ty<'tcx>, Ty<'tcx>)> {
+ if let ValuePairs::Terms(ExpectedFound {
+ expected: ty::Term::Ty(expected),
+ found: ty::Term::Ty(found),
+ }) = self
+ {
+ Some((expected, found))
+ } else {
+ None
+ }
+ }
+}
+
/// The trace designates the path through inference that we took to
/// encounter an error or subtyping constraint.
///
tcx: TyCtxt<'tcx>,
fresh_typeck_results: Option<RefCell<ty::TypeckResults<'tcx>>>,
defining_use_anchor: Option<LocalDefId>,
+ reveal_defining_opaque_types: bool,
}
pub trait TyCtxtInferExt<'tcx> {
impl<'tcx> TyCtxtInferExt<'tcx> for TyCtxt<'tcx> {
fn infer_ctxt(self) -> InferCtxtBuilder<'tcx> {
- InferCtxtBuilder { tcx: self, defining_use_anchor: None, fresh_typeck_results: None }
+ InferCtxtBuilder {
+ tcx: self,
+ defining_use_anchor: None,
+ fresh_typeck_results: None,
+ reveal_defining_opaque_types: false,
+ }
}
}
self
}
+ /// WF-checking doesn't need to recompute opaque types and can instead use
+ /// the type_of query to get them from typeck.
+ pub fn reveal_defining_opaque_types(mut self) -> Self {
+ self.reveal_defining_opaque_types = true;
+ self
+ }
+
/// Given a canonical value `C` as a starting point, create an
/// inference context that contains each of the bound values
/// within instantiated as a fresh variable. The `f` closure is
}
pub fn enter<R>(&mut self, f: impl for<'a> FnOnce(InferCtxt<'a, 'tcx>) -> R) -> R {
- let InferCtxtBuilder { tcx, defining_use_anchor, ref fresh_typeck_results } = *self;
+ let InferCtxtBuilder {
+ tcx,
+ defining_use_anchor,
+ reveal_defining_opaque_types,
+ ref fresh_typeck_results,
+ } = *self;
let in_progress_typeck_results = fresh_typeck_results.as_ref();
f(InferCtxt {
tcx,
defining_use_anchor,
+ reveal_defining_opaque_types,
in_progress_typeck_results,
inner: RefCell::new(InferCtxtInner::new()),
lexical_region_resolutions: RefCell::new(None),
&'a self,
trace: TypeTrace<'tcx>,
param_env: ty::ParamEnv<'tcx>,
+ define_opaque_types: bool,
) -> CombineFields<'a, 'tcx> {
CombineFields {
infcx: self,
cause: None,
param_env,
obligations: PredicateObligations::new(),
+ define_opaque_types,
}
}
self.tcx.mk_ty_var(self.next_ty_var_id(origin))
}
+ pub fn next_ty_var_id_in_universe(
+ &self,
+ origin: TypeVariableOrigin,
+ universe: ty::UniverseIndex,
+ ) -> TyVid {
+ self.inner.borrow_mut().type_variables().new_var(universe, origin)
+ }
+
pub fn next_ty_var_in_universe(
&self,
origin: TypeVariableOrigin,
universe: ty::UniverseIndex,
) -> Ty<'tcx> {
- let vid = self.inner.borrow_mut().type_variables().new_var(universe, origin);
+ let vid = self.next_ty_var_id_in_universe(origin, universe);
self.tcx.mk_ty_var(vid)
}
a: Ty<'tcx>,
b: Ty<'tcx>,
) -> TypeTrace<'tcx> {
- TypeTrace { cause: cause.clone(), values: Types(ExpectedFound::new(a_is_expected, a, b)) }
+ TypeTrace {
+ cause: cause.clone(),
+ values: Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())),
+ }
}
pub fn consts(
a: &'tcx ty::Const<'tcx>,
b: &'tcx ty::Const<'tcx>,
) -> TypeTrace<'tcx> {
- TypeTrace { cause: cause.clone(), values: Consts(ExpectedFound::new(a_is_expected, a, b)) }
+ TypeTrace {
+ cause: cause.clone(),
+ values: Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())),
+ }
}
}
use crate::infer::combine::ConstEquateRelation;
use crate::infer::InferCtxt;
use crate::infer::{ConstVarValue, ConstVariableValue};
+use crate::infer::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_data_structures::fx::FxHashMap;
use rustc_middle::ty::error::TypeError;
use rustc_middle::ty::fold::{TypeFoldable, TypeVisitor};
use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
use rustc_middle::ty::{self, InferConst, Ty, TyCtxt};
+use rustc_span::Span;
use std::fmt::Debug;
use std::ops::ControlFlow;
pub trait TypeRelatingDelegate<'tcx> {
fn param_env(&self) -> ty::ParamEnv<'tcx>;
+ fn span(&self) -> Span;
/// Push a constraint `sup: sub` -- this constraint must be
/// satisfied for the two types to be related. `sub` and `sup` may
info: ty::VarianceDiagInfo<'tcx>,
);
+ fn register_opaque_type(&mut self, a: Ty<'tcx>, b: Ty<'tcx>, a_is_expected: bool);
+
fn const_equate(&mut self, a: &'tcx ty::Const<'tcx>, b: &'tcx ty::Const<'tcx>);
/// Creates a new universe index. Used when instantiating placeholders.
projection_ty: ty::ProjectionTy<'tcx>,
value_ty: Ty<'tcx>,
) -> Ty<'tcx> {
- use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_span::DUMMY_SP;
match *value_ty.kind() {
kind: TypeVariableOriginKind::MiscVariable,
span: DUMMY_SP,
});
+ // FIXME(lazy-normalization): This will always ICE, because the recursive
+ // call will end up in the _ arm below.
self.relate_projection_ty(projection_ty, var);
self.relate_projection_ty(other_projection_ty, var);
var
#[instrument(skip(self), level = "debug")]
fn tys(&mut self, a: Ty<'tcx>, mut b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
+ let infcx = self.infcx;
+
let a = self.infcx.shallow_resolve(a);
if !D::forbid_inference_vars() {
(&ty::Infer(ty::TyVar(vid)), _) => self.relate_ty_var((vid, b)),
+ (&ty::Opaque(a_def_id, _), &ty::Opaque(b_def_id, _)) if a_def_id == b_def_id => {
+ self.infcx.super_combine_tys(self, a, b)
+ }
+ (&ty::Opaque(did, ..), _) | (_, &ty::Opaque(did, ..)) if did.is_local() => {
+ let (a, b) = if self.a_is_expected() { (a, b) } else { (b, a) };
+ let mut generalize = |ty, ty_is_expected| {
+ let var = infcx.next_ty_var_id_in_universe(
+ TypeVariableOrigin {
+ kind: TypeVariableOriginKind::MiscVariable,
+ span: self.delegate.span(),
+ },
+ ty::UniverseIndex::ROOT,
+ );
+ if ty_is_expected {
+ self.relate_ty_var((ty, var))
+ } else {
+ self.relate_ty_var((var, ty))
+ }
+ };
+ let (a, b) = match (a.kind(), b.kind()) {
+ (&ty::Opaque(..), _) => (a, generalize(b, false)?),
+ (_, &ty::Opaque(..)) => (generalize(a, true)?, b),
+ _ => unreachable!(),
+ };
+ self.delegate.register_opaque_type(a, b, true);
+ trace!(a = ?a.kind(), b = ?b.kind(), "opaque type instantiated");
+ Ok(a)
+ }
+
(&ty::Projection(projection_ty), _)
if D::normalization() == NormalizationStrategy::Lazy =>
{
-use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use crate::infer::{InferCtxt, InferOk};
-use crate::traits;
+use crate::traits::{self, PredicateObligation};
+use hir::def_id::{DefId, LocalDefId};
+use hir::OpaqueTyOrigin;
use rustc_data_structures::sync::Lrc;
use rustc_data_structures::vec_map::VecMap;
use rustc_hir as hir;
-use rustc_hir::def_id::LocalDefId;
+use rustc_middle::traits::ObligationCause;
use rustc_middle::ty::fold::BottomUpFolder;
use rustc_middle::ty::subst::{GenericArgKind, Subst};
use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable, TypeVisitor};
pub type OpaqueTypeMap<'tcx> = VecMap<OpaqueTypeKey<'tcx>, OpaqueTypeDecl<'tcx>>;
+mod table;
+
+pub use table::{OpaqueTypeStorage, OpaqueTypeTable};
+
+use super::InferResult;
+
/// Information about the opaque types whose values we
/// are inferring in this function (these are the `impl Trait` that
/// appear in the return type).
-#[derive(Copy, Clone, Debug)]
+#[derive(Clone, Debug)]
pub struct OpaqueTypeDecl<'tcx> {
- /// The opaque type (`ty::Opaque`) for this declaration.
- pub opaque_type: Ty<'tcx>,
+ /// The hidden types that have been inferred for this opaque type.
+ /// There can be multiple, but they are all `lub`ed together at the end
+ /// to obtain the canonical hidden type.
+ pub hidden_type: OpaqueHiddenType<'tcx>,
+
+ /// The origin of the opaque type.
+ pub origin: hir::OpaqueTyOrigin,
+}
+#[derive(Copy, Clone, Debug, TypeFoldable)]
+pub struct OpaqueHiddenType<'tcx> {
/// The span of this particular definition of the opaque type. So
/// for example:
///
/// In cases where the fn returns `(impl Trait, impl Trait)` or
/// other such combinations, the result is currently
/// over-approximated, but better than nothing.
- pub definition_span: Span,
+ pub span: Span,
/// The type variable that represents the value of the opaque type
/// that we require. In other words, after we compile this function,
/// those that are arguments to `Foo` in the constraint above. (In
/// other words, `?C` should not include `'b`, even though it's a
/// lifetime parameter on `foo`.)
- pub concrete_ty: Ty<'tcx>,
-
- /// The origin of the opaque type.
- pub origin: hir::OpaqueTyOrigin,
+ pub ty: Ty<'tcx>,
}
impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
- /// Replaces all opaque types in `value` with fresh inference variables
- /// and creates appropriate obligations. For example, given the input:
- ///
- /// impl Iterator<Item = impl Debug>
- ///
- /// this method would create two type variables, `?0` and `?1`. It would
- /// return the type `?0` but also the obligations:
- ///
- /// ?0: Iterator<Item = ?1>
- /// ?1: Debug
- ///
- /// Moreover, it returns an `OpaqueTypeMap` that would map `?0` to
- /// info about the `impl Iterator<..>` type and `?1` to info about
- /// the `impl Debug` type.
- ///
- /// # Parameters
- ///
- /// - `parent_def_id` -- the `DefId` of the function in which the opaque type
- /// is defined
- /// - `body_id` -- the body-id with which the resulting obligations should
- /// be associated
- /// - `param_env` -- the in-scope parameter environment to be used for
- /// obligations
- /// - `value` -- the value within which we are instantiating opaque types
- /// - `value_span` -- the span where the value came from, used in error reporting
- pub fn instantiate_opaque_types<T: TypeFoldable<'tcx>>(
+ pub fn handle_opaque_type(
&self,
- body_id: hir::HirId,
+ a: Ty<'tcx>,
+ b: Ty<'tcx>,
+ cause: &ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
- value: T,
- value_span: Span,
- ) -> InferOk<'tcx, T> {
- debug!(
- "instantiate_opaque_types(value={:?}, body_id={:?}, \
- param_env={:?}, value_span={:?})",
- value, body_id, param_env, value_span,
- );
- let mut instantiator =
- Instantiator { infcx: self, body_id, param_env, value_span, obligations: vec![] };
- let value = instantiator.instantiate_opaque_types_in_map(value);
- InferOk { value, obligations: instantiator.obligations }
+ ) -> InferResult<'tcx, ()> {
+ if a.references_error() || b.references_error() {
+ return Ok(InferOk { value: (), obligations: vec![] });
+ }
+ if self.defining_use_anchor.is_some() {
+ let process = |a: Ty<'tcx>, b: Ty<'tcx>| match *a.kind() {
+ ty::Opaque(def_id, substs) => {
+ if let ty::Opaque(did2, _) = *b.kind() {
+ // We could accept this, but there are various ways to handle this situation, and we don't
+ // want to make a decision on it right now. Likely this case is so super rare anyway, that
+ // no one encounters it in practice.
+ // It does occur however in `fn fut() -> impl Future<Output = i32> { async { 42 } }`,
+ // where it is of no concern, so we only check for TAITs.
+ if let Some(OpaqueTyOrigin::TyAlias) =
+ self.opaque_type_origin(did2, cause.span)
+ {
+ self.tcx
+ .sess
+ .struct_span_err(
+ cause.span,
+ "opaque type's hidden type cannot be another opaque type from the same scope",
+ )
+ .span_label(cause.span, "one of the two opaque types used here has to be outside its defining scope")
+ .span_note(
+ self.tcx.def_span(def_id),
+ "opaque type whose hidden type is being assigned",
+ )
+ .span_note(
+ self.tcx.def_span(did2),
+ "opaque type being used as hidden type",
+ )
+ .emit();
+ }
+ }
+ Some(self.register_hidden_type(
+ OpaqueTypeKey { def_id, substs },
+ cause.clone(),
+ param_env,
+ b,
+ // Check that this is `impl Trait` type is
+ // declared by `parent_def_id` -- i.e., one whose
+ // value we are inferring. At present, this is
+ // always true during the first phase of
+ // type-check, but not always true later on during
+ // NLL. Once we support named opaque types more fully,
+ // this same scenario will be able to arise during all phases.
+ //
+ // Here is an example using type alias `impl Trait`
+ // that indicates the distinction we are checking for:
+ //
+ // ```rust
+ // mod a {
+ // pub type Foo = impl Iterator;
+ // pub fn make_foo() -> Foo { .. }
+ // }
+ //
+ // mod b {
+ // fn foo() -> a::Foo { a::make_foo() }
+ // }
+ // ```
+ //
+ // Here, the return type of `foo` references an
+ // `Opaque` indeed, but not one whose value is
+ // presently being inferred. You can get into a
+ // similar situation with closure return types
+ // today:
+ //
+ // ```rust
+ // fn foo() -> impl Iterator { .. }
+ // fn bar() {
+ // let x = || foo(); // returns the Opaque assoc with `foo`
+ // }
+ // ```
+ self.opaque_type_origin(def_id, cause.span)?,
+ ))
+ }
+ _ => None,
+ };
+ if let Some(res) = process(a, b) {
+ res
+ } else if let Some(res) = process(b, a) {
+ res
+ } else {
+ // Rerun equality check, but this time error out due to
+ // different types.
+ match self.at(cause, param_env).define_opaque_types(false).eq(a, b) {
+ Ok(_) => span_bug!(
+ cause.span,
+ "opaque types are never equal to anything but themselves: {:#?}",
+ (a, b)
+ ),
+ Err(e) => Err(e),
+ }
+ }
+ } else {
+ let (opaque_type, hidden_ty) = match (a.kind(), b.kind()) {
+ (ty::Opaque(..), _) => (a, b),
+ (_, ty::Opaque(..)) => (b, a),
+ types => span_bug!(
+ cause.span,
+ "opaque type obligations only work for opaque types: {:#?}",
+ types
+ ),
+ };
+ let key = opaque_type.expect_opaque_type();
+ let origin = self.opaque_ty_origin_unchecked(key.def_id, cause.span);
+ let prev = self.inner.borrow_mut().opaque_types().register(
+ key,
+ OpaqueHiddenType { ty: hidden_ty, span: cause.span },
+ origin,
+ );
+ match prev {
+ Some(prev) => self.at(cause, param_env).eq(prev, hidden_ty),
+ None => Ok(InferOk { value: (), obligations: vec![] }),
+ }
+ }
}
/// Given the map `opaque_types` containing the opaque
/// but this is not necessary, because the opaque type we
/// create will be allowed to reference `T`. So we only generate a
/// constraint that `'0: 'a`.
- ///
- /// # The `free_region_relations` parameter
- ///
- /// The `free_region_relations` argument is used to find the
- /// "minimum" of the regions supplied to a given opaque type.
- /// It must be a relation that can answer whether `'a <= 'b`,
- /// where `'a` and `'b` are regions that appear in the "substs"
- /// for the opaque type references (the `<'a>` in `Foo1<'a>`).
- ///
- /// Note that we do not impose the constraints based on the
- /// generic regions from the `Foo1` definition (e.g., `'x`). This
- /// is because the constraints we are imposing here is basically
- /// the concern of the one generating the constraining type C1,
- /// which is the current function. It also means that we can
- /// take "implied bounds" into account in some cases:
- ///
- /// ```text
- /// trait SomeTrait<'a, 'b> { }
- /// fn foo<'a, 'b>(_: &'a &'b u32) -> impl SomeTrait<'a, 'b> { .. }
- /// ```
- ///
- /// Here, the fact that `'b: 'a` is known only because of the
- /// implied bounds from the `&'a &'b u32` parameter, and is not
- /// "inherent" to the opaque type definition.
- ///
- /// # Parameters
- ///
- /// - `opaque_types` -- the map produced by `instantiate_opaque_types`
- /// - `free_region_relations` -- something that can be used to relate
- /// the free regions (`'a`) that appear in the impl trait.
#[instrument(level = "debug", skip(self))]
- pub fn constrain_opaque_type(
+ pub fn register_member_constraints(
&self,
+ param_env: ty::ParamEnv<'tcx>,
opaque_type_key: OpaqueTypeKey<'tcx>,
- opaque_defn: &OpaqueTypeDecl<'tcx>,
+ concrete_ty: Ty<'tcx>,
+ span: Span,
) {
let def_id = opaque_type_key.def_id;
let tcx = self.tcx;
- let concrete_ty = self.resolve_vars_if_possible(opaque_defn.concrete_ty);
+ let concrete_ty = self.resolve_vars_if_possible(concrete_ty);
debug!(?concrete_ty);
- let first_own_region = match opaque_defn.origin {
+ let first_own_region = match self.opaque_ty_origin_unchecked(def_id, span) {
hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) => {
// We lower
//
op: |r| {
self.member_constraint(
opaque_type_key.def_id,
- opaque_defn.definition_span,
+ span,
concrete_ty,
r,
&choice_regions,
});
}
- fn opaque_type_origin(&self, def_id: LocalDefId) -> Option<hir::OpaqueTyOrigin> {
- let tcx = self.tcx;
- let opaque_hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
+ pub fn opaque_ty_obligation(
+ &self,
+ a: Ty<'tcx>,
+ b: Ty<'tcx>,
+ a_is_expected: bool,
+ param_env: ty::ParamEnv<'tcx>,
+ cause: ObligationCause<'tcx>,
+ ) -> PredicateObligation<'tcx> {
+ let (a, b) = if a_is_expected { (a, b) } else { (b, a) };
+ PredicateObligation::new(
+ cause,
+ param_env,
+ self.tcx.mk_predicate(ty::Binder::dummy(ty::PredicateKind::OpaqueType(a, b))),
+ )
+ }
+
+ #[instrument(skip(self), level = "trace")]
+ pub fn opaque_type_origin(&self, opaque_def_id: DefId, span: Span) -> Option<OpaqueTyOrigin> {
+ let def_id = opaque_def_id.as_local()?;
+ let opaque_hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
let parent_def_id = self.defining_use_anchor?;
- let item_kind = &tcx.hir().expect_item(def_id).kind;
+ let item_kind = &self.tcx.hir().expect_item(def_id).kind;
+
let hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) = item_kind else {
span_bug!(
- tcx.def_span(def_id),
- "weird opaque type: {:#?}",
+ span,
+ "weird opaque type: {:#?}, {:#?}",
+ opaque_def_id,
item_kind
)
};
hir::OpaqueTyOrigin::FnReturn(parent) => parent == parent_def_id,
// Named `type Foo = impl Bar;`
hir::OpaqueTyOrigin::TyAlias => {
- may_define_opaque_type(tcx, parent_def_id, opaque_hir_id)
+ may_define_opaque_type(self.tcx, parent_def_id, opaque_hir_id)
}
};
+ trace!(?origin);
in_definition_scope.then_some(*origin)
}
+
+ #[instrument(skip(self), level = "trace")]
+ fn opaque_ty_origin_unchecked(&self, opaque_def_id: DefId, span: Span) -> OpaqueTyOrigin {
+ let def_id = opaque_def_id.as_local().unwrap();
+ let origin = match self.tcx.hir().expect_item(def_id).kind {
+ hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => origin,
+ ref itemkind => {
+ span_bug!(span, "weird opaque type: {:?}, {:#?}", opaque_def_id, itemkind)
+ }
+ };
+ trace!(?origin);
+ origin
+ }
+
+ pub fn opaque_types(&self) -> OpaqueTypeMap<'tcx> {
+ self.inner.borrow().opaque_type_storage.opaque_types()
+ }
}
// Visitor that requires that (almost) all regions in the type visited outlive
}
}
-struct Instantiator<'a, 'tcx> {
- infcx: &'a InferCtxt<'a, 'tcx>,
- body_id: hir::HirId,
- param_env: ty::ParamEnv<'tcx>,
- value_span: Span,
- obligations: Vec<traits::PredicateObligation<'tcx>>,
+pub enum UseKind {
+ DefiningUse,
+ OpaqueUse,
}
-impl<'a, 'tcx> Instantiator<'a, 'tcx> {
- fn instantiate_opaque_types_in_map<T: TypeFoldable<'tcx>>(&mut self, value: T) -> T {
- let tcx = self.infcx.tcx;
- value.fold_with(&mut BottomUpFolder {
- tcx,
- ty_op: |ty| {
- if ty.references_error() {
- return tcx.ty_error();
- } else if let ty::Opaque(def_id, substs) = ty.kind() {
- // Check that this is `impl Trait` type is
- // declared by `parent_def_id` -- i.e., one whose
- // value we are inferring. At present, this is
- // always true during the first phase of
- // type-check, but not always true later on during
- // NLL. Once we support named opaque types more fully,
- // this same scenario will be able to arise during all phases.
- //
- // Here is an example using type alias `impl Trait`
- // that indicates the distinction we are checking for:
- //
- // ```rust
- // mod a {
- // pub type Foo = impl Iterator;
- // pub fn make_foo() -> Foo { .. }
- // }
- //
- // mod b {
- // fn foo() -> a::Foo { a::make_foo() }
- // }
- // ```
- //
- // Here, the return type of `foo` references an
- // `Opaque` indeed, but not one whose value is
- // presently being inferred. You can get into a
- // similar situation with closure return types
- // today:
- //
- // ```rust
- // fn foo() -> impl Iterator { .. }
- // fn bar() {
- // let x = || foo(); // returns the Opaque assoc with `foo`
- // }
- // ```
- if let Some(def_id) = def_id.as_local() {
- if let Some(origin) = self.infcx.opaque_type_origin(def_id) {
- let opaque_type_key =
- OpaqueTypeKey { def_id: def_id.to_def_id(), substs };
- return self.fold_opaque_ty(ty, opaque_type_key, origin);
- }
-
- debug!(
- "instantiate_opaque_types_in_map: \
- encountered opaque outside its definition scope \
- def_id={:?}",
- def_id,
- );
- }
- }
-
- ty
- },
- lt_op: |lt| lt,
- ct_op: |ct| ct,
- })
+impl UseKind {
+ pub fn is_defining(self) -> bool {
+ match self {
+ UseKind::DefiningUse => true,
+ UseKind::OpaqueUse => false,
+ }
}
+}
+impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
#[instrument(skip(self), level = "debug")]
- fn fold_opaque_ty(
- &mut self,
- ty: Ty<'tcx>,
+ fn register_hidden_type(
+ &self,
opaque_type_key: OpaqueTypeKey<'tcx>,
+ cause: ObligationCause<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ hidden_ty: Ty<'tcx>,
origin: hir::OpaqueTyOrigin,
- ) -> Ty<'tcx> {
- let infcx = self.infcx;
- let tcx = infcx.tcx;
+ ) -> InferResult<'tcx, ()> {
+ let tcx = self.tcx;
let OpaqueTypeKey { def_id, substs } = opaque_type_key;
- // Use the same type variable if the exact same opaque type appears more
- // than once in the return type (e.g., if it's passed to a type alias).
- if let Some(opaque_defn) = infcx.inner.borrow().opaque_types.get(&opaque_type_key) {
- debug!("re-using cached concrete type {:?}", opaque_defn.concrete_ty.kind());
- return opaque_defn.concrete_ty;
- }
-
- let ty_var = infcx.next_ty_var(TypeVariableOrigin {
- kind: TypeVariableOriginKind::TypeInference,
- span: self.value_span,
- });
-
// Ideally, we'd get the span where *this specific `ty` came
// from*, but right now we just use the span from the overall
// value being folded. In simple cases like `-> impl Foo`,
// these are the same span, but not in cases like `-> (impl
// Foo, impl Bar)`.
- let definition_span = self.value_span;
+ let span = cause.span;
- {
- let mut infcx = self.infcx.inner.borrow_mut();
- infcx.opaque_types.insert(
- OpaqueTypeKey { def_id, substs },
- OpaqueTypeDecl { opaque_type: ty, definition_span, concrete_ty: ty_var, origin },
- );
- infcx.opaque_types_vars.insert(ty_var, ty);
+ let mut obligations = vec![];
+ let prev = self.inner.borrow_mut().opaque_types().register(
+ OpaqueTypeKey { def_id, substs },
+ OpaqueHiddenType { ty: hidden_ty, span },
+ origin,
+ );
+ if let Some(prev) = prev {
+ obligations = self.at(&cause, param_env).eq(prev, hidden_ty)?.obligations;
}
- debug!("generated new type inference var {:?}", ty_var.kind());
-
let item_bounds = tcx.explicit_item_bounds(def_id);
- self.obligations.reserve(item_bounds.len());
for (predicate, _) in item_bounds {
debug!(?predicate);
let predicate = predicate.subst(tcx, substs);
- debug!(?predicate);
let predicate = predicate.fold_with(&mut BottomUpFolder {
tcx,
ty_op: |ty| match *ty.kind() {
- // Replace all other mentions of the same opaque type with the hidden type,
- // as the bounds must hold on the hidden type after all.
- ty::Opaque(def_id2, substs2) if def_id == def_id2 && substs == substs2 => {
- ty_var
- }
- // Instantiate nested instances of `impl Trait`.
- ty::Opaque(..) => self.instantiate_opaque_types_in_map(ty),
- _ => ty,
- },
- lt_op: |lt| lt,
- ct_op: |ct| ct,
- });
-
- // We can't normalize associated types from `rustc_infer`, but we can eagerly register inference variables for them.
- let predicate = predicate.fold_with(&mut BottomUpFolder {
- tcx,
- ty_op: |ty| match ty.kind() {
+ // We can't normalize associated types from `rustc_infer`,
+ // but we can eagerly register inference variables for them.
ty::Projection(projection_ty) if !projection_ty.has_escaping_bound_vars() => {
- infcx.infer_projection(
- self.param_env,
- *projection_ty,
- traits::ObligationCause::misc(self.value_span, self.body_id),
+ self.infer_projection(
+ param_env,
+ projection_ty,
+ cause.clone(),
0,
- &mut self.obligations,
+ &mut obligations,
)
}
+ // Replace all other mentions of the same opaque type with the hidden type,
+ // as the bounds must hold on the hidden type after all.
+ ty::Opaque(def_id2, substs2) if def_id == def_id2 && substs == substs2 => {
+ hidden_ty
+ }
_ => ty,
},
lt_op: |lt| lt,
ct_op: |ct| ct,
});
- debug!(?predicate);
if let ty::PredicateKind::Projection(projection) = predicate.kind().skip_binder() {
if projection.term.references_error() {
- return tcx.ty_error();
+ // No point on adding these obligations since there's a type error involved.
+ return Ok(InferOk { value: (), obligations: vec![] });
}
+ trace!("{:#?}", projection.term);
}
-
- let cause =
- traits::ObligationCause::new(self.value_span, self.body_id, traits::OpaqueType);
-
// Require that the predicate holds for the concrete type.
debug!(?predicate);
- self.obligations.push(traits::Obligation::new(cause, self.param_env, predicate));
+ obligations.push(traits::Obligation::new(cause.clone(), param_env, predicate));
}
-
- ty_var
+ Ok(InferOk { value: (), obligations })
}
}
--- /dev/null
+use rustc_data_structures::undo_log::UndoLogs;
+use rustc_hir::OpaqueTyOrigin;
+use rustc_middle::ty::{self, OpaqueTypeKey, Ty};
+use rustc_span::DUMMY_SP;
+
+use crate::infer::{InferCtxtUndoLogs, UndoLog};
+
+use super::{OpaqueHiddenType, OpaqueTypeDecl, OpaqueTypeMap};
+
+#[derive(Default, Debug)]
+pub struct OpaqueTypeStorage<'tcx> {
+ // Opaque types found in explicit return types and their
+ // associated fresh inference variable. Writeback resolves these
+ // variables to get the concrete type, which can be used to
+ // 'de-opaque' OpaqueTypeDecl, after typeck is done with all functions.
+ pub opaque_types: OpaqueTypeMap<'tcx>,
+}
+
+impl<'tcx> OpaqueTypeStorage<'tcx> {
+ #[instrument(level = "debug")]
+ pub(crate) fn remove(&mut self, key: OpaqueTypeKey<'tcx>, idx: Option<OpaqueHiddenType<'tcx>>) {
+ if let Some(idx) = idx {
+ self.opaque_types.get_mut(&key).unwrap().hidden_type = idx;
+ } else {
+ match self.opaque_types.remove(&key) {
+ None => bug!("reverted opaque type inference that was never registered: {:?}", key),
+ Some(_) => {}
+ }
+ }
+ }
+
+ pub fn get_decl(&self, key: &OpaqueTypeKey<'tcx>) -> Option<&OpaqueTypeDecl<'tcx>> {
+ self.opaque_types.get(key)
+ }
+
+ pub fn opaque_types(&self) -> OpaqueTypeMap<'tcx> {
+ self.opaque_types.clone()
+ }
+
+ #[instrument(level = "debug")]
+ pub fn take_opaque_types(&mut self) -> OpaqueTypeMap<'tcx> {
+ std::mem::take(&mut self.opaque_types)
+ }
+
+ #[inline]
+ pub(crate) fn with_log<'a>(
+ &'a mut self,
+ undo_log: &'a mut InferCtxtUndoLogs<'tcx>,
+ ) -> OpaqueTypeTable<'a, 'tcx> {
+ OpaqueTypeTable { storage: self, undo_log }
+ }
+}
+
+impl<'tcx> Drop for OpaqueTypeStorage<'tcx> {
+ fn drop(&mut self) {
+ if !self.opaque_types.is_empty() {
+ ty::tls::with(|tcx| {
+ tcx.sess.delay_span_bug(DUMMY_SP, &format!("{:?}", self.opaque_types))
+ });
+ }
+ }
+}
+
+pub struct OpaqueTypeTable<'a, 'tcx> {
+ storage: &'a mut OpaqueTypeStorage<'tcx>,
+
+ undo_log: &'a mut InferCtxtUndoLogs<'tcx>,
+}
+
+impl<'a, 'tcx> OpaqueTypeTable<'a, 'tcx> {
+ #[instrument(skip(self), level = "debug")]
+ pub fn register(
+ &mut self,
+ key: OpaqueTypeKey<'tcx>,
+ hidden_type: OpaqueHiddenType<'tcx>,
+ origin: OpaqueTyOrigin,
+ ) -> Option<Ty<'tcx>> {
+ if let Some(decl) = self.storage.opaque_types.get_mut(&key) {
+ let prev = std::mem::replace(&mut decl.hidden_type, hidden_type);
+ self.undo_log.push(UndoLog::OpaqueTypes(key, Some(prev)));
+ return Some(prev.ty);
+ }
+ let decl = OpaqueTypeDecl { hidden_type, origin };
+ self.storage.opaque_types.insert(key, decl);
+ self.undo_log.push(UndoLog::OpaqueTypes(key, None));
+ None
+ }
+}
| ty::PredicateKind::TypeOutlives(..)
| ty::PredicateKind::ConstEvaluatable(..)
| ty::PredicateKind::ConstEquate(..)
+ | ty::PredicateKind::OpaqueType(..)
| ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(r_a, r_b)) => {
Some(OutlivesBound::RegionSubRegion(r_b, r_a))
/// This function may have to perform normalizations, and hence it
/// returns an `InferOk` with subobligations that must be
/// processed.
+ #[instrument(level = "debug", skip(self, region_bound_pairs_map))]
pub fn process_registered_region_obligations(
&self,
region_bound_pairs_map: &FxHashMap<hir::HirId, RegionBoundPairs<'tcx>>,
"cannot process registered region obligations in a snapshot"
);
- debug!(?param_env, "process_registered_region_obligations()");
-
let my_region_obligations = self.take_registered_region_obligations();
for (body_id, RegionObligation { sup_type, sub_region, origin }) in my_region_obligations {
use super::SubregionOrigin;
use crate::infer::combine::ConstEquateRelation;
+use crate::infer::{TypeVariableOrigin, TypeVariableOriginKind};
use crate::traits::Obligation;
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::relate::{Cause, Relate, RelateResult, TypeRelation};
}
}
+ #[instrument(skip(self), level = "debug")]
fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
- debug!("{}.tys({:?}, {:?})", self.tag(), a, b);
-
if a == b {
return Ok(a);
}
let infcx = self.fields.infcx;
let a = infcx.inner.borrow_mut().type_variables().replace_if_possible(a);
let b = infcx.inner.borrow_mut().type_variables().replace_if_possible(b);
+
match (a.kind(), b.kind()) {
(&ty::Infer(TyVar(_)), &ty::Infer(TyVar(_))) => {
// Shouldn't have any LBR here, so we can safely put
Ok(self.tcx().ty_error())
}
+ (&ty::Opaque(a_def_id, _), &ty::Opaque(b_def_id, _)) if a_def_id == b_def_id => {
+ self.fields.infcx.super_combine_tys(self, a, b)?;
+ Ok(a)
+ }
+ (&ty::Opaque(did, ..), _) | (_, &ty::Opaque(did, ..))
+ if self.fields.define_opaque_types && did.is_local() =>
+ {
+ let mut generalize = |ty, ty_is_expected| {
+ let var = infcx.next_ty_var_id_in_universe(
+ TypeVariableOrigin {
+ kind: TypeVariableOriginKind::MiscVariable,
+ span: self.fields.trace.cause.span,
+ },
+ ty::UniverseIndex::ROOT,
+ );
+ self.fields.instantiate(ty, RelationDir::SubtypeOf, var, ty_is_expected)?;
+ Ok(infcx.tcx.mk_ty_var(var))
+ };
+ let (a, b) = if self.a_is_expected { (a, b) } else { (b, a) };
+ let (a, b) = match (a.kind(), b.kind()) {
+ (&ty::Opaque(..), _) => (a, generalize(b, true)?),
+ (_, &ty::Opaque(..)) => (generalize(a, false)?, b),
+ _ => unreachable!(),
+ };
+ self.fields.obligations.push(infcx.opaque_ty_obligation(
+ a,
+ b,
+ true,
+ self.param_env(),
+ self.fields.trace.cause.clone(),
+ ));
+ Ok(a)
+ }
+
_ => {
self.fields.infcx.super_combine_tys(self, a, b)?;
Ok(a)
use rustc_data_structures::undo_log::{Rollback, UndoLogs};
use rustc_data_structures::unify as ut;
use rustc_middle::infer::unify_key::RegionVidKey;
-use rustc_middle::ty;
+use rustc_middle::ty::{self, OpaqueTypeKey};
use crate::{
infer::{region_constraints, type_variable, InferCtxtInner},
traits,
};
+use super::opaque_types::OpaqueHiddenType;
+
pub struct Snapshot<'tcx> {
pub(crate) undo_len: usize,
_marker: PhantomData<&'tcx ()>,
/// Records the "undo" data for a single operation that affects some form of inference variable.
pub(crate) enum UndoLog<'tcx> {
+ OpaqueTypes(OpaqueTypeKey<'tcx>, Option<OpaqueHiddenType<'tcx>>),
TypeVariables(type_variable::UndoLog<'tcx>),
ConstUnificationTable(sv::UndoLog<ut::Delegate<ty::ConstVid<'tcx>>>),
IntUnificationTable(sv::UndoLog<ut::Delegate<ty::IntVid>>),
impl<'tcx> Rollback<UndoLog<'tcx>> for InferCtxtInner<'tcx> {
fn reverse(&mut self, undo: UndoLog<'tcx>) {
match undo {
+ UndoLog::OpaqueTypes(key, idx) => self.opaque_type_storage.remove(key, idx),
UndoLog::TypeVariables(undo) => self.type_variable_storage.reverse(undo),
UndoLog::ConstUnificationTable(undo) => self.const_unification_storage.reverse(undo),
UndoLog::IntUnificationTable(undo) => self.int_unification_storage.reverse(undo),
// Currently, we do not elaborate WF predicates,
// although we easily could.
}
+ ty::PredicateKind::OpaqueType(..) => {
+ todo!("{:#?}", obligation)
+ }
ty::PredicateKind::ObjectSafe(..) => {
// Currently, we do not elaborate object-safe
// predicates.
Coerce(..) |
ConstEvaluatable(..) |
ConstEquate(..) |
+ OpaqueType(..) |
TypeWellFormedFromEnv(..) => continue,
};
if predicate.is_global() {
fn build_dll_import(&self, abi: Abi, item: &hir::ForeignItemRef) -> DllImport {
let calling_convention = if self.tcx.sess.target.arch == "x86" {
match abi {
- Abi::C { .. } | Abi::Cdecl => DllCallingConvention::C,
+ Abi::C { .. } | Abi::Cdecl { .. } => DllCallingConvention::C,
Abi::Stdcall { .. } | Abi::System { .. } => {
DllCallingConvention::Stdcall(self.i686_arg_list_size(item))
}
- Abi::Fastcall => DllCallingConvention::Fastcall(self.i686_arg_list_size(item)),
+ Abi::Fastcall { .. } => {
+ DllCallingConvention::Fastcall(self.i686_arg_list_size(item))
+ }
// Vectorcall is intentionally not supported at this time.
_ => {
self.tcx.sess.span_fatal(
}
} else {
match abi {
- Abi::C { .. } | Abi::Win64 | Abi::System { .. } => DllCallingConvention::C,
+ Abi::C { .. } | Abi::Win64 { .. } | Abi::System { .. } => DllCallingConvention::C,
_ => {
self.tcx.sess.span_fatal(
item.span,
pub var_values: CanonicalVarValues<'tcx>,
pub region_constraints: QueryRegionConstraints<'tcx>,
pub certainty: Certainty,
+ /// List of opaque types which we tried to compare to another type.
+ /// Inside the query we don't know yet whether the opaque type actually
+ /// should get its hidden type inferred. So we bubble the opaque type
+ /// and the type it was compared against upwards and let the query caller
+ /// handle it.
+ pub opaque_types: Vec<(Ty<'tcx>, Ty<'tcx>)>,
pub value: R,
}
self.relate(a, b)
}
+ #[instrument(skip(self), level = "debug")]
fn regions(
&mut self,
a: ty::Region<'tcx>,
b: ty::Region<'tcx>,
) -> RelateResult<'tcx, ty::Region<'tcx>> {
- debug!("{}.regions({:?}, {:?})", self.tag(), a, b);
Ok(a)
}
+ #[instrument(skip(self), level = "debug")]
fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
- debug!("{}.tys({:?}, {:?})", self.tag(), a, b);
if a == b {
return Ok(a);
}
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::steal::Steal;
use rustc_data_structures::sync::{self, Lock, Lrc, WorkerLocal};
+use rustc_data_structures::vec_map::VecMap;
use rustc_errors::ErrorReported;
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
/// this field will be set to `Some(ErrorReported)`.
pub tainted_by_errors: Option<ErrorReported>,
- /// All the opaque types that are restricted to concrete types
- /// by this function.
- pub concrete_opaque_types: FxHashSet<DefId>,
+ /// All the opaque types that have hidden types set
+ /// by this function. For return-position-impl-trait we also store the
+ /// type here, so that mir-borrowck can figure out hidden types,
+ /// even if they are only set in dead code (which doesn't show up in MIR).
+ /// For type-alias-impl-trait, this map is only used to prevent query cycles,
+ /// so the hidden types are all `None`.
+ pub concrete_opaque_types: VecMap<DefId, Option<Ty<'tcx>>>,
/// Tracks the minimum captures required for a closure;
/// see `MinCaptureInformationMap` for more details.
ty::PredicateKind::TypeWellFormedFromEnv(ty) => {
self.add_ty(ty);
}
+ ty::PredicateKind::OpaqueType(opaque, ty) => {
+ self.add_ty(opaque);
+ self.add_ty(ty);
+ }
}
}
type BreakTy = FoundFlags;
#[inline]
- #[instrument(level = "trace")]
- fn visit_ty(&mut self, t: Ty<'_>) -> ControlFlow<Self::BreakTy> {
- debug!(
- "HasTypeFlagsVisitor: t={:?} t.flags={:?} self.flags={:?}",
- t,
- t.flags(),
- self.flags
- );
- if t.flags().intersects(self.flags) {
+ #[instrument(skip(self), level = "trace")]
+ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
+ let flags = t.flags();
+ trace!(t.flags=?t.flags());
+ if flags.intersects(self.flags) {
ControlFlow::Break(FoundFlags)
} else {
ControlFlow::CONTINUE
}
#[inline]
- #[instrument(level = "trace")]
+ #[instrument(skip(self), level = "trace")]
fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
let flags = FlagComputation::for_const(c);
trace!(r.flags=?flags);
// [rfc]: https://github.com/rust-lang/rfcs/blob/master/text/2945-c-unwind-abi.md
use SpecAbi::*;
match abi {
- C { unwind } | Stdcall { unwind } | System { unwind } | Thiscall { unwind } => {
+ C { unwind }
+ | System { unwind }
+ | Cdecl { unwind }
+ | Stdcall { unwind }
+ | Fastcall { unwind }
+ | Vectorcall { unwind }
+ | Thiscall { unwind }
+ | Aapcs { unwind }
+ | Win64 { unwind }
+ | SysV64 { unwind } => {
unwind
|| (!tcx.features().c_unwind && tcx.sess.panic_strategy() == PanicStrategy::Unwind)
}
- Cdecl
- | Fastcall
- | Vectorcall
- | Aapcs
- | Win64
- | SysV64
- | PtxKernel
+ PtxKernel
| Msp430Interrupt
| X86Interrupt
| AmdGpuKernel
EfiApi => bug!("eficall abi should be selected elsewhere"),
Stdcall { .. } => Conv::X86Stdcall,
- Fastcall => Conv::X86Fastcall,
- Vectorcall => Conv::X86VectorCall,
+ Fastcall { .. } => Conv::X86Fastcall,
+ Vectorcall { .. } => Conv::X86VectorCall,
Thiscall { .. } => Conv::X86ThisCall,
C { .. } => Conv::C,
Unadjusted => Conv::C,
- Win64 => Conv::X86_64Win64,
- SysV64 => Conv::X86_64SysV,
- Aapcs => Conv::ArmAapcs,
+ Win64 { .. } => Conv::X86_64Win64,
+ SysV64 { .. } => Conv::X86_64SysV,
+ Aapcs { .. } => Conv::ArmAapcs,
CCmseNonSecureCall => Conv::CCmseNonSecureCall,
PtxKernel => Conv::PtxKernel,
Msp430Interrupt => Conv::Msp430Intr,
Wasm => Conv::C,
// These API constants ought to be more specific...
- Cdecl => Conv::C,
+ Cdecl { .. } => Conv::C,
}
}
///
/// Only used for Chalk.
TypeWellFormedFromEnv(Ty<'tcx>),
+
+ /// Represents a hidden type assignment for an opaque type.
+ /// Such obligations get processed by checking whether the item currently being
+ /// type-checked may acually define it.
+ OpaqueType(Ty<'tcx>, Ty<'tcx>),
}
/// The crate outlives map is computed during typeck and contains the
| PredicateKind::TypeOutlives(..)
| PredicateKind::ConstEvaluatable(..)
| PredicateKind::ConstEquate(..)
+ | PredicateKind::OpaqueType(..)
| PredicateKind::TypeWellFormedFromEnv(..) => None,
}
}
| PredicateKind::ClosureKind(..)
| PredicateKind::ConstEvaluatable(..)
| PredicateKind::ConstEquate(..)
+ | PredicateKind::OpaqueType(..)
| PredicateKind::TypeWellFormedFromEnv(..) => None,
}
}
}
}
-#[derive(Copy, Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable, TypeFoldable)]
+#[derive(
+ Copy,
+ Clone,
+ Debug,
+ PartialEq,
+ Eq,
+ HashStable,
+ TyEncodable,
+ TyDecodable,
+ TypeFoldable,
+ Lift
+)]
pub struct OpaqueTypeKey<'tcx> {
pub def_id: DefId,
pub substs: SubstsRef<'tcx>,
return Ok(self);
}
- return with_no_queries(|| {
- let def_key = self.tcx().def_key(def_id);
- if let Some(name) = def_key.disambiguated_data.data.get_opt_name() {
- p!(write("{}", name));
- // FIXME(eddyb) print this with `print_def_path`.
- if !substs.is_empty() {
- p!("::");
- p!(generic_delimiters(|cx| cx.comma_sep(substs.iter())));
+ let parent = self.tcx().parent(def_id).expect("opaque types always have a parent");
+ match self.tcx().def_kind(parent) {
+ DefKind::TyAlias | DefKind::AssocTy => {
+ if let ty::Opaque(d, _) = *self.tcx().type_of(parent).kind() {
+ if d == def_id {
+ // If the type alias directly starts with the `impl` of the
+ // opaque type we're printing, then skip the `::{opaque#1}`.
+ p!(print_def_path(parent, substs));
+ return Ok(self);
+ }
}
+ // Complex opaque type, e.g. `type Foo = (i32, impl Debug);`
+ p!(print_def_path(def_id, substs));
return Ok(self);
}
-
- self.pretty_print_opaque_impl_type(def_id, substs)
- });
+ _ => return self.pretty_print_opaque_impl_type(def_id, substs),
+ }
}
ty::Str => p!("str"),
ty::Generator(did, substs, movability) => {
ty::PredicateKind::TypeWellFormedFromEnv(ty) => {
p!("the type `", print(ty), "` is found in the environment")
}
+ ty::PredicateKind::OpaqueType(a, b) => {
+ p!("opaque type assigment with `", print(a), "` == `", print(b) ,"`")
+ }
}
}
ty::PredicateKind::TypeWellFormedFromEnv(ty) => {
write!(f, "TypeWellFormedFromEnv({:?})", ty)
}
+ ty::PredicateKind::OpaqueType(a, b) => {
+ write!(f, "OpaqueType({:?}, {:?})", a.kind(), b.kind())
+ }
}
}
}
ty::PredicateKind::TypeWellFormedFromEnv(ty) => {
tcx.lift(ty).map(ty::PredicateKind::TypeWellFormedFromEnv)
}
+ ty::PredicateKind::OpaqueType(opaque, ty) => {
+ Some(ty::PredicateKind::OpaqueType(tcx.lift(opaque)?, tcx.lift(ty)?))
+ }
}
}
}
/// The anonymous type of a closure. Used to represent the type of
/// `|a| a`.
+ /// For the order of the substs see the `ClosureSubsts` type's documentation.
Closure(DefId, SubstsRef<'tcx>),
/// The anonymous type of a generator. Used to represent the type of
}
}
+ pub fn expect_opaque_type(&self) -> ty::OpaqueTypeKey<'tcx> {
+ match *self.kind() {
+ Opaque(def_id, substs) => ty::OpaqueTypeKey { def_id, substs },
+ _ => bug!("`expect_opaque_type` called on non-opaque type: {}", self),
+ }
+ }
+
pub fn simd_size_and_type(&self, tcx: TyCtxt<'tcx>) -> (u64, Ty<'tcx>) {
match self.kind() {
Adt(def, substs) => {
use crate::build::matches::ArmHasGuard;
use crate::build::ForGuard::OutsideGuard;
use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder};
-use rustc_middle::mir::*;
use rustc_middle::thir::*;
+use rustc_middle::{mir::*, ty};
use rustc_session::lint::builtin::UNSAFE_OP_IN_UNSAFE_FN;
use rustc_session::lint::Level;
use rustc_span::Span;
// This return type is usually `()`, unless the block is diverging, in which case the
// return type is `!`. For the unit type, we need to actually return the unit, but in
// the case of `!`, no return value is required, as the block will never return.
- if destination_ty.is_unit() {
+ // Opaque types of empty bodies also need this unit assignment, in order to infer that their
+ // type is actually unit. Otherwise there will be no defining use found in the MIR.
+ if destination_ty.is_unit() || matches!(destination_ty.kind(), ty::Opaque(..)) {
// We only want to assign an implicit `()` as the return value of the block if the
// block does not diverge. (Otherwise, we may try to assign a unit to a `!`-type.)
this.cfg.push_assign_unit(block, source_info, destination, this.tcx);
}
}
- #[instrument(level = "debug", skip(self, record_graph))]
fn encode_node(
&mut self,
node: &NodeInfo<K>,
stat.edge_counter += edge_count as u64;
}
- debug!(?index, ?node);
let encoder = &mut self.encoder;
if self.result.is_ok() {
self.result = node.encode(encoder);
use std::borrow::Cow;
use std::collections::{BTreeMap, HashMap};
-use std::io;
-use std::io::prelude::*;
use std::mem::swap;
use std::num::FpCategory as Fp;
use std::ops::Index;
pub enum ParserError {
/// msg, line, col
SyntaxError(ErrorCode, usize, usize),
- IoError(io::ErrorKind, String),
}
// Builder and Parser have the same errors.
}
}
-fn io_error_to_error(io: io::Error) -> ParserError {
- IoError(io.kind(), io.to_string())
-}
-
impl fmt::Display for ParserError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
// FIXME this should be a nicer error
}
}
-/// Decodes a json value from an `&mut io::Read`
-pub fn from_reader(rdr: &mut dyn Read) -> Result<Json, BuilderError> {
- let mut contents = Vec::new();
- match rdr.read_to_end(&mut contents) {
- Ok(c) => c,
- Err(e) => return Err(io_error_to_error(e)),
- };
- let s = match str::from_utf8(&contents).ok() {
- Some(s) => s,
- _ => return Err(SyntaxError(NotUtf8, 0, 0)),
- };
- let mut builder = Builder::new(s.chars());
- builder.build()
-}
-
/// Decodes a json value from a string
pub fn from_str(s: &str) -> Result<Json, BuilderError> {
let mut builder = Builder::new(s.chars());
match &cx.target_spec().arch[..] {
"x86" => {
- let flavor = if abi == spec::abi::Abi::Fastcall {
+ let flavor = if let spec::abi::Abi::Fastcall { .. } = abi {
x86::Flavor::Fastcall
} else {
x86::Flavor::General
};
x86::compute_abi_info(cx, self, flavor);
}
- "x86_64" => {
- if abi == spec::abi::Abi::SysV64 {
- x86_64::compute_abi_info(cx, self);
- } else if abi == spec::abi::Abi::Win64 || cx.target_spec().is_like_windows {
- x86_win64::compute_abi_info(self);
- } else {
- x86_64::compute_abi_info(cx, self);
+ "x86_64" => match abi {
+ spec::abi::Abi::SysV64 { .. } => x86_64::compute_abi_info(cx, self),
+ spec::abi::Abi::Win64 { .. } => x86_win64::compute_abi_info(self),
+ _ => {
+ if cx.target_spec().is_like_windows {
+ x86_win64::compute_abi_info(self)
+ } else {
+ x86_64::compute_abi_info(cx, self)
+ }
}
- }
+ },
"aarch64" => aarch64::compute_abi_info(cx, self),
"amdgpu" => amdgpu::compute_abi_info(cx, self),
"arm" => arm::compute_abi_info(cx, self),
// churn. The specific values are meaningless.
Rust,
C { unwind: bool },
- Cdecl,
+ Cdecl { unwind: bool },
Stdcall { unwind: bool },
- Fastcall,
- Vectorcall,
+ Fastcall { unwind: bool },
+ Vectorcall { unwind: bool },
Thiscall { unwind: bool },
- Aapcs,
- Win64,
- SysV64,
+ Aapcs { unwind: bool },
+ Win64 { unwind: bool },
+ SysV64 { unwind: bool },
PtxKernel,
Msp430Interrupt,
X86Interrupt,
AbiData { abi: Abi::Rust, name: "Rust" },
AbiData { abi: Abi::C { unwind: false }, name: "C" },
AbiData { abi: Abi::C { unwind: true }, name: "C-unwind" },
- AbiData { abi: Abi::Cdecl, name: "cdecl" },
+ AbiData { abi: Abi::Cdecl { unwind: false }, name: "cdecl" },
+ AbiData { abi: Abi::Cdecl { unwind: true }, name: "cdecl-unwind" },
AbiData { abi: Abi::Stdcall { unwind: false }, name: "stdcall" },
AbiData { abi: Abi::Stdcall { unwind: true }, name: "stdcall-unwind" },
- AbiData { abi: Abi::Fastcall, name: "fastcall" },
- AbiData { abi: Abi::Vectorcall, name: "vectorcall" },
+ AbiData { abi: Abi::Fastcall { unwind: false }, name: "fastcall" },
+ AbiData { abi: Abi::Fastcall { unwind: true }, name: "fastcall-unwind" },
+ AbiData { abi: Abi::Vectorcall { unwind: false }, name: "vectorcall" },
+ AbiData { abi: Abi::Vectorcall { unwind: true }, name: "vectorcall-unwind" },
AbiData { abi: Abi::Thiscall { unwind: false }, name: "thiscall" },
AbiData { abi: Abi::Thiscall { unwind: true }, name: "thiscall-unwind" },
- AbiData { abi: Abi::Aapcs, name: "aapcs" },
- AbiData { abi: Abi::Win64, name: "win64" },
- AbiData { abi: Abi::SysV64, name: "sysv64" },
+ AbiData { abi: Abi::Aapcs { unwind: false }, name: "aapcs" },
+ AbiData { abi: Abi::Aapcs { unwind: true }, name: "aapcs-unwind" },
+ AbiData { abi: Abi::Win64 { unwind: false }, name: "win64" },
+ AbiData { abi: Abi::Win64 { unwind: true }, name: "win64-unwind" },
+ AbiData { abi: Abi::SysV64 { unwind: false }, name: "sysv64" },
+ AbiData { abi: Abi::SysV64 { unwind: true }, name: "sysv64-unwind" },
AbiData { abi: Abi::PtxKernel, name: "ptx-kernel" },
AbiData { abi: Abi::Msp430Interrupt, name: "msp430-interrupt" },
AbiData { abi: Abi::X86Interrupt, name: "x86-interrupt" },
C { unwind: false } => 1,
C { unwind: true } => 2,
// Platform-specific ABIs
- Cdecl => 3,
- Stdcall { unwind: false } => 4,
- Stdcall { unwind: true } => 5,
- Fastcall => 6,
- Vectorcall => 7,
- Thiscall { unwind: false } => 8,
- Thiscall { unwind: true } => 9,
- Aapcs => 10,
- Win64 => 11,
- SysV64 => 12,
- PtxKernel => 13,
- Msp430Interrupt => 14,
- X86Interrupt => 15,
- AmdGpuKernel => 16,
- EfiApi => 17,
- AvrInterrupt => 18,
- AvrNonBlockingInterrupt => 19,
- CCmseNonSecureCall => 20,
- Wasm => 21,
+ Cdecl { unwind: false } => 3,
+ Cdecl { unwind: true } => 4,
+ Stdcall { unwind: false } => 5,
+ Stdcall { unwind: true } => 6,
+ Fastcall { unwind: false } => 7,
+ Fastcall { unwind: true } => 8,
+ Vectorcall { unwind: false } => 9,
+ Vectorcall { unwind: true } => 10,
+ Thiscall { unwind: false } => 11,
+ Thiscall { unwind: true } => 12,
+ Aapcs { unwind: false } => 13,
+ Aapcs { unwind: true } => 14,
+ Win64 { unwind: false } => 15,
+ Win64 { unwind: true } => 16,
+ SysV64 { unwind: false } => 17,
+ SysV64 { unwind: true } => 18,
+ PtxKernel => 19,
+ Msp430Interrupt => 20,
+ X86Interrupt => 21,
+ AmdGpuKernel => 22,
+ EfiApi => 23,
+ AvrInterrupt => 24,
+ AvrNonBlockingInterrupt => 25,
+ CCmseNonSecureCall => 26,
+ Wasm => 27,
// Cross-platform ABIs
- System { unwind: false } => 22,
- System { unwind: true } => 23,
- RustIntrinsic => 24,
- RustCall => 25,
- PlatformIntrinsic => 26,
- Unadjusted => 27,
+ System { unwind: false } => 28,
+ System { unwind: true } => 29,
+ RustIntrinsic => 30,
+ RustCall => 31,
+ PlatformIntrinsic => 32,
+ Unadjusted => 33,
};
debug_assert!(
AbiDatas
Abi::Stdcall { unwind }
}
Abi::System { unwind } => Abi::C { unwind },
- Abi::EfiApi if self.arch == "x86_64" => Abi::Win64,
+ Abi::EfiApi if self.arch == "x86_64" => Abi::Win64 { unwind: false },
Abi::EfiApi => Abi::C { unwind: false },
// See commentary in `is_abi_supported`.
Abi::Stdcall { .. } | Abi::Thiscall { .. } if self.arch == "x86" => abi,
Abi::Stdcall { unwind } | Abi::Thiscall { unwind } => Abi::C { unwind },
- Abi::Fastcall if self.arch == "x86" => abi,
- Abi::Vectorcall if ["x86", "x86_64"].contains(&&self.arch[..]) => abi,
- Abi::Fastcall | Abi::Vectorcall => Abi::C { unwind: false },
+ Abi::Fastcall { .. } if self.arch == "x86" => abi,
+ Abi::Vectorcall { .. } if ["x86", "x86_64"].contains(&&self.arch[..]) => abi,
+ Abi::Fastcall { unwind } | Abi::Vectorcall { unwind } => Abi::C { unwind },
abi => abi,
}
| RustCall
| PlatformIntrinsic
| Unadjusted
- | Cdecl
+ | Cdecl { .. }
| EfiApi => true,
X86Interrupt => ["x86", "x86_64"].contains(&&self.arch[..]),
- Aapcs => "arm" == self.arch,
+ Aapcs { .. } => "arm" == self.arch,
CCmseNonSecureCall => ["arm", "aarch64"].contains(&&self.arch[..]),
- Win64 | SysV64 => self.arch == "x86_64",
+ Win64 { .. } | SysV64 { .. } => self.arch == "x86_64",
PtxKernel => self.arch == "nvptx64",
Msp430Interrupt => self.arch == "msp430",
AmdGpuKernel => self.arch == "amdgcn",
// > convention is used.
//
// -- https://docs.microsoft.com/en-us/cpp/cpp/argument-passing-and-naming-conventions
- Stdcall { .. } | Fastcall | Vectorcall if self.is_like_windows => true,
+ Stdcall { .. } | Fastcall { .. } | Vectorcall { .. } if self.is_like_windows => true,
// Outside of Windows we want to only support these calling conventions for the
// architectures for which these calling conventions are actually well defined.
- Stdcall { .. } | Fastcall if self.arch == "x86" => true,
- Vectorcall if ["x86", "x86_64"].contains(&&self.arch[..]) => true,
+ Stdcall { .. } | Fastcall { .. } if self.arch == "x86" => true,
+ Vectorcall { .. } if ["x86", "x86_64"].contains(&&self.arch[..]) => true,
// Return a `None` for other cases so that we know to emit a future compat lint.
- Stdcall { .. } | Fastcall | Vectorcall => return None,
+ Stdcall { .. } | Fastcall { .. } | Vectorcall { .. } => return None,
})
}
use std::fs;
fn load_file(path: &Path) -> Result<(Target, TargetWarnings), String> {
- let contents = fs::read(path).map_err(|e| e.to_string())?;
- let obj = json::from_reader(&mut &contents[..]).map_err(|e| e.to_string())?;
+ let contents = fs::read_to_string(path).map_err(|e| e.to_string())?;
+ let obj = json::from_str(&contents).map_err(|e| e.to_string())?;
Target::from_json(obj)
}
/// purpose of this function is to do that translation.
///
/// (*) C1 and C2 were introduced in the comments on
- /// `constrain_opaque_type`. Read that comment for more context.
+ /// `register_member_constraints`. Read that comment for more context.
///
/// # Parameters
///
instantiated_ty: Ty<'tcx>,
span: Span,
) -> 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
// after producing an error for each of them.
let definition_ty = instantiated_ty.fold_with(&mut ReverseMapper::new(
self.tcx,
- self.is_tainted_by_errors(),
def_id,
map,
instantiated_ty,
struct ReverseMapper<'tcx> {
tcx: TyCtxt<'tcx>,
- /// If errors have already been reported in this fn, we suppress
- /// our own errors because they are sometimes derivative.
- tainted_by_errors: bool,
-
opaque_type_def_id: DefId,
map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>>,
map_missing_regions_to_empty: bool,
impl<'tcx> ReverseMapper<'tcx> {
fn new(
tcx: TyCtxt<'tcx>,
- tainted_by_errors: bool,
opaque_type_def_id: DefId,
map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>>,
hidden_ty: Ty<'tcx>,
) -> Self {
Self {
tcx,
- tainted_by_errors,
opaque_type_def_id,
map,
map_missing_regions_to_empty: false,
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.tainted_by_errors => {
- self.tcx.lifetimes.re_root_empty
- }
+ 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(
| ty::PredicateKind::RegionOutlives(..)
| ty::PredicateKind::ConstEvaluatable(..)
| ty::PredicateKind::ConstEquate(..)
+ | ty::PredicateKind::OpaqueType(..)
| ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ref t, ref r)) => {
// Search for a bound of the form `erased_self_ty
| ty::PredicateKind::Subtype(..)
| ty::PredicateKind::ConstEvaluatable(..)
| ty::PredicateKind::Coerce(..)
+ | ty::PredicateKind::OpaqueType(..)
| ty::PredicateKind::TypeWellFormedFromEnv(..) => {}
};
}
});
let impl_source = drain_fulfillment_cx_or_panic(&infcx, &mut fulfill_cx, impl_source);
+ // We may constrain the hidden types of opaque types in this query, but this is
+ // not information our callers need, as all that information is handled by borrowck
+ // and typeck.
+ drop(infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types());
+
debug!("Cache miss: {:?} => {:?}", trait_ref, impl_source);
Ok(impl_source)
})
span,
"TypeWellFormedFromEnv predicate should only exist in the environment"
),
+
+ ty::PredicateKind::OpaqueType(..) => {
+ todo!("{:#?}", obligation);
+ }
}
}
normalized_ty,
data.term,
) {
- values = Some(match (normalized_ty, data.term) {
- (ty::Term::Ty(normalized_ty), ty::Term::Ty(ty)) => {
- infer::ValuePairs::Types(ExpectedFound::new(
- is_normalized_ty_expected,
- normalized_ty,
- ty,
- ))
- }
- (ty::Term::Const(normalized_ct), ty::Term::Const(ct)) => {
- infer::ValuePairs::Consts(ExpectedFound::new(
- is_normalized_ty_expected,
- normalized_ct,
- ct,
- ))
- }
- (_, _) => span_bug!(
- obligation.cause.span,
- "found const or type where other expected"
- ),
- });
+ values = Some(infer::ValuePairs::Terms(ExpectedFound::new(
+ is_normalized_ty_expected,
+ normalized_ty,
+ data.term,
+ )));
err_buf = error;
err = &err_buf;
}
ty::Generator(..) => "generator",
_ => "function",
};
+ let span = self.tcx.sess.source_map().guess_head_span(span);
let mut err = struct_span_err!(
self.tcx.sess,
span,
));
let original_span = err.span.primary_span().unwrap();
+ let original_span = self.tcx.sess.source_map().guess_head_span(original_span);
let mut span = MultiSpan::from_span(original_span);
let message = outer_generator
ty::PredicateKind::TypeWellFormedFromEnv(..) => {
bug!("TypeWellFormedFromEnv is only used for Chalk")
}
+ ty::PredicateKind::OpaqueType(..) => {
+ todo!("{:#?}", obligation);
+ }
},
Some(pred) => match pred {
ty::PredicateKind::Trait(data) => {
ty::PredicateKind::TypeWellFormedFromEnv(..) => {
bug!("TypeWellFormedFromEnv is only used for Chalk")
}
+ ty::PredicateKind::OpaqueType(a, b) => {
+ match self.selcx.infcx().handle_opaque_type(
+ a,
+ b,
+ &obligation.cause,
+ obligation.param_env,
+ ) {
+ Ok(value) => ProcessResult::Changed(mk_pending(value.obligations)),
+ Err(err) => ProcessResult::Error(FulfillmentErrorCode::CodeSubtypeError(
+ ExpectedFound::new(true, a, b),
+ err,
+ )),
+ }
+ }
},
}
}
| ty::PredicateKind::Coerce(..)
| ty::PredicateKind::ConstEvaluatable(..)
| ty::PredicateKind::ConstEquate(..)
+ | ty::PredicateKind::OpaqueType(..)
| ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
}
}
| ty::PredicateKind::TypeOutlives(..)
| ty::PredicateKind::ConstEvaluatable(..)
| ty::PredicateKind::ConstEquate(..)
+ | ty::PredicateKind::OpaqueType(..)
| ty::PredicateKind::TypeWellFormedFromEnv(..) => false,
}
})
use crate::traits::engine::TraitEngineExt as _;
use crate::traits::query::type_op::TypeOpOutput;
use crate::traits::query::Fallible;
-use crate::traits::{ObligationCause, TraitEngine};
+use crate::traits::TraitEngine;
use rustc_infer::traits::TraitEngineExt as _;
use rustc_span::source_map::DUMMY_SP;
op: impl FnOnce() -> Fallible<InferOk<'tcx, R>>,
) -> Fallible<TypeOpOutput<'tcx, Op>> {
let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
- let dummy_body_id = ObligationCause::dummy().body_id;
// During NLL, we expect that nobody will register region
// obligations **except** as part of a custom type op (and, at the
);
let InferOk { value, obligations } = infcx.commit_if_ok(|_| op())?;
- debug_assert!(obligations.iter().all(|o| o.cause.body_id == dummy_body_id));
fulfill_cx.register_predicate_obligations(infcx, obligations);
let errors = fulfill_cx.select_all_or_error(infcx);
if !errors.is_empty() {
};
if obligation.predicate.skip_binder().self_ty().is_ty_var() {
+ debug!(ty = ?obligation.predicate.skip_binder().self_ty(), "ambiguous inference var or opaque type");
// Self is a type variable (e.g., `_: AsRef<str>`).
//
// This is somewhat problematic, as the current scheme can't really
use rustc_middle::mir::interpret::ErrorHandled;
use rustc_middle::thir::abstract_const::NotConstEvaluatable;
use rustc_middle::ty::fast_reject::{self, SimplifyParams, StripReferences};
+use rustc_middle::ty::fold::BottomUpFolder;
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::relate::TypeRelation;
use rustc_middle::ty::subst::{GenericArgKind, Subst, SubstsRef};
ty::PredicateKind::TypeWellFormedFromEnv(..) => {
bug!("TypeWellFormedFromEnv is only used for chalk")
}
+ ty::PredicateKind::OpaqueType(a, b) => {
+ match self.infcx().handle_opaque_type(
+ a,
+ b,
+ &obligation.cause,
+ obligation.param_env,
+ ) {
+ Ok(res) => {
+ self.evaluate_predicates_recursively(previous_stack, res.obligations)
+ }
+ Err(_) => Ok(EvaluatedToErr),
+ }
+ }
}
});
}
}
+ #[instrument(skip(self, param_env, cache_fresh_trait_pred, dep_node), level = "debug")]
fn insert_candidate_cache(
&mut self,
mut param_env: ty::ParamEnv<'tcx>,
/// a projection, look at the bounds of `T::Bar`, see if we can find a
/// `Baz` bound. We return indexes into the list returned by
/// `tcx.item_bounds` for any applicable bounds.
+ #[instrument(level = "debug", skip(self))]
fn match_projection_obligation_against_definition_bounds(
&mut self,
obligation: &TraitObligation<'tcx>,
let poly_trait_predicate = self.infcx().resolve_vars_if_possible(obligation.predicate);
let placeholder_trait_predicate =
self.infcx().replace_bound_vars_with_placeholders(poly_trait_predicate);
- debug!(
- ?placeholder_trait_predicate,
- "match_projection_obligation_against_definition_bounds"
- );
+ debug!(?placeholder_trait_predicate);
let tcx = self.infcx.tcx;
let (def_id, substs) = match *placeholder_trait_predicate.trait_ref.self_ty().kind() {
})
.collect();
- debug!(?matching_bounds, "match_projection_obligation_against_definition_bounds");
+ debug!(?matching_bounds);
matching_bounds
}
});
self.infcx
.at(&obligation.cause, obligation.param_env)
+ .define_opaque_types(false)
.sup(ty::Binder::dummy(placeholder_trait_ref), trait_bound)
.map(|InferOk { obligations: _, value: () }| {
// This method is called within a probe, so we can't have
self.infcx
.at(&obligation.cause, obligation.param_env)
+ .define_opaque_types(false)
.sup(obligation.predicate, infer_projection)
.map_or(false, |InferOk { obligations, value: () }| {
self.evaluate_predicates_recursively(
match self.match_impl(impl_def_id, obligation) {
Ok(substs) => substs,
Err(()) => {
- bug!(
- "Impl {:?} was matchable against {:?} but now is not",
- impl_def_id,
- obligation
+ self.infcx.tcx.sess.delay_span_bug(
+ obligation.cause.span,
+ &format!(
+ "Impl {:?} was matchable against {:?} but now is not",
+ impl_def_id, obligation
+ ),
);
+ let value = self.infcx.fresh_substs_for_item(obligation.cause.span, impl_def_id);
+ let err = self.tcx().ty_error();
+ let value = value.fold_with(&mut BottomUpFolder {
+ tcx: self.tcx(),
+ ty_op: |_| err,
+ lt_op: |l| l,
+ ct_op: |c| c,
+ });
+ Normalized { value, obligations: vec![] }
}
}
}
) -> Result<Vec<PredicateObligation<'tcx>>, ()> {
self.infcx
.at(&obligation.cause, obligation.param_env)
+ // We don't want predicates for opaque types to just match all other types,
+ // if there is an obligation on the opaque type, then that obligation must be met
+ // opaquely. Otherwise we'd match any obligation to the opaque type and then error
+ // out later.
+ .define_opaque_types(false)
.sup(obligation.predicate.to_poly_trait_ref(), poly_trait_ref)
.map(|InferOk { obligations, .. }| obligations)
.map_err(|_| ())
wf.compute(c1.into());
wf.compute(c2.into());
}
+ ty::PredicateKind::OpaqueType(opaque, ty) => {
+ wf.compute(opaque.into());
+ wf.compute(ty.into());
+ }
ty::PredicateKind::TypeWellFormedFromEnv(..) => {
bug!("TypeWellFormedFromEnv is only used for Chalk")
}
| ty::PredicateKind::ClosureKind(..)
| ty::PredicateKind::Subtype(..)
| ty::PredicateKind::Coerce(..)
+ | ty::PredicateKind::OpaqueType(..)
| ty::PredicateKind::ConstEvaluatable(..)
| ty::PredicateKind::ConstEquate(..) => bug!("unexpected predicate {}", predicate),
};
| ty::PredicateKind::Subtype(..)
| ty::PredicateKind::Coerce(..)
| ty::PredicateKind::ConstEvaluatable(..)
+ | ty::PredicateKind::OpaqueType(..)
| ty::PredicateKind::ConstEquate(..) => {
chalk_ir::GoalData::All(chalk_ir::Goals::empty(interner))
}
| ty::PredicateKind::Coerce(..)
| ty::PredicateKind::ConstEvaluatable(..)
| ty::PredicateKind::ConstEquate(..)
+ | ty::PredicateKind::OpaqueType(..)
| ty::PredicateKind::TypeWellFormedFromEnv(..) => {
bug!("unexpected predicate {}", &self)
}
| ty::PredicateKind::Coerce(..)
| ty::PredicateKind::ConstEvaluatable(..)
| ty::PredicateKind::ConstEquate(..)
+ | ty::PredicateKind::OpaqueType(..)
| ty::PredicateKind::TypeWellFormedFromEnv(..) => {
bug!("unexpected predicate {}", &self)
}
var_values: CanonicalVarValues { var_values },
region_constraints: QueryRegionConstraints::default(),
certainty: Certainty::Proven,
+ opaque_types: vec![],
value: (),
},
};
.make_identity(tcx),
region_constraints: QueryRegionConstraints::default(),
certainty: Certainty::Ambiguous,
+ opaque_types: vec![],
value: (),
},
};
| ty::PredicateKind::ObjectSafe(..)
| ty::PredicateKind::ConstEvaluatable(..)
| ty::PredicateKind::ConstEquate(..)
+ | ty::PredicateKind::OpaqueType(..)
| ty::PredicateKind::TypeWellFormedFromEnv(..) => vec![],
ty::PredicateKind::WellFormed(arg) => {
wf_args.push(arg);
| ty::PredicateKind::Coerce(..)
| ty::PredicateKind::ConstEvaluatable(..)
| ty::PredicateKind::ConstEquate(..)
+ | ty::PredicateKind::OpaqueType(..)
| ty::PredicateKind::TypeWellFormedFromEnv(..) => true,
}
}
| TypeFlags::HAS_CT_INFER.bits
| TypeFlags::HAS_TY_PLACEHOLDER.bits
| TypeFlags::HAS_CT_PLACEHOLDER.bits
+ // The `evaluate_obligation` query does not return further
+ // obligations. If it evaluates an obligation with an opaque
+ // type, that opaque type may get compared to another type,
+ // constraining it. We would lose this information.
+ // FIXME: differentiate between crate-local opaque types
+ // and opaque types from other crates, as only opaque types
+ // from the local crate can possibly be a local name
+ | TypeFlags::HAS_TY_OPAQUE.bits
// We consider 'freshened' types and constants
// to depend on a particular fn.
// The freshening process throws away information,
use rustc_hir::{self as hir, ExprKind};
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::traits::Obligation;
-use rustc_middle::ty::{self, ToPredicate, Ty, TyS};
+use rustc_middle::ty::{self, ToPredicate, Ty, TyS, TypeFoldable};
use rustc_span::{MultiSpan, Span};
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
use rustc_trait_selection::traits::{
let arm_ty = self.check_expr_with_expectation(&arm.body, expected);
all_arms_diverge &= self.diverges.get();
- let opt_suggest_box_span =
- self.opt_suggest_box_span(arm.body.span, arm_ty, orig_expected);
+ let opt_suggest_box_span = self.opt_suggest_box_span(arm_ty, orig_expected);
let (arm_span, semi_span) =
self.get_appropriate_arm_semicolon_removal_span(&arms, i, prior_arm_ty, arm_ty);
// provide a structured suggestion in that case.
pub(crate) fn opt_suggest_box_span(
&self,
- span: Span,
outer_ty: &'tcx TyS<'tcx>,
orig_expected: Expectation<'tcx>,
) -> Option<Span> {
- match (orig_expected, self.ret_coercion_impl_trait.map(|ty| (self.body_id.owner, ty))) {
- (Expectation::ExpectHasType(expected), Some((_id, ty)))
- if self.in_tail_expr && self.can_coerce(outer_ty, expected) =>
+ match orig_expected {
+ Expectation::ExpectHasType(expected)
+ if self.in_tail_expr
+ && self.ret_coercion.as_ref()?.borrow().merged_ty().has_opaque_types()
+ && self.can_coerce(outer_ty, expected) =>
{
- let impl_trait_ret_ty =
- self.infcx.instantiate_opaque_types(self.body_id, self.param_env, ty, span);
- assert!(
- impl_trait_ret_ty.obligations.is_empty(),
- "we should never get new obligations here"
- );
let obligations = self.fulfillment_cx.borrow().pending_obligations();
let mut suggest_box = !obligations.is_empty();
for o in obligations {
expected: Expectation<'tcx>,
fn_sig: ty::FnSig<'tcx>,
) -> Ty<'tcx> {
- // `fn_sig` is the *signature* of the cosure being called. We
+ // `fn_sig` is the *signature* of the closure being called. We
// don't know the full details yet (`Fn` vs `FnMut` etc), but we
// do know the types expected for each argument and the return
// type.
use rustc_middle::ty::layout::MAX_SIMD_LANES;
use rustc_middle::ty::subst::GenericArgKind;
use rustc_middle::ty::util::{Discr, IntTypeExt};
-use rustc_middle::ty::{self, OpaqueTypeKey, ParamEnv, RegionKind, Ty, TyCtxt};
+use rustc_middle::ty::{self, ParamEnv, RegionKind, Ty, TyCtxt};
use rustc_session::lint::builtin::{UNINHABITED_STATIC, UNSUPPORTED_CALLING_CONVENTIONS};
use rustc_span::symbol::sym;
use rustc_span::{self, MultiSpan, Span};
can_be_generator: Option<hir::Movability>,
return_type_pre_known: bool,
) -> (FnCtxt<'a, 'tcx>, Option<GeneratorTypes<'tcx>>) {
- let mut fn_sig = fn_sig;
-
// Create the function context. This is either derived from scratch or,
// in the case of closures, based on the outer context.
let mut fcx = FnCtxt::new(inherited, param_env, body.value.hir_id);
let declared_ret_ty = fn_sig.output();
- let revealed_ret_ty =
- fcx.instantiate_opaque_types_from_value(declared_ret_ty, decl.output.span());
- debug!("check_fn: declared_ret_ty: {}, revealed_ret_ty: {}", declared_ret_ty, revealed_ret_ty);
- fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(revealed_ret_ty)));
+ fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(declared_ret_ty)));
fcx.ret_type_span = Some(decl.output.span());
- if let ty::Opaque(..) = declared_ret_ty.kind() {
- fcx.ret_coercion_impl_trait = Some(declared_ret_ty);
- }
- fn_sig = tcx.mk_fn_sig(
- fn_sig.inputs().iter().cloned(),
- revealed_ret_ty,
- fn_sig.c_variadic,
- fn_sig.unsafety,
- fn_sig.abi,
- );
let span = body.value.span;
fcx.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::DynReturnFn, span });
debug!("actual_return_ty replaced with {:?}", actual_return_ty);
}
- fcx.demand_suptype(span, revealed_ret_ty, actual_return_ty);
+ fcx.demand_suptype(span, declared_ret_ty, actual_return_ty);
// Check that a function marked as `#[panic_handler]` has signature `fn(&PanicInfo) -> !`
if let Some(panic_impl_did) = tcx.lang_items().panic_impl() {
span: Span,
origin: &hir::OpaqueTyOrigin,
) {
+ let hidden_type = tcx.type_of(def_id).subst(tcx, substs);
+
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
let defining_use_anchor = match *origin {
hir::OpaqueTyOrigin::FnReturn(did) | hir::OpaqueTyOrigin::AsyncFn(did) => did,
let misc_cause = traits::ObligationCause::misc(span, hir_id);
- let _ = inh.register_infer_ok_obligations(
- infcx.instantiate_opaque_types(hir_id, param_env, opaque_ty, span),
- );
-
- let opaque_type_map = infcx.inner.borrow().opaque_types.clone();
- for (OpaqueTypeKey { def_id, substs }, opaque_defn) in opaque_type_map {
- let hidden_type = tcx.type_of(def_id).subst(tcx, substs);
- trace!(?hidden_type);
- match infcx.at(&misc_cause, param_env).eq(opaque_defn.concrete_ty, hidden_type) {
- Ok(infer_ok) => inh.register_infer_ok_obligations(infer_ok),
- Err(ty_err) => tcx.sess.delay_span_bug(
- span,
- &format!(
- "could not check bounds on revealed type `{}`:\n{}",
- hidden_type, ty_err,
- ),
- ),
- }
+ match infcx.at(&misc_cause, param_env).eq(opaque_ty, hidden_type) {
+ Ok(infer_ok) => inh.register_infer_ok_obligations(infer_ok),
+ Err(ty_err) => tcx.sess.delay_span_bug(
+ span,
+ &format!("could not unify `{}` with revealed type:\n{}", hidden_type, ty_err,),
+ ),
}
// Check that all obligations are satisfied by the implementation's
match origin {
// Checked when type checking the function containing them.
- hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) => return,
+ hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) => {}
// Can have different predicates to their defining use
hir::OpaqueTyOrigin::TyAlias => {
// Finally, resolve all regions. This catches wily misuses of
fcx.regionck_item(hir_id, span, FxHashSet::default());
}
}
+
+ // Clean up after ourselves
+ let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
});
}
use super::{check_fn, Expectation, FnCtxt, GeneratorTypes};
use crate::astconv::AstConv;
+use crate::rustc_middle::ty::subst::Subst;
+use hir::OpaqueTyOrigin;
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_hir::lang_items::LangItem;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::LateBoundRegionConversionTime;
use rustc_infer::infer::{InferOk, InferResult};
+use rustc_infer::traits::ObligationCause;
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::subst::InternalSubsts;
use rustc_middle::ty::{self, Ty};
use rustc_span::source_map::Span;
+use rustc_span::DUMMY_SP;
use rustc_target::spec::abi::Abi;
use rustc_trait_selection::traits::error_reporting::ArgKind;
use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
expected_ty: Ty<'tcx>,
) -> (Option<ExpectedSig<'tcx>>, Option<ty::ClosureKind>) {
match *expected_ty.kind() {
+ ty::Opaque(def_id, substs) => {
+ let bounds = self.tcx.explicit_item_bounds(def_id);
+ let sig = bounds.iter().find_map(|(pred, span)| match pred.kind().skip_binder() {
+ ty::PredicateKind::Projection(proj_predicate) => self
+ .deduce_sig_from_projection(
+ Some(*span),
+ pred.kind().rebind(proj_predicate.subst(self.tcx, substs)),
+ ),
+ _ => None,
+ });
+
+ let kind = bounds
+ .iter()
+ .filter_map(|(pred, _)| match pred.kind().skip_binder() {
+ ty::PredicateKind::Trait(tp) => {
+ self.tcx.fn_trait_kind_from_lang_item(tp.def_id())
+ }
+ _ => None,
+ })
+ .fold(None, |best, cur| Some(best.map_or(cur, |best| cmp::min(best, cur))));
+ trace!(?sig, ?kind);
+ (sig, kind)
+ }
ty::Dynamic(ref object_type, ..) => {
let sig = object_type.projection_bounds().find_map(|pb| {
let pb = pb.with_self_ty(self.tcx, self.tcx.types.trait_object_dummy_self);
) -> (Option<ExpectedSig<'tcx>>, Option<ty::ClosureKind>) {
let expected_sig =
self.obligations_for_self_ty(expected_vid).find_map(|(_, obligation)| {
- debug!(
- "deduce_expectations_from_obligations: obligation.predicate={:?}",
- obligation.predicate
- );
+ debug!(?obligation.predicate);
let bound_predicate = obligation.predicate.kind();
if let ty::PredicateKind::Projection(proj_predicate) =
// in this binder we are creating.
assert!(!expected_sig.sig.skip_binder().has_vars_bound_above(ty::INNERMOST));
let bound_sig = expected_sig.sig.map_bound(|sig| {
+ let output = self.hide_parent_opaque_types(
+ sig.output(),
+ expected_sig.cause_span.unwrap_or(DUMMY_SP),
+ body.id().hir_id,
+ );
self.tcx.mk_fn_sig(
sig.inputs().iter().cloned(),
- sig.output(),
+ output,
sig.c_variadic,
hir::Unsafety::Normal,
Abi::RustCall,
_ => astconv.ty_infer(None, decl.output.span()),
},
};
+ let supplied_return =
+ self.hide_parent_opaque_types(supplied_return, decl.output.span(), body.id().hir_id);
let result = ty::Binder::bind_with_vars(
self.tcx.mk_fn_sig(
result
}
+ fn hide_parent_opaque_types(&self, ty: Ty<'tcx>, span: Span, body_id: hir::HirId) -> Ty<'tcx> {
+ ty.fold_with(&mut ty::fold::BottomUpFolder {
+ tcx: self.infcx.tcx,
+ lt_op: |lt| lt,
+ ct_op: |ct| ct,
+ ty_op: |ty| match *ty.kind() {
+ // Closures can't create hidden types for opaque types of their parent, as they
+ // do not have all the outlives information available. Also `type_of` looks for
+ // hidden types in the owner (so the closure's parent), so it would not find these
+ // definitions.
+ ty::Opaque(def_id, _substs)
+ if matches!(
+ self.infcx.opaque_type_origin(def_id, DUMMY_SP),
+ Some(OpaqueTyOrigin::FnReturn(..))
+ ) =>
+ {
+ let ty_var = self.next_ty_var(TypeVariableOrigin {
+ kind: TypeVariableOriginKind::TypeInference,
+ span,
+ });
+ let cause = ObligationCause::misc(span, body_id);
+ self.register_predicates(vec![self.infcx.opaque_ty_obligation(
+ ty,
+ ty_var,
+ true,
+ self.param_env,
+ cause,
+ )]);
+ ty_var
+ }
+ _ => ty,
+ },
+ })
+ }
+
/// Invoked when we are translating the generator that results
/// from desugaring an `async fn`. Returns the "sugared" return
/// type of the `async fn` -- that is, the return type that the
/// user specified. The "desugared" return type is an `impl
/// Future<Output = T>`, so we do this by searching through the
/// obligations to extract the `T`.
+ #[instrument(skip(self), level = "debug")]
fn deduce_future_output_from_obligations(&self, expr_def_id: DefId) -> Option<Ty<'tcx>> {
- debug!("deduce_future_output_from_obligations(expr_def_id={:?})", expr_def_id);
-
let ret_coercion = self.ret_coercion.as_ref().unwrap_or_else(|| {
span_bug!(self.tcx.def_span(expr_def_id), "async fn generator outside of a fn")
});
- // In practice, the return type of the surrounding function is
- // always a (not yet resolved) inference variable, because it
- // is the hidden type for an `impl Trait` that we are going to
- // be inferring.
let ret_ty = ret_coercion.borrow().expected_ty();
let ret_ty = self.inh.infcx.shallow_resolve(ret_ty);
- let ret_vid = match *ret_ty.kind() {
- ty::Infer(ty::TyVar(ret_vid)) => ret_vid,
+ let (def_id, substs) = match *ret_ty.kind() {
+ ty::Opaque(def_id, substs) => (def_id, substs),
ty::Error(_) => return None,
_ => span_bug!(
self.tcx.def_span(expr_def_id),
),
};
+ let item_bounds = self.tcx.explicit_item_bounds(def_id);
+
// Search for a pending obligation like
//
// `<R as Future>::Output = T`
//
// where R is the return type we are expecting. This type `T`
// will be our output.
- let output_ty = self.obligations_for_self_ty(ret_vid).find_map(|(_, obligation)| {
- let bound_predicate = obligation.predicate.kind();
+ let output_ty = item_bounds.iter().find_map(|&(predicate, span)| {
+ let bound_predicate = predicate.subst(self.tcx, substs).kind();
if let ty::PredicateKind::Projection(proj_predicate) = bound_predicate.skip_binder() {
self.deduce_future_output_from_projection(
- obligation.cause.span,
+ span,
bound_predicate.rebind(proj_predicate),
)
} else {
/// Returns the current "merged type", representing our best-guess
/// at the LUB of the expressions we've seen so far (if any). This
- /// isn't *final* until you call `self.final()`, which will return
+ /// isn't *final* until you call `self.complete()`, which will return
/// the merged type.
pub fn merged_ty(&self) -> Ty<'tcx> {
self.final_ty.unwrap_or(self.expected_ty)
&mut diag,
&cause,
trait_err_span.map(|sp| (sp, "type in trait".to_owned())),
- Some(infer::ValuePairs::Types(ExpectedFound {
- expected: trait_fty,
- found: impl_fty,
+ Some(infer::ValuePairs::Terms(ExpectedFound {
+ expected: trait_fty.into(),
+ found: impl_fty.into(),
})),
&terr,
false,
&mut diag,
&cause,
trait_c_span.map(|span| (span, "type in trait".to_owned())),
- Some(infer::ValuePairs::Types(ExpectedFound {
- expected: trait_ty,
- found: impl_ty,
+ Some(infer::ValuePairs::Terms(ExpectedFound {
+ expected: trait_ty.into(),
+ found: impl_ty.into(),
})),
&terr,
false,
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_middle::ty::{self, Ty};
+use rustc_span::DUMMY_SP;
use rustc_span::{self, Span};
use super::Expectation::*;
// when checking the 'then' block which are incompatible with the
// 'else' branch.
pub(super) fn adjust_for_branches(&self, fcx: &FnCtxt<'a, 'tcx>) -> Expectation<'tcx> {
- match *self {
+ match self.strip_opaque(fcx) {
ExpectHasType(ety) => {
let ety = fcx.shallow_resolve(ety);
if !ety.is_ty_var() { ExpectHasType(ety) } else { NoExpectation }
/// for the program to type-check). `only_has_type` will return
/// such a constraint, if it exists.
pub(super) fn only_has_type(self, fcx: &FnCtxt<'a, 'tcx>) -> Option<Ty<'tcx>> {
- match self {
- ExpectHasType(ty) => Some(fcx.resolve_vars_if_possible(ty)),
+ match self.strip_opaque(fcx) {
+ ExpectHasType(ty) => Some(ty),
NoExpectation | ExpectCastableToType(_) | ExpectRvalueLikeUnsized(_) | IsLast(_) => {
None
}
}
}
+ /// We must not treat opaque types as expected types in their defining scope, as that
+ /// will break `fn foo() -> impl Trait { if cond { a } else { b } }` if `a` and `b` are
+ /// only "equal" if they coerce to a common target, like two different function items
+ /// coercing to a function pointer if they have the same signature.
+ fn strip_opaque(self, fcx: &FnCtxt<'a, 'tcx>) -> Self {
+ match self {
+ ExpectHasType(ty) => {
+ let ty = fcx.resolve_vars_if_possible(ty);
+ match *ty.kind() {
+ ty::Opaque(def_id, _)
+ if fcx.infcx.opaque_type_origin(def_id, DUMMY_SP).is_some() =>
+ {
+ NoExpectation
+ }
+ _ => self,
+ }
+ }
+ _ => self,
+ }
+ }
+
/// Like `only_has_type`, but instead of returning `None` if no
/// hard constraint exists, creates a fresh type variable.
pub(super) fn coercion_target_type(self, fcx: &FnCtxt<'a, 'tcx>, span: Span) -> Ty<'tcx> {
};
let else_diverges = self.diverges.get();
- let opt_suggest_box_span =
- self.opt_suggest_box_span(else_expr.span, else_ty, orig_expected);
+ let opt_suggest_box_span = self.opt_suggest_box_span(else_ty, orig_expected);
let if_cause =
self.if_cause(sp, then_expr, else_expr, then_ty, else_ty, opt_suggest_box_span);
self.fulfillment_cx.borrow_mut().pending_obligations()
);
- // Check if we have any unsolved varibales. If not, no need for fallback.
+ // Check if we have any unsolved variables. If not, no need for fallback.
let unsolved_variables = self.unsolved_variables();
if unsolved_variables.is_empty() {
return false;
// refer to opaque types.
self.select_obligations_where_possible(fallback_has_occurred, |_| {});
- // We now run fallback again, but this time we allow it to replace
- // unconstrained opaque type variables, in addition to performing
- // other kinds of fallback.
- for ty in &self.unsolved_variables() {
- fallback_has_occurred |= self.fallback_opaque_type_vars(ty);
- }
-
- // See if we can make any more progress.
- self.select_obligations_where_possible(fallback_has_occurred, |_| {});
-
fallback_has_occurred
}
true
}
- /// Second round of fallback: Unconstrained type variables created
- /// from the instantiation of an opaque type fall back to the
- /// opaque type itself. This is a somewhat incomplete attempt to
- /// manage "identity passthrough" for `impl Trait` types.
- ///
- /// For example, in this code:
- ///
- ///```
- /// type MyType = impl Copy;
- /// fn defining_use() -> MyType { true }
- /// fn other_use() -> MyType { defining_use() }
- /// ```
- ///
- /// `defining_use` will constrain the instantiated inference
- /// variable to `bool`, while `other_use` will constrain
- /// the instantiated inference variable to `MyType`.
- ///
- /// When we process opaque types during writeback, we
- /// will handle cases like `other_use`, and not count
- /// them as defining usages
- ///
- /// However, we also need to handle cases like this:
- ///
- /// ```rust
- /// pub type Foo = impl Copy;
- /// fn produce() -> Option<Foo> {
- /// None
- /// }
- /// ```
- ///
- /// In the above snippet, the inference variable created by
- /// instantiating `Option<Foo>` will be completely unconstrained.
- /// We treat this as a non-defining use by making the inference
- /// variable fall back to the opaque type itself.
- fn fallback_opaque_type_vars(&self, ty: Ty<'tcx>) -> bool {
- let span = self
- .infcx
- .type_var_origin(ty)
- .map(|origin| origin.span)
- .unwrap_or(rustc_span::DUMMY_SP);
- let oty = self.inner.borrow().opaque_types_vars.get(ty).copied();
- if let Some(opaque_ty) = oty {
- debug!(
- "fallback_opaque_type_vars(ty={:?}): falling back to opaque type {:?}",
- ty, opaque_ty
- );
- self.demand_eqtype(span, ty, opaque_ty);
- true
- } else {
- return false;
- }
- }
-
/// The "diverging fallback" system is rather complicated. This is
/// a result of our need to balance 'do the right thing' with
/// backwards compatibility.
(result, spans)
}
- /// Replaces the opaque types from the given value with type variables,
- /// and records the `OpaqueTypeMap` for later use during writeback. See
- /// `InferCtxt::instantiate_opaque_types` for more details.
- #[instrument(skip(self, value_span), level = "debug")]
- pub(in super::super) fn instantiate_opaque_types_from_value<T: TypeFoldable<'tcx>>(
- &self,
- value: T,
- value_span: Span,
- ) -> T {
- self.register_infer_ok_obligations(self.instantiate_opaque_types(
- self.body_id,
- self.param_env,
- value,
- value_span,
- ))
- }
-
/// Convenience method which tracks extra diagnostic information for normalization
/// that occurs as a result of WF checking. The `hir_id` is the `HirId` of the hir item
/// whose type is being wf-checked - this is used to construct a more precise span if
// inference variable.
ty::PredicateKind::ClosureKind(..) => None,
ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
+ ty::PredicateKind::OpaqueType(..) => None,
}
})
.filter(move |(tr, _)| self.self_type_matches_expected_vid(*tr, ty_var_root))
/// any).
pub(super) ret_coercion: Option<RefCell<DynamicCoerceMany<'tcx>>>,
- pub(super) ret_coercion_impl_trait: Option<Ty<'tcx>>,
-
pub(super) ret_type_span: Option<Span>,
/// Used exclusively to reduce cost of advanced evaluation used for
param_env,
err_count_on_creation: inh.tcx.sess.err_count(),
ret_coercion: None,
- ret_coercion_impl_trait: None,
ret_type_span: None,
in_tail_expr: false,
ret_coercion_span: Cell::new(None),
let def_id = self.def_id;
self.infcx.enter(|infcx| f(Inherited::new(infcx, def_id)))
}
+
+ /// WF-checking doesn't need to recompute opaque types and can instead use
+ /// the type_of query to get them from typeck.
+ pub fn reveal_defining_opaque_types(mut self) -> Self {
+ self.infcx = self.infcx.reveal_defining_opaque_types();
+ self
+ }
}
impl<'a, 'tcx> Inherited<'a, 'tcx> {
}
}
+ #[instrument(level = "debug", skip(self))]
pub(super) fn register_predicate(&self, obligation: traits::PredicateObligation<'tcx>) {
- debug!("register_predicate({:?})", obligation);
if obligation.has_escaping_bound_vars() {
span_bug!(obligation.cause.span, "escaping bound vars in predicate {:?}", obligation);
}
| ty::PredicateKind::TypeOutlives(..)
| ty::PredicateKind::ConstEvaluatable(..)
| ty::PredicateKind::ConstEquate(..)
+ | ty::PredicateKind::OpaqueType(..)
| ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
}
});
TraitCandidate(trait_ref) => self.probe(|_| {
let _ = self
.at(&ObligationCause::dummy(), self.param_env)
+ .define_opaque_types(false)
.sup(candidate.xform_self_ty, self_ty);
match self.select_trait_candidate(trait_ref) {
Ok(Some(traits::ImplSource::UserDefined(ref impl_data))) => {
// First check that the self type can be related.
let sub_obligations = match self
.at(&ObligationCause::dummy(), self.param_env)
+ .define_opaque_types(false)
.sup(probe.xform_self_ty, self_ty)
{
Ok(InferOk { obligations, value: () }) => obligations,
);
if self
.at(&ObligationCause::dummy(), self.param_env)
+ .define_opaque_types(false)
.sup(return_ty, xform_ret_ty)
.is_err()
{
typeck_with_fallback(tcx, def_id, fallback)
}
+#[instrument(skip(tcx, fallback))]
fn typeck_with_fallback<'tcx>(
tcx: TyCtxt<'tcx>,
def_id: LocalDefId,
// Returns a list of `Ty`s for each upvar.
fn final_upvar_tys(&self, closure_id: DefId) -> Vec<Ty<'tcx>> {
- // Presently an unboxed closure type cannot "escape" out of a
- // function, so we will only encounter ones that originated in the
- // local crate or were inlined into it along with some function.
- // This may change if abstract return types of some sort are
- // implemented.
self.typeck_results
.borrow()
.closure_min_captures_flattened(closure_id)
fn for_id(tcx: TyCtxt<'_>, def_id: LocalDefId, span: Span) -> CheckWfFcxBuilder<'_> {
CheckWfFcxBuilder {
- inherited: Inherited::build(tcx, def_id),
+ inherited: Inherited::build(tcx, def_id).reveal_defining_opaque_types(),
id: hir::HirId::make_owner(def_id),
span,
param_env: tcx.param_env(def_id),
use rustc_middle::ty::{self, ClosureSizeProfileData, Ty, TyCtxt};
use rustc_span::symbol::sym;
use rustc_span::Span;
-use rustc_trait_selection::opaque_types::InferCtxtExt;
use std::mem;
wbcx.visit_closures();
wbcx.visit_liberated_fn_sigs();
wbcx.visit_fru_field_types();
- wbcx.visit_opaque_types(body.value.span);
+ wbcx.visit_opaque_types();
wbcx.visit_coercion_casts();
wbcx.visit_user_provided_tys();
wbcx.visit_user_provided_sigs();
fcx_typeck_results.generator_interior_types.clone();
}
- #[instrument(skip(self, span), level = "debug")]
- fn visit_opaque_types(&mut self, span: Span) {
- let opaque_types = self.fcx.infcx.inner.borrow().opaque_types.clone();
- for (opaque_type_key, opaque_defn) in opaque_types {
- let hir_id =
- self.tcx().hir().local_def_id_to_hir_id(opaque_type_key.def_id.expect_local());
- let instantiated_ty = self.resolve(opaque_defn.concrete_ty, &hir_id);
-
- debug_assert!(!instantiated_ty.has_escaping_bound_vars());
-
- let opaque_type_key = self.fcx.fully_resolve(opaque_type_key).unwrap();
-
- // Prevent:
- // * `fn foo<T>() -> Foo<T>`
- // * `fn foo<T: Bound + Other>() -> Foo<T>`
- // from being defining.
-
- // Also replace all generic params with the ones from the opaque type
- // definition so that
- // ```rust
- // type Foo<T> = impl Baz + 'static;
- // fn foo<U>() -> Foo<U> { .. }
- // ```
- // figures out the concrete type with `U`, but the stored type is with `T`.
-
- // FIXME: why are we calling this here? This seems too early, and duplicated.
- let definition_ty = self.fcx.infer_opaque_definition_from_instantiation(
- opaque_type_key,
- instantiated_ty,
- span,
- );
-
- let mut skip_add = false;
-
- if let ty::Opaque(definition_ty_def_id, _substs) = *definition_ty.kind() {
- if opaque_defn.origin == hir::OpaqueTyOrigin::TyAlias {
- if opaque_type_key.def_id == definition_ty_def_id {
- debug!(
- "skipping adding concrete definition for opaque type {:?} {:?}",
- opaque_defn, opaque_type_key.def_id
- );
- skip_add = true;
- }
+ #[instrument(skip(self), level = "debug")]
+ fn visit_opaque_types(&mut self) {
+ let opaque_types =
+ self.fcx.infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
+ for (opaque_type_key, decl) in opaque_types {
+ let hidden_type = match decl.origin {
+ hir::OpaqueTyOrigin::FnReturn(_) | hir::OpaqueTyOrigin::AsyncFn(_) => {
+ Some(self.resolve(decl.hidden_type.ty, &decl.hidden_type.span))
}
- }
-
- if opaque_type_key.substs.needs_infer() {
- span_bug!(span, "{:#?} has inference variables", opaque_type_key.substs)
- }
-
- // We only want to add an entry into `concrete_opaque_types`
- // if we actually found a defining usage of this opaque type.
- // Otherwise, we do nothing - we'll either find a defining usage
- // in some other location, or we'll end up emitting an error due
- // to the lack of defining usage
- if !skip_add {
- self.typeck_results.concrete_opaque_types.insert(opaque_type_key.def_id);
- }
+ hir::OpaqueTyOrigin::TyAlias => None,
+ };
+ self.typeck_results.concrete_opaque_types.insert(opaque_type_key.def_id, hidden_type);
}
}
.get_value_matching(|(key, _)| key.def_id == def_id.to_def_id())
.copied()
.unwrap_or_else(|| {
- tcx.sess.delay_span_bug(
- DUMMY_SP,
- &format!(
- "owner {:?} has no opaque type for {:?} in its typeck results",
- owner, def_id,
- ),
- );
- if let Some(ErrorReported) =
- tcx.typeck(owner).tainted_by_errors
- {
+ let table = tcx.typeck(owner);
+ if let Some(ErrorReported) = table.tainted_by_errors {
// Some error in the
// owner fn prevented us from populating
// the `concrete_opaque_types` table.
tcx.ty_error()
} else {
- // We failed to resolve the opaque type or it
- // resolves to itself. Return the non-revealed
- // type, which should result in E0720.
- tcx.mk_opaque(
- def_id.to_def_id(),
- InternalSubsts::identity_for_item(tcx, def_id.to_def_id()),
- )
+ table.concrete_opaque_types.get(&def_id.to_def_id()).copied().unwrap_or_else(|| {
+ // We failed to resolve the opaque type or it
+ // resolves to itself. We interpret this as the
+ // no values of the hidden type ever being constructed,
+ // so we can just make the hidden type be `!`.
+ // For backwards compatibility reasons, we fall back to
+ // `()` until we the diverging default is changed.
+ Some(tcx.mk_diverging_default())
+ }).expect("RPIT always have a hidden type from typeck")
}
});
debug!("concrete_ty = {:?}", concrete_ty);
}
// Calling `mir_borrowck` can lead to cycle errors through
// const-checking, avoid calling it if we don't have to.
- if !self.tcx.typeck(def_id).concrete_opaque_types.contains(&self.def_id) {
+ // ```rust
+ // type Foo = impl Fn() -> usize; // when computing type for this
+ // const fn bar() -> Foo {
+ // || 0usize
+ // }
+ // const BAZR: Foo = bar(); // we would mir-borrowck this, causing cycles
+ // // because we again need to reveal `Foo` so we can check whether the
+ // // constant does not contain interior mutability.
+ // ```
+ let tables = self.tcx.typeck(def_id);
+ if let Some(_) = tables.tainted_by_errors {
+ self.found = Some((DUMMY_SP, self.tcx.ty_error()));
+ return;
+ }
+ if tables.concrete_opaque_types.get(&self.def_id).is_none() {
debug!("no constraints in typeck results");
return;
}
intravisit::walk_expr(self, ex);
}
fn visit_item(&mut self, it: &'tcx Item<'tcx>) {
- debug!("find_existential_constraints: visiting {:?}", it);
+ trace!(?it.def_id);
// The opaque type itself or its children are not within its reveal scope.
if it.def_id.to_def_id() != self.def_id {
self.check(it.def_id);
}
}
fn visit_impl_item(&mut self, it: &'tcx ImplItem<'tcx>) {
- debug!("find_existential_constraints: visiting {:?}", it);
+ trace!(?it.def_id);
// The opaque type itself or its children are not within its reveal scope.
if it.def_id.to_def_id() != self.def_id {
self.check(it.def_id);
}
}
fn visit_trait_item(&mut self, it: &'tcx TraitItem<'tcx>) {
- debug!("find_existential_constraints: visiting {:?}", it);
+ trace!(?it.def_id);
self.check(it.def_id);
intravisit::walk_trait_item(self, it);
}
let scope = tcx.hir().get_defining_scope(hir_id);
let mut locator = ConstraintLocator { def_id: def_id.to_def_id(), tcx, found: None };
- debug!("find_opaque_ty_constraints: scope={:?}", scope);
+ debug!(?scope);
if scope == hir::CRATE_HIR_ID {
tcx.hir().walk_toplevel_module(&mut locator);
} else {
- debug!("find_opaque_ty_constraints: scope={:?}", tcx.hir().get(scope));
+ trace!("scope={:#?}", tcx.hir().get(scope));
match tcx.hir().get(scope) {
// We explicitly call `visit_*` methods, instead of using `intravisit::walk_*` methods
// This allows our visitor to process the defining item itself, causing
Some((_, ty)) => ty,
None => {
let span = tcx.def_span(def_id);
- tcx.sess.span_err(span, "could not find defining uses");
+ let name = tcx.item_name(tcx.parent(def_id.to_def_id()).unwrap());
+ let label = format!(
+ "`{}` must be used in combination with a concrete type within the same module",
+ name
+ );
+ tcx.sess.struct_span_err(span, "unconstrained opaque type").note(&label).emit();
tcx.ty_error()
}
}
| ty::PredicateKind::ClosureKind(..)
| ty::PredicateKind::ConstEvaluatable(..)
| ty::PredicateKind::ConstEquate(..)
+ | ty::PredicateKind::OpaqueType(..)
| ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
}
}
fn require_c_abi_if_c_variadic(tcx: TyCtxt<'_>, decl: &hir::FnDecl<'_>, abi: Abi, span: Span) {
match (decl.c_variadic, abi) {
// The function has the correct calling convention, or isn't a "C-variadic" function.
- (false, _) | (true, Abi::C { .. }) | (true, Abi::Cdecl) => {}
+ (false, _) | (true, Abi::C { .. }) | (true, Abi::Cdecl { .. }) => {}
// The function is a "C-variadic" function with an incorrect calling convention.
(true, _) => {
let mut err = struct_span_err!(
| ty::PredicateKind::Coerce(..)
| ty::PredicateKind::ConstEvaluatable(..)
| ty::PredicateKind::ConstEquate(..)
+ | ty::PredicateKind::OpaqueType(..)
| ty::PredicateKind::TypeWellFormedFromEnv(..) => (),
}
}
#![feature(binary_heap_as_slice)]
#![feature(inplace_iteration)]
#![feature(iter_advance_by)]
+#![feature(round_char_boundary)]
#![feature(slice_group_by)]
#![feature(slice_partition_dedup)]
#![feature(string_remove_matches)]
}
}
}
+
+#[test]
+fn floor_char_boundary() {
+ fn check_many(s: &str, arg: impl IntoIterator<Item = usize>, ret: usize) {
+ for idx in arg {
+ assert_eq!(
+ s.floor_char_boundary(idx),
+ ret,
+ "{:?}.floor_char_boundary({:?}) != {:?}",
+ s,
+ idx,
+ ret
+ );
+ }
+ }
+
+ // edge case
+ check_many("", [0, 1, isize::MAX as usize, usize::MAX], 0);
+
+ // basic check
+ check_many("x", [0], 0);
+ check_many("x", [1, isize::MAX as usize, usize::MAX], 1);
+
+ // 1-byte chars
+ check_many("jp", [0], 0);
+ check_many("jp", [1], 1);
+ check_many("jp", 2..4, 2);
+
+ // 2-byte chars
+ check_many("ĵƥ", 0..2, 0);
+ check_many("ĵƥ", 2..4, 2);
+ check_many("ĵƥ", 4..6, 4);
+
+ // 3-byte chars
+ check_many("日本", 0..3, 0);
+ check_many("日本", 3..6, 3);
+ check_many("日本", 6..8, 6);
+
+ // 4-byte chars
+ check_many("🇯🇵", 0..4, 0);
+ check_many("🇯🇵", 4..8, 4);
+ check_many("🇯🇵", 8..10, 8);
+}
+
+#[test]
+fn ceil_char_boundary() {
+ fn check_many(s: &str, arg: impl IntoIterator<Item = usize>, ret: usize) {
+ for idx in arg {
+ assert_eq!(
+ s.ceil_char_boundary(idx),
+ ret,
+ "{:?}.ceil_char_boundary({:?}) != {:?}",
+ s,
+ idx,
+ ret
+ );
+ }
+ }
+
+ // edge case
+ check_many("", [0], 0);
+
+ // basic check
+ check_many("x", [0], 0);
+ check_many("x", [1], 1);
+
+ // 1-byte chars
+ check_many("jp", [0], 0);
+ check_many("jp", [1], 1);
+ check_many("jp", [2], 2);
+
+ // 2-byte chars
+ check_many("ĵƥ", 0..=0, 0);
+ check_many("ĵƥ", 1..=2, 2);
+ check_many("ĵƥ", 3..=4, 4);
+
+ // 3-byte chars
+ check_many("日本", 0..=0, 0);
+ check_many("日本", 1..=3, 3);
+ check_many("日本", 4..=6, 6);
+
+ // 4-byte chars
+ check_many("🇯🇵", 0..=0, 0);
+ check_many("🇯🇵", 1..=4, 4);
+ check_many("🇯🇵", 5..=8, 8);
+}
+
+#[test]
+#[should_panic]
+fn ceil_char_boundary_above_len_panic() {
+ let _ = "x".ceil_char_boundary(2);
+}
pub fn escape_ascii(&self) -> ascii::EscapeDefault {
ascii::escape_default(*self)
}
+
+ pub(crate) fn is_utf8_char_boundary(self) -> bool {
+ // This is bit magic equivalent to: b < 128 || b >= 192
+ (self as i8) >= -0x40
+ }
}
#[lang = "u16"]
}
forward_ref_op_assign! { impl const AddAssign, add_assign for Wrapping<$t>, Wrapping<$t> }
+ #[stable(feature = "wrapping_int_assign_impl", since = "1.60.0")]
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const AddAssign<$t> for Wrapping<$t> {
+ #[inline]
+ fn add_assign(&mut self, other: $t) {
+ *self = *self + Wrapping(other);
+ }
+ }
+ forward_ref_op_assign! { impl const AddAssign, add_assign for Wrapping<$t>, $t }
+
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_ops", issue = "90080")]
impl const Sub for Wrapping<$t> {
}
forward_ref_op_assign! { impl const SubAssign, sub_assign for Wrapping<$t>, Wrapping<$t> }
+ #[stable(feature = "wrapping_int_assign_impl", since = "1.60.0")]
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const SubAssign<$t> for Wrapping<$t> {
+ #[inline]
+ fn sub_assign(&mut self, other: $t) {
+ *self = *self - Wrapping(other);
+ }
+ }
+ forward_ref_op_assign! { impl const SubAssign, sub_assign for Wrapping<$t>, $t }
+
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_ops", issue = "90080")]
impl const Mul for Wrapping<$t> {
}
forward_ref_op_assign! { impl const MulAssign, mul_assign for Wrapping<$t>, Wrapping<$t> }
+ #[stable(feature = "wrapping_int_assign_impl", since = "1.60.0")]
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const MulAssign<$t> for Wrapping<$t> {
+ #[inline]
+ fn mul_assign(&mut self, other: $t) {
+ *self = *self * Wrapping(other);
+ }
+ }
+ forward_ref_op_assign! { impl const MulAssign, mul_assign for Wrapping<$t>, $t }
+
#[stable(feature = "wrapping_div", since = "1.3.0")]
#[rustc_const_unstable(feature = "const_ops", issue = "90080")]
impl const Div for Wrapping<$t> {
}
forward_ref_op_assign! { impl const DivAssign, div_assign for Wrapping<$t>, Wrapping<$t> }
+ #[stable(feature = "wrapping_int_assign_impl", since = "1.60.0")]
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const DivAssign<$t> for Wrapping<$t> {
+ #[inline]
+ fn div_assign(&mut self, other: $t) {
+ *self = *self / Wrapping(other);
+ }
+ }
+ forward_ref_op_assign! { impl const DivAssign, div_assign for Wrapping<$t>, $t }
+
#[stable(feature = "wrapping_impls", since = "1.7.0")]
#[rustc_const_unstable(feature = "const_ops", issue = "90080")]
impl const Rem for Wrapping<$t> {
}
forward_ref_op_assign! { impl const RemAssign, rem_assign for Wrapping<$t>, Wrapping<$t> }
+ #[stable(feature = "wrapping_int_assign_impl", since = "1.60.0")]
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const RemAssign<$t> for Wrapping<$t> {
+ #[inline]
+ fn rem_assign(&mut self, other: $t) {
+ *self = *self % Wrapping(other);
+ }
+ }
+ forward_ref_op_assign! { impl const RemAssign, rem_assign for Wrapping<$t>, $t }
+
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_ops", issue = "90080")]
impl const Not for Wrapping<$t> {
}
forward_ref_op_assign! { impl const BitXorAssign, bitxor_assign for Wrapping<$t>, Wrapping<$t> }
+ #[stable(feature = "wrapping_int_assign_impl", since = "1.60.0")]
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const BitXorAssign<$t> for Wrapping<$t> {
+ #[inline]
+ fn bitxor_assign(&mut self, other: $t) {
+ *self = *self ^ Wrapping(other);
+ }
+ }
+ forward_ref_op_assign! { impl const BitXorAssign, bitxor_assign for Wrapping<$t>, $t }
+
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_ops", issue = "90080")]
impl const BitOr for Wrapping<$t> {
}
forward_ref_op_assign! { impl const BitOrAssign, bitor_assign for Wrapping<$t>, Wrapping<$t> }
+ #[stable(feature = "wrapping_int_assign_impl", since = "1.60.0")]
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const BitOrAssign<$t> for Wrapping<$t> {
+ #[inline]
+ fn bitor_assign(&mut self, other: $t) {
+ *self = *self | Wrapping(other);
+ }
+ }
+ forward_ref_op_assign! { impl const BitOrAssign, bitor_assign for Wrapping<$t>, $t }
+
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_ops", issue = "90080")]
impl const BitAnd for Wrapping<$t> {
}
forward_ref_op_assign! { impl const BitAndAssign, bitand_assign for Wrapping<$t>, Wrapping<$t> }
+ #[stable(feature = "wrapping_int_assign_impl", since = "1.60.0")]
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const BitAndAssign<$t> for Wrapping<$t> {
+ #[inline]
+ fn bitand_assign(&mut self, other: $t) {
+ *self = *self & Wrapping(other);
+ }
+ }
+ forward_ref_op_assign! { impl const BitAndAssign, bitand_assign for Wrapping<$t>, $t }
+
#[stable(feature = "wrapping_neg", since = "1.10.0")]
#[rustc_const_unstable(feature = "const_ops", issue = "90080")]
impl const Neg for Wrapping<$t> {
use iter::SplitInternal;
use iter::{MatchesInternal, SplitNInternal};
-use validations::truncate_to_char_boundary;
-
#[inline(never)]
#[cold]
#[track_caller]
fn slice_error_fail(s: &str, begin: usize, end: usize) -> ! {
const MAX_DISPLAY_LENGTH: usize = 256;
- let (truncated, s_trunc) = truncate_to_char_boundary(s, MAX_DISPLAY_LENGTH);
- let ellipsis = if truncated { "[...]" } else { "" };
+ let trunc_len = s.floor_char_boundary(MAX_DISPLAY_LENGTH);
+ let s_trunc = &s[..trunc_len];
+ let ellipsis = if trunc_len < s.len() { "[...]" } else { "" };
// 1. out of bounds
if begin > s.len() || end > s.len() {
// 3. character boundary
let index = if !s.is_char_boundary(begin) { begin } else { end };
// find the character
- let mut char_start = index;
- while !s.is_char_boundary(char_start) {
- char_start -= 1;
- }
+ let char_start = s.floor_char_boundary(index);
// `char_start` must be less than len and a char boundary
let ch = s[char_start..].chars().next().unwrap();
let char_range = char_start..char_start + ch.len_utf8();
// code on higher opt-levels. See PR #84751 for more details.
None => index == self.len(),
- // This is bit magic equivalent to: b < 128 || b >= 192
- Some(&b) => (b as i8) >= -0x40,
+ Some(&b) => b.is_utf8_char_boundary(),
+ }
+ }
+
+ /// Finds the closest `x` not exceeding `index` where `is_char_boundary(x)` is `true`.
+ ///
+ /// This method can help you truncate a string so that it's still valid UTF-8, but doesn't
+ /// exceed a given number of bytes. Note that this is done purely at the character level
+ /// and can still visually split graphemes, even though the underlying characters aren't
+ /// split. For example, the emoji 🧑🔬 (scientist) could be split so that the string only
+ /// includes 🧑 (person) instead.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(round_char_boundary)]
+ /// let s = "❤️🧡💛💚💙💜";
+ /// assert_eq!(s.len(), 26);
+ /// assert!(!s.is_char_boundary(13));
+ ///
+ /// let closest = s.floor_char_boundary(13);
+ /// assert_eq!(closest, 10);
+ /// assert_eq!(&s[..closest], "❤️🧡");
+ /// ```
+ #[unstable(feature = "round_char_boundary", issue = "93743")]
+ #[inline]
+ pub fn floor_char_boundary(&self, index: usize) -> usize {
+ if index >= self.len() {
+ self.len()
+ } else {
+ let lower_bound = index.saturating_sub(3);
+ let new_index = self.as_bytes()[lower_bound..=index]
+ .iter()
+ .rposition(|b| b.is_utf8_char_boundary());
+
+ // SAFETY: we know that the character boundary will be within four bytes
+ unsafe { lower_bound + new_index.unwrap_unchecked() }
+ }
+ }
+
+ /// Finds the closest `x` not below `index` where `is_char_boundary(x)` is `true`.
+ ///
+ /// This method is the natural complement to [`floor_char_boundary`]. See that method
+ /// for more details.
+ ///
+ /// [`floor_char_boundary`]: str::floor_char_boundary
+ ///
+ /// # Panics
+ ///
+ /// Panics if `index > self.len()`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(round_char_boundary)]
+ /// let s = "❤️🧡💛💚💙💜";
+ /// assert_eq!(s.len(), 26);
+ /// assert!(!s.is_char_boundary(13));
+ ///
+ /// let closest = s.ceil_char_boundary(13);
+ /// assert_eq!(closest, 14);
+ /// assert_eq!(&s[..closest], "❤️🧡💛");
+ /// ```
+ #[unstable(feature = "round_char_boundary", issue = "93743")]
+ #[inline]
+ pub fn ceil_char_boundary(&self, index: usize) -> usize {
+ if index > self.len() {
+ slice_error_fail(self, index, index)
+ } else {
+ let upper_bound = Ord::min(index + 4, self.len());
+ self.as_bytes()[index..upper_bound]
+ .iter()
+ .position(|b| b.is_utf8_char_boundary())
+ .map_or(upper_bound, |pos| pos + index)
}
}
/// Mask of the value bits of a continuation byte.
const CONT_MASK: u8 = 0b0011_1111;
-
-// truncate `&str` to length at most equal to `max`
-// return `true` if it were truncated, and the new str.
-pub(super) fn truncate_to_char_boundary(s: &str, mut max: usize) -> (bool, &str) {
- if max >= s.len() {
- (false, s)
- } else {
- while !s.is_char_boundary(max) {
- max -= 1;
- }
- (true, &s[..max])
- }
-}
impl From<NulError> for io::Error {
/// Converts a [`NulError`] into a [`io::Error`].
fn from(_: NulError) -> io::Error {
- io::Error::new_const(io::ErrorKind::InvalidInput, &"data provided contains a nul byte")
+ io::const_io_error!(io::ErrorKind::InvalidInput, "data provided contains a nul byte")
}
}
/// assert!(cstr.is_err());
/// ```
#[stable(feature = "cstr_from_bytes", since = "1.10.0")]
- pub fn from_bytes_with_nul(bytes: &[u8]) -> Result<&CStr, FromBytesWithNulError> {
+ pub fn from_bytes_with_nul(bytes: &[u8]) -> Result<&Self, FromBytesWithNulError> {
let nul_pos = memchr::memchr(0, bytes);
- if let Some(nul_pos) = nul_pos {
- if nul_pos + 1 != bytes.len() {
- return Err(FromBytesWithNulError::interior_nul(nul_pos));
+ match nul_pos {
+ Some(nul_pos) if nul_pos + 1 == bytes.len() => {
+ // SAFETY: We know there is only one nul byte, at the end
+ // of the byte slice.
+ Ok(unsafe { Self::from_bytes_with_nul_unchecked(bytes) })
}
- Ok(unsafe { CStr::from_bytes_with_nul_unchecked(bytes) })
- } else {
- Err(FromBytesWithNulError::not_nul_terminated())
+ Some(nul_pos) => Err(FromBytesWithNulError::interior_nul(nul_pos)),
+ None => Err(FromBytesWithNulError::not_nul_terminated()),
}
}
match path.parent() {
Some(p) => self.create_dir_all(p)?,
None => {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
io::ErrorKind::Uncategorized,
- &"failed to create whole tree",
+ "failed to create whole tree",
));
}
}
let mut bytes = Vec::new();
self.read_to_end(&mut bytes)?;
let string = crate::str::from_utf8(&bytes).map_err(|_| {
- io::Error::new_const(
+ io::const_io_error!(
io::ErrorKind::InvalidData,
- &"stream did not contain valid UTF-8",
+ "stream did not contain valid UTF-8",
)
})?;
*buf += string;
use crate::error;
use crate::fmt;
use crate::io::{
- self, Error, ErrorKind, IntoInnerError, IoSlice, Seek, SeekFrom, Write, DEFAULT_BUF_SIZE,
+ self, ErrorKind, IntoInnerError, IoSlice, Seek, SeekFrom, Write, DEFAULT_BUF_SIZE,
};
use crate::mem;
use crate::ptr;
match r {
Ok(0) => {
- return Err(Error::new_const(
+ return Err(io::const_io_error!(
ErrorKind::WriteZero,
- &"failed to write the buffered data",
+ "failed to write the buffered data",
));
}
Ok(n) => guard.consume(n),
use crate::io::prelude::*;
use crate::cmp;
-use crate::io::{self, Error, ErrorKind, IoSlice, IoSliceMut, ReadBuf, SeekFrom};
+use crate::io::{self, ErrorKind, IoSlice, IoSliceMut, ReadBuf, SeekFrom};
use core::convert::TryInto;
self.pos = n;
Ok(self.pos)
}
- None => Err(Error::new_const(
+ None => Err(io::const_io_error!(
ErrorKind::InvalidInput,
- &"invalid seek to a negative or overflowing position",
+ "invalid seek to a negative or overflowing position",
)),
}
}
// Resizing write implementation
fn vec_write(pos_mut: &mut u64, vec: &mut Vec<u8>, buf: &[u8]) -> io::Result<usize> {
let pos: usize = (*pos_mut).try_into().map_err(|_| {
- Error::new_const(
+ io::const_io_error!(
ErrorKind::InvalidInput,
- &"cursor position exceeds maximum possible vector length",
+ "cursor position exceeds maximum possible vector length",
)
})?;
// Make sure the internal buffer is as least as big as where we
#[cfg(test)]
mod tests;
+#[cfg(target_pointer_width = "64")]
+mod repr_bitpacked;
+#[cfg(target_pointer_width = "64")]
+use repr_bitpacked::Repr;
+
+#[cfg(not(target_pointer_width = "64"))]
+mod repr_unpacked;
+#[cfg(not(target_pointer_width = "64"))]
+use repr_unpacked::Repr;
+
use crate::convert::From;
use crate::error;
use crate::fmt;
}
}
-enum Repr {
+// Only derive debug in tests, to make sure it
+// doesn't accidentally get printed.
+#[cfg_attr(test, derive(Debug))]
+enum ErrorData<C> {
Os(i32),
Simple(ErrorKind),
- // &str is a fat pointer, but &&str is a thin pointer.
- SimpleMessage(ErrorKind, &'static &'static str),
- Custom(Box<Custom>),
+ SimpleMessage(&'static SimpleMessage),
+ Custom(C),
}
+// `#[repr(align(4))]` is probably redundant, it should have that value or
+// higher already. We include it just because repr_bitpacked.rs's encoding
+// requires an alignment >= 4 (note that `#[repr(align)]` will not reduce the
+// alignment required by the struct, only increase it).
+//
+// If we add more variants to ErrorData, this can be increased to 8, but it
+// should probably be behind `#[cfg_attr(target_pointer_width = "64", ...)]` or
+// whatever cfg we're using to enable the `repr_bitpacked` code, since only the
+// that version needs the alignment, and 8 is higher than the alignment we'll
+// have on 32 bit platforms.
+//
+// (For the sake of being explicit: the alignment requirement here only matters
+// if `error/repr_bitpacked.rs` is in use — for the unpacked repr it doesn't
+// matter at all)
+#[repr(align(4))]
#[derive(Debug)]
+pub(crate) struct SimpleMessage {
+ kind: ErrorKind,
+ message: &'static str,
+}
+
+impl SimpleMessage {
+ pub(crate) const fn new(kind: ErrorKind, message: &'static str) -> Self {
+ Self { kind, message }
+ }
+}
+
+/// Create and return an `io::Error` for a given `ErrorKind` and constant
+/// message. This doesn't allocate.
+pub(crate) macro const_io_error($kind:expr, $message:expr $(,)?) {
+ $crate::io::error::Error::from_static_message({
+ const MESSAGE_DATA: $crate::io::error::SimpleMessage =
+ $crate::io::error::SimpleMessage::new($kind, $message);
+ &MESSAGE_DATA
+ })
+}
+
+// As with `SimpleMessage`: `#[repr(align(4))]` here is just because
+// repr_bitpacked's encoding requires it. In practice it almost certainly be
+// already be this high or higher.
+#[derive(Debug)]
+#[repr(align(4))]
struct Custom {
kind: ErrorKind,
error: Box<dyn error::Error + Send + Sync>,
/// ```
#[inline]
fn from(kind: ErrorKind) -> Error {
- Error { repr: Repr::Simple(kind) }
+ Error { repr: Repr::new_simple(kind) }
}
}
}
fn _new(kind: ErrorKind, error: Box<dyn error::Error + Send + Sync>) -> Error {
- Error { repr: Repr::Custom(Box::new(Custom { kind, error })) }
+ Error { repr: Repr::new_custom(Box::new(Custom { kind, error })) }
}
- /// Creates a new I/O error from a known kind of error as well as a
- /// constant message.
+ /// Creates a new I/O error from a known kind of error as well as a constant
+ /// message.
///
/// This function does not allocate.
///
- /// This function should maybe change to
- /// `new_const<const MSG: &'static str>(kind: ErrorKind)`
- /// in the future, when const generics allow that.
+ /// You should not use this directly, and instead use the `const_io_error!`
+ /// macro: `io::const_io_error!(ErrorKind::Something, "some_message")`.
+ ///
+ /// This function should maybe change to `from_static_message<const MSG: &'static
+ /// str>(kind: ErrorKind)` in the future, when const generics allow that.
#[inline]
- pub(crate) const fn new_const(kind: ErrorKind, message: &'static &'static str) -> Error {
- Self { repr: Repr::SimpleMessage(kind, message) }
+ pub(crate) const fn from_static_message(msg: &'static SimpleMessage) -> Error {
+ Self { repr: Repr::new_simple_message(msg) }
}
/// Returns an error representing the last OS error which occurred.
#[must_use]
#[inline]
pub fn from_raw_os_error(code: i32) -> Error {
- Error { repr: Repr::Os(code) }
+ Error { repr: Repr::new_os(code) }
}
/// Returns the OS error that this error represents (if any).
#[must_use]
#[inline]
pub fn raw_os_error(&self) -> Option<i32> {
- match self.repr {
- Repr::Os(i) => Some(i),
- Repr::Custom(..) => None,
- Repr::Simple(..) => None,
- Repr::SimpleMessage(..) => None,
+ match self.repr.data() {
+ ErrorData::Os(i) => Some(i),
+ ErrorData::Custom(..) => None,
+ ErrorData::Simple(..) => None,
+ ErrorData::SimpleMessage(..) => None,
}
}
#[must_use]
#[inline]
pub fn get_ref(&self) -> Option<&(dyn error::Error + Send + Sync + 'static)> {
- match self.repr {
- Repr::Os(..) => None,
- Repr::Simple(..) => None,
- Repr::SimpleMessage(..) => None,
- Repr::Custom(ref c) => Some(&*c.error),
+ match self.repr.data() {
+ ErrorData::Os(..) => None,
+ ErrorData::Simple(..) => None,
+ ErrorData::SimpleMessage(..) => None,
+ ErrorData::Custom(c) => Some(&*c.error),
}
}
#[must_use]
#[inline]
pub fn get_mut(&mut self) -> Option<&mut (dyn error::Error + Send + Sync + 'static)> {
- match self.repr {
- Repr::Os(..) => None,
- Repr::Simple(..) => None,
- Repr::SimpleMessage(..) => None,
- Repr::Custom(ref mut c) => Some(&mut *c.error),
+ match self.repr.data_mut() {
+ ErrorData::Os(..) => None,
+ ErrorData::Simple(..) => None,
+ ErrorData::SimpleMessage(..) => None,
+ ErrorData::Custom(c) => Some(&mut *c.error),
}
}
#[must_use = "`self` will be dropped if the result is not used"]
#[inline]
pub fn into_inner(self) -> Option<Box<dyn error::Error + Send + Sync>> {
- match self.repr {
- Repr::Os(..) => None,
- Repr::Simple(..) => None,
- Repr::SimpleMessage(..) => None,
- Repr::Custom(c) => Some(c.error),
+ match self.repr.into_data() {
+ ErrorData::Os(..) => None,
+ ErrorData::Simple(..) => None,
+ ErrorData::SimpleMessage(..) => None,
+ ErrorData::Custom(c) => Some(c.error),
}
}
#[must_use]
#[inline]
pub fn kind(&self) -> ErrorKind {
- match self.repr {
- Repr::Os(code) => sys::decode_error_kind(code),
- Repr::Custom(ref c) => c.kind,
- Repr::Simple(kind) => kind,
- Repr::SimpleMessage(kind, _) => kind,
+ match self.repr.data() {
+ ErrorData::Os(code) => sys::decode_error_kind(code),
+ ErrorData::Custom(c) => c.kind,
+ ErrorData::Simple(kind) => kind,
+ ErrorData::SimpleMessage(m) => m.kind,
}
}
}
impl fmt::Debug for Repr {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
- match *self {
- Repr::Os(code) => fmt
+ match self.data() {
+ ErrorData::Os(code) => fmt
.debug_struct("Os")
.field("code", &code)
.field("kind", &sys::decode_error_kind(code))
.field("message", &sys::os::error_string(code))
.finish(),
- Repr::Custom(ref c) => fmt::Debug::fmt(&c, fmt),
- Repr::Simple(kind) => fmt.debug_tuple("Kind").field(&kind).finish(),
- Repr::SimpleMessage(kind, &message) => {
- fmt.debug_struct("Error").field("kind", &kind).field("message", &message).finish()
- }
+ ErrorData::Custom(c) => fmt::Debug::fmt(&c, fmt),
+ ErrorData::Simple(kind) => fmt.debug_tuple("Kind").field(&kind).finish(),
+ ErrorData::SimpleMessage(msg) => fmt
+ .debug_struct("Error")
+ .field("kind", &msg.kind)
+ .field("message", &msg.message)
+ .finish(),
}
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl fmt::Display for Error {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
- match self.repr {
- Repr::Os(code) => {
+ match self.repr.data() {
+ ErrorData::Os(code) => {
let detail = sys::os::error_string(code);
write!(fmt, "{} (os error {})", detail, code)
}
- Repr::Custom(ref c) => c.error.fmt(fmt),
- Repr::Simple(kind) => write!(fmt, "{}", kind.as_str()),
- Repr::SimpleMessage(_, &msg) => msg.fmt(fmt),
+ ErrorData::Custom(ref c) => c.error.fmt(fmt),
+ ErrorData::Simple(kind) => write!(fmt, "{}", kind.as_str()),
+ ErrorData::SimpleMessage(msg) => msg.message.fmt(fmt),
}
}
}
impl error::Error for Error {
#[allow(deprecated, deprecated_in_future)]
fn description(&self) -> &str {
- match self.repr {
- Repr::Os(..) | Repr::Simple(..) => self.kind().as_str(),
- Repr::SimpleMessage(_, &msg) => msg,
- Repr::Custom(ref c) => c.error.description(),
+ match self.repr.data() {
+ ErrorData::Os(..) | ErrorData::Simple(..) => self.kind().as_str(),
+ ErrorData::SimpleMessage(msg) => msg.message,
+ ErrorData::Custom(c) => c.error.description(),
}
}
#[allow(deprecated)]
fn cause(&self) -> Option<&dyn error::Error> {
- match self.repr {
- Repr::Os(..) => None,
- Repr::Simple(..) => None,
- Repr::SimpleMessage(..) => None,
- Repr::Custom(ref c) => c.error.cause(),
+ match self.repr.data() {
+ ErrorData::Os(..) => None,
+ ErrorData::Simple(..) => None,
+ ErrorData::SimpleMessage(..) => None,
+ ErrorData::Custom(c) => c.error.cause(),
}
}
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
- match self.repr {
- Repr::Os(..) => None,
- Repr::Simple(..) => None,
- Repr::SimpleMessage(..) => None,
- Repr::Custom(ref c) => c.error.source(),
+ match self.repr.data() {
+ ErrorData::Os(..) => None,
+ ErrorData::Simple(..) => None,
+ ErrorData::SimpleMessage(..) => None,
+ ErrorData::Custom(c) => c.error.source(),
}
}
}
--- /dev/null
+//! This is a densely packed error representation which is used on targets with
+//! 64-bit pointers.
+//!
+//! (Note that `bitpacked` vs `unpacked` here has no relationship to
+//! `#[repr(packed)]`, it just refers to attempting to use any available bits in
+//! a more clever manner than `rustc`'s default layout algorithm would).
+//!
+//! Conceptually, it stores the same data as the "unpacked" equivalent we use on
+//! other targets. Specifically, you can imagine it as an optimized version of
+//! the following enum (which is roughly equivalent to what's stored by
+//! `repr_unpacked::Repr`, e.g. `super::ErrorData<Box<Custom>>`):
+//!
+//! ```ignore (exposition-only)
+//! enum ErrorData {
+//! Os(i32),
+//! Simple(ErrorKind),
+//! SimpleMessage(&'static SimpleMessage),
+//! Custom(Box<Custom>),
+//! }
+//! ```
+//!
+//! However, it packs this data into a 64bit non-zero value.
+//!
+//! This optimization not only allows `io::Error` to occupy a single pointer,
+//! but improves `io::Result` as well, especially for situations like
+//! `io::Result<()>` (which is now 64 bits) or `io::Result<u64>` (which is now
+//! 128 bits), which are quite common.
+//!
+//! # Layout
+//! Tagged values are 64 bits, with the 2 least significant bits used for the
+//! tag. This means there are there are 4 "variants":
+//!
+//! - **Tag 0b00**: The first variant is equivalent to
+//! `ErrorData::SimpleMessage`, and holds a `&'static SimpleMessage` directly.
+//!
+//! `SimpleMessage` has an alignment >= 4 (which is requested with
+//! `#[repr(align)]` and checked statically at the bottom of this file), which
+//! means every `&'static SimpleMessage` should have the both tag bits as 0,
+//! meaning its tagged and untagged representation are equivalent.
+//!
+//! This means we can skip tagging it, which is necessary as this variant can
+//! be constructed from a `const fn`, which probably cannot tag pointers (or
+//! at least it would be difficult).
+//!
+//! - **Tag 0b01**: The other pointer variant holds the data for
+//! `ErrorData::Custom` and the remaining 62 bits are used to store a
+//! `Box<Custom>`. `Custom` also has alignment >= 4, so the bottom two bits
+//! are free to use for the tag.
+//!
+//! The only important thing to note is that `ptr::wrapping_add` and
+//! `ptr::wrapping_sub` are used to tag the pointer, rather than bitwise
+//! operations. This should preserve the pointer's provenance, which would
+//! otherwise be lost.
+//!
+//! - **Tag 0b10**: Holds the data for `ErrorData::Os(i32)`. We store the `i32`
+//! in the pointer's most significant 32 bits, and don't use the bits `2..32`
+//! for anything. Using the top 32 bits is just to let us easily recover the
+//! `i32` code with the correct sign.
+//!
+//! - **Tag 0b11**: Holds the data for `ErrorData::Simple(ErrorKind)`. This
+//! stores the `ErrorKind` in the top 32 bits as well, although it doesn't
+//! occupy nearly that many. Most of the bits are unused here, but it's not
+//! like we need them for anything else yet.
+//!
+//! # Use of `NonNull<()>`
+//!
+//! Everything is stored in a `NonNull<()>`, which is odd, but actually serves a
+//! purpose.
+//!
+//! Conceptually you might think of this more like:
+//!
+//! ```ignore (exposition-only)
+//! union Repr {
+//! // holds integer (Simple/Os) variants, and
+//! // provides access to the tag bits.
+//! bits: NonZeroU64,
+//! // Tag is 0, so this is stored untagged.
+//! msg: &'static SimpleMessage,
+//! // Tagged (offset) `Box<Custom>` pointer.
+//! tagged_custom: NonNull<()>,
+//! }
+//! ```
+//!
+//! But there are a few problems with this:
+//!
+//! 1. Union access is equivalent to a transmute, so this representation would
+//! require we transmute between integers and pointers in at least one
+//! direction, which may be UB (and even if not, it is likely harder for a
+//! compiler to reason about than explicit ptr->int operations).
+//!
+//! 2. Even if all fields of a union have a niche, the union itself doesn't,
+//! although this may change in the future. This would make things like
+//! `io::Result<()>` and `io::Result<usize>` larger, which defeats part of
+//! the motivation of this bitpacking.
+//!
+//! Storing everything in a `NonZeroUsize` (or some other integer) would be a
+//! bit more traditional for pointer tagging, but it would lose provenance
+//! information, couldn't be constructed from a `const fn`, and would probably
+//! run into other issues as well.
+//!
+//! The `NonNull<()>` seems like the only alternative, even if it's fairly odd
+//! to use a pointer type to store something that may hold an integer, some of
+//! the time.
+
+use super::{Custom, ErrorData, ErrorKind, SimpleMessage};
+use alloc::boxed::Box;
+use core::mem::{align_of, size_of};
+use core::ptr::NonNull;
+
+// The 2 least-significant bits are used as tag.
+const TAG_MASK: usize = 0b11;
+const TAG_SIMPLE_MESSAGE: usize = 0b00;
+const TAG_CUSTOM: usize = 0b01;
+const TAG_OS: usize = 0b10;
+const TAG_SIMPLE: usize = 0b11;
+
+#[repr(transparent)]
+pub(super) struct Repr(NonNull<()>);
+
+// All the types `Repr` stores internally are Send + Sync, and so is it.
+unsafe impl Send for Repr {}
+unsafe impl Sync for Repr {}
+
+impl Repr {
+ pub(super) fn new_custom(b: Box<Custom>) -> Self {
+ let p = Box::into_raw(b).cast::<u8>();
+ // Should only be possible if an allocator handed out a pointer with
+ // wrong alignment.
+ debug_assert_eq!((p as usize & TAG_MASK), 0);
+ // Note: We know `TAG_CUSTOM <= size_of::<Custom>()` (static_assert at
+ // end of file), and both the start and end of the expression must be
+ // valid without address space wraparound due to `Box`'s semantics.
+ //
+ // This means it would be correct to implement this using `ptr::add`
+ // (rather than `ptr::wrapping_add`), but it's unclear this would give
+ // any benefit, so we just use `wrapping_add` instead.
+ let tagged = p.wrapping_add(TAG_CUSTOM).cast::<()>();
+ // Safety: `TAG_CUSTOM + p` is the same as `TAG_CUSTOM | p`,
+ // because `p`'s alignment means it isn't allowed to have any of the
+ // `TAG_BITS` set (you can verify that addition and bitwise-or are the
+ // same when the operands have no bits in common using a truth table).
+ //
+ // Then, `TAG_CUSTOM | p` is not zero, as that would require
+ // `TAG_CUSTOM` and `p` both be zero, and neither is (as `p` came from a
+ // box, and `TAG_CUSTOM` just... isn't zero -- it's `0b01`). Therefore,
+ // `TAG_CUSTOM + p` isn't zero and so `tagged` can't be, and the
+ // `new_unchecked` is safe.
+ let res = Self(unsafe { NonNull::new_unchecked(tagged) });
+ // quickly smoke-check we encoded the right thing (This generally will
+ // only run in libstd's tests, unless the user uses -Zbuild-std)
+ debug_assert!(matches!(res.data(), ErrorData::Custom(_)), "repr(custom) encoding failed");
+ res
+ }
+
+ #[inline]
+ pub(super) fn new_os(code: i32) -> Self {
+ let utagged = ((code as usize) << 32) | TAG_OS;
+ // Safety: `TAG_OS` is not zero, so the result of the `|` is not 0.
+ let res = Self(unsafe { NonNull::new_unchecked(utagged as *mut ()) });
+ // quickly smoke-check we encoded the right thing (This generally will
+ // only run in libstd's tests, unless the user uses -Zbuild-std)
+ debug_assert!(
+ matches!(res.data(), ErrorData::Os(c) if c == code),
+ "repr(os) encoding failed for {}",
+ code,
+ );
+ res
+ }
+
+ #[inline]
+ pub(super) fn new_simple(kind: ErrorKind) -> Self {
+ let utagged = ((kind as usize) << 32) | TAG_SIMPLE;
+ // Safety: `TAG_SIMPLE` is not zero, so the result of the `|` is not 0.
+ let res = Self(unsafe { NonNull::new_unchecked(utagged as *mut ()) });
+ // quickly smoke-check we encoded the right thing (This generally will
+ // only run in libstd's tests, unless the user uses -Zbuild-std)
+ debug_assert!(
+ matches!(res.data(), ErrorData::Simple(k) if k == kind),
+ "repr(simple) encoding failed {:?}",
+ kind,
+ );
+ res
+ }
+
+ #[inline]
+ pub(super) const fn new_simple_message(m: &'static SimpleMessage) -> Self {
+ // Safety: References are never null.
+ Self(unsafe { NonNull::new_unchecked(m as *const _ as *mut ()) })
+ }
+
+ #[inline]
+ pub(super) fn data(&self) -> ErrorData<&Custom> {
+ // Safety: We're a Repr, decode_repr is fine.
+ unsafe { decode_repr(self.0, |c| &*c) }
+ }
+
+ #[inline]
+ pub(super) fn data_mut(&mut self) -> ErrorData<&mut Custom> {
+ // Safety: We're a Repr, decode_repr is fine.
+ unsafe { decode_repr(self.0, |c| &mut *c) }
+ }
+
+ #[inline]
+ pub(super) fn into_data(self) -> ErrorData<Box<Custom>> {
+ let this = core::mem::ManuallyDrop::new(self);
+ // Safety: We're a Repr, decode_repr is fine. The `Box::from_raw` is
+ // safe because we prevent double-drop using `ManuallyDrop`.
+ unsafe { decode_repr(this.0, |p| Box::from_raw(p)) }
+ }
+}
+
+impl Drop for Repr {
+ #[inline]
+ fn drop(&mut self) {
+ // Safety: We're a Repr, decode_repr is fine. The `Box::from_raw` is
+ // safe because we're being dropped.
+ unsafe {
+ let _ = decode_repr(self.0, |p| Box::<Custom>::from_raw(p));
+ }
+ }
+}
+
+// Shared helper to decode a `Repr`'s internal pointer into an ErrorData.
+//
+// Safety: `ptr`'s bits should be encoded as described in the document at the
+// top (it should `some_repr.0`)
+#[inline]
+unsafe fn decode_repr<C, F>(ptr: NonNull<()>, make_custom: F) -> ErrorData<C>
+where
+ F: FnOnce(*mut Custom) -> C,
+{
+ let bits = ptr.as_ptr() as usize;
+ match bits & TAG_MASK {
+ TAG_OS => {
+ let code = ((bits as i64) >> 32) as i32;
+ ErrorData::Os(code)
+ }
+ TAG_SIMPLE => {
+ let kind_bits = (bits >> 32) as u32;
+ let kind = kind_from_prim(kind_bits).unwrap_or_else(|| {
+ debug_assert!(false, "Invalid io::error::Repr bits: `Repr({:#018x})`", bits);
+ // This means the `ptr` passed in was not valid, which violates
+ // the unsafe contract of `decode_repr`.
+ //
+ // Using this rather than unwrap meaningfully improves the code
+ // for callers which only care about one variant (usually
+ // `Custom`)
+ core::hint::unreachable_unchecked();
+ });
+ ErrorData::Simple(kind)
+ }
+ TAG_SIMPLE_MESSAGE => ErrorData::SimpleMessage(&*ptr.cast::<SimpleMessage>().as_ptr()),
+ TAG_CUSTOM => {
+ // It would be correct for us to use `ptr::sub` here (see the
+ // comment above the `wrapping_add` call in `new_custom` for why),
+ // but it isn't clear that it makes a difference, so we don't.
+ let custom = ptr.as_ptr().cast::<u8>().wrapping_sub(TAG_CUSTOM).cast::<Custom>();
+ ErrorData::Custom(make_custom(custom))
+ }
+ _ => {
+ // Can't happen, and compiler can tell
+ unreachable!();
+ }
+ }
+}
+
+// This compiles to the same code as the check+transmute, but doesn't require
+// unsafe, or to hard-code max ErrorKind or its size in a way the compiler
+// couldn't verify.
+#[inline]
+fn kind_from_prim(ek: u32) -> Option<ErrorKind> {
+ macro_rules! from_prim {
+ ($prim:expr => $Enum:ident { $($Variant:ident),* $(,)? }) => {{
+ // Force a compile error if the list gets out of date.
+ const _: fn(e: $Enum) = |e: $Enum| match e {
+ $($Enum::$Variant => ()),*
+ };
+ match $prim {
+ $(v if v == ($Enum::$Variant as _) => Some($Enum::$Variant),)*
+ _ => None,
+ }
+ }}
+ }
+ from_prim!(ek => ErrorKind {
+ NotFound,
+ PermissionDenied,
+ ConnectionRefused,
+ ConnectionReset,
+ HostUnreachable,
+ NetworkUnreachable,
+ ConnectionAborted,
+ NotConnected,
+ AddrInUse,
+ AddrNotAvailable,
+ NetworkDown,
+ BrokenPipe,
+ AlreadyExists,
+ WouldBlock,
+ NotADirectory,
+ IsADirectory,
+ DirectoryNotEmpty,
+ ReadOnlyFilesystem,
+ FilesystemLoop,
+ StaleNetworkFileHandle,
+ InvalidInput,
+ InvalidData,
+ TimedOut,
+ WriteZero,
+ StorageFull,
+ NotSeekable,
+ FilesystemQuotaExceeded,
+ FileTooLarge,
+ ResourceBusy,
+ ExecutableFileBusy,
+ Deadlock,
+ CrossesDevices,
+ TooManyLinks,
+ FilenameTooLong,
+ ArgumentListTooLong,
+ Interrupted,
+ Other,
+ UnexpectedEof,
+ Unsupported,
+ OutOfMemory,
+ Uncategorized,
+ })
+}
+
+// Some static checking to alert us if a change breaks any of the assumptions
+// that our encoding relies on for correctness and soundness. (Some of these are
+// a bit overly thorough/cautious, admittedly)
+//
+// If any of these are hit on a platform that libstd supports, we should likely
+// just use `repr_unpacked.rs` there instead (unless the fix is easy).
+macro_rules! static_assert {
+ ($condition:expr) => {
+ const _: () = assert!($condition);
+ };
+ (@usize_eq: $lhs:expr, $rhs:expr) => {
+ const _: [(); $lhs] = [(); $rhs];
+ };
+}
+
+// The bitpacking we use requires pointers be exactly 64 bits.
+static_assert!(@usize_eq: size_of::<NonNull<()>>(), 8);
+
+// We also require pointers and usize be the same size.
+static_assert!(@usize_eq: size_of::<NonNull<()>>(), size_of::<usize>());
+
+// `Custom` and `SimpleMessage` need to be thin pointers.
+static_assert!(@usize_eq: size_of::<&'static SimpleMessage>(), 8);
+static_assert!(@usize_eq: size_of::<Box<Custom>>(), 8);
+
+static_assert!((TAG_MASK + 1).is_power_of_two());
+// And they must have sufficient alignment.
+static_assert!(align_of::<SimpleMessage>() >= TAG_MASK + 1);
+static_assert!(align_of::<Custom>() >= TAG_MASK + 1);
+
+static_assert!(@usize_eq: (TAG_MASK & TAG_SIMPLE_MESSAGE), TAG_SIMPLE_MESSAGE);
+static_assert!(@usize_eq: (TAG_MASK & TAG_CUSTOM), TAG_CUSTOM);
+static_assert!(@usize_eq: (TAG_MASK & TAG_OS), TAG_OS);
+static_assert!(@usize_eq: (TAG_MASK & TAG_SIMPLE), TAG_SIMPLE);
+
+// This is obviously true (`TAG_CUSTOM` is `0b01`), but in `Repr::new_custom` we
+// offset a pointer by this value, and expect it to both be within the same
+// object, and to not wrap around the address space. See the comment in that
+// function for further details.
+//
+// Actually, at the moment we use `ptr::wrapping_add`, not `ptr::add`, so this
+// check isn't needed for that one, although the assertion that we don't
+// actually wrap around in that wrapping_add does simplify the safety reasoning
+// elsewhere considerably.
+static_assert!(size_of::<Custom>() >= TAG_CUSTOM);
+
+// These two store a payload which is allowed to be zero, so they must be
+// non-zero to preserve the `NonNull`'s range invariant.
+static_assert!(TAG_OS != 0);
+static_assert!(TAG_SIMPLE != 0);
+// We can't tag `SimpleMessage`s, the tag must be 0.
+static_assert!(@usize_eq: TAG_SIMPLE_MESSAGE, 0);
+
+// Check that the point of all of this still holds.
+//
+// We'd check against `io::Error`, but *technically* it's allowed to vary,
+// as it's not `#[repr(transparent)]`/`#[repr(C)]`. We could add that, but
+// the `#[repr()]` would show up in rustdoc, which might be seen as a stable
+// commitment.
+static_assert!(@usize_eq: size_of::<Repr>(), 8);
+static_assert!(@usize_eq: size_of::<Option<Repr>>(), 8);
+static_assert!(@usize_eq: size_of::<Result<(), Repr>>(), 8);
+static_assert!(@usize_eq: size_of::<Result<usize, Repr>>(), 16);
--- /dev/null
+//! This is a fairly simple unpacked error representation that's used on
+//! non-64bit targets, where the packed 64 bit representation wouldn't work, and
+//! would have no benefit.
+
+use super::{Custom, ErrorData, ErrorKind, SimpleMessage};
+use alloc::boxed::Box;
+
+type Inner = ErrorData<Box<Custom>>;
+
+pub(super) struct Repr(Inner);
+
+impl Repr {
+ pub(super) fn new_custom(b: Box<Custom>) -> Self {
+ Self(Inner::Custom(b))
+ }
+ #[inline]
+ pub(super) fn new_os(code: i32) -> Self {
+ Self(Inner::Os(code))
+ }
+ #[inline]
+ pub(super) fn new_simple(kind: ErrorKind) -> Self {
+ Self(Inner::Simple(kind))
+ }
+ #[inline]
+ pub(super) const fn new_simple_message(m: &'static SimpleMessage) -> Self {
+ Self(Inner::SimpleMessage(m))
+ }
+ #[inline]
+ pub(super) fn into_data(self) -> ErrorData<Box<Custom>> {
+ self.0
+ }
+ #[inline]
+ pub(super) fn data(&self) -> ErrorData<&Custom> {
+ match &self.0 {
+ Inner::Os(c) => ErrorData::Os(*c),
+ Inner::Simple(k) => ErrorData::Simple(*k),
+ Inner::SimpleMessage(m) => ErrorData::SimpleMessage(*m),
+ Inner::Custom(m) => ErrorData::Custom(&*m),
+ }
+ }
+ #[inline]
+ pub(super) fn data_mut(&mut self) -> ErrorData<&mut Custom> {
+ match &mut self.0 {
+ Inner::Os(c) => ErrorData::Os(*c),
+ Inner::Simple(k) => ErrorData::Simple(*k),
+ Inner::SimpleMessage(m) => ErrorData::SimpleMessage(*m),
+ Inner::Custom(m) => ErrorData::Custom(&mut *m),
+ }
+ }
+}
-use super::{Custom, Error, ErrorKind, Repr};
+use super::{const_io_error, Custom, Error, ErrorData, ErrorKind, Repr};
+use crate::assert_matches::assert_matches;
use crate::error;
use crate::fmt;
use crate::mem::size_of;
let msg = error_string(code);
let kind = decode_error_kind(code);
let err = Error {
- repr: Repr::Custom(box Custom {
+ repr: Repr::new_custom(box Custom {
kind: ErrorKind::InvalidInput,
- error: box Error { repr: super::Repr::Os(code) },
+ error: box Error { repr: super::Repr::new_os(code) },
}),
};
let expected = format!(
#[test]
fn test_const() {
- const E: Error = Error::new_const(ErrorKind::NotFound, &"hello");
+ const E: Error = const_io_error!(ErrorKind::NotFound, "hello");
assert_eq!(E.kind(), ErrorKind::NotFound);
assert_eq!(E.to_string(), "hello");
assert!(format!("{:?}", E).contains("\"hello\""));
assert!(format!("{:?}", E).contains("NotFound"));
}
+
+#[test]
+fn test_os_packing() {
+ for code in -20i32..20i32 {
+ let e = Error::from_raw_os_error(code);
+ assert_eq!(e.raw_os_error(), Some(code));
+ assert_matches!(
+ e.repr.data(),
+ ErrorData::Os(c) if c == code,
+ );
+ }
+}
+
+#[test]
+fn test_errorkind_packing() {
+ assert_eq!(Error::from(ErrorKind::NotFound).kind(), ErrorKind::NotFound);
+ assert_eq!(Error::from(ErrorKind::PermissionDenied).kind(), ErrorKind::PermissionDenied);
+ assert_eq!(Error::from(ErrorKind::Uncategorized).kind(), ErrorKind::Uncategorized);
+ // Check that the innards look like like what we want.
+ assert_matches!(
+ Error::from(ErrorKind::OutOfMemory).repr.data(),
+ ErrorData::Simple(ErrorKind::OutOfMemory),
+ );
+}
+
+#[test]
+fn test_simple_message_packing() {
+ use super::{ErrorKind::*, SimpleMessage};
+ macro_rules! check_simple_msg {
+ ($err:expr, $kind:ident, $msg:literal) => {{
+ let e = &$err;
+ // Check that the public api is right.
+ assert_eq!(e.kind(), $kind);
+ assert!(format!("{:?}", e).contains($msg));
+ // and we got what we expected
+ assert_matches!(
+ e.repr.data(),
+ ErrorData::SimpleMessage(SimpleMessage { kind: $kind, message: $msg })
+ );
+ }};
+ }
+
+ let not_static = const_io_error!(Uncategorized, "not a constant!");
+ check_simple_msg!(not_static, Uncategorized, "not a constant!");
+
+ const CONST: Error = const_io_error!(NotFound, "definitely a constant!");
+ check_simple_msg!(CONST, NotFound, "definitely a constant!");
+
+ static STATIC: Error = const_io_error!(BrokenPipe, "a constant, sort of!");
+ check_simple_msg!(STATIC, BrokenPipe, "a constant, sort of!");
+}
+
+#[derive(Debug, PartialEq)]
+struct Bojji(bool);
+impl error::Error for Bojji {}
+impl fmt::Display for Bojji {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "ah! {:?}", self)
+ }
+}
+
+#[test]
+fn test_custom_error_packing() {
+ use super::Custom;
+ let test = Error::new(ErrorKind::Uncategorized, Bojji(true));
+ assert_matches!(
+ test.repr.data(),
+ ErrorData::Custom(Custom {
+ kind: ErrorKind::Uncategorized,
+ error,
+ }) if error.downcast_ref::<Bojji>().as_deref() == Some(&Bojji(true)),
+ );
+}
use crate::cmp;
use crate::fmt;
use crate::io::{
- self, BufRead, Error, ErrorKind, IoSlice, IoSliceMut, Read, ReadBuf, Seek, SeekFrom, Write,
+ self, BufRead, ErrorKind, IoSlice, IoSliceMut, Read, ReadBuf, Seek, SeekFrom, Write,
};
use crate::mem;
#[inline]
fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
if buf.len() > self.len() {
- return Err(Error::new_const(ErrorKind::UnexpectedEof, &"failed to fill whole buffer"));
+ return Err(io::const_io_error!(
+ ErrorKind::UnexpectedEof,
+ "failed to fill whole buffer"
+ ));
}
let (a, b) = self.split_at(buf.len());
if self.write(data)? == data.len() {
Ok(())
} else {
- Err(Error::new_const(ErrorKind::WriteZero, &"failed to write whole buffer"))
+ Err(io::const_io_error!(ErrorKind::WriteZero, "failed to write whole buffer"))
}
}
#[unstable(feature = "read_buf", issue = "78485")]
pub use self::readbuf::ReadBuf;
+pub(crate) use error::const_io_error;
mod buffered;
pub(crate) mod copy;
let ret = f(g.buf);
if str::from_utf8(&g.buf[g.len..]).is_err() {
ret.and_then(|_| {
- Err(Error::new_const(ErrorKind::InvalidData, &"stream did not contain valid UTF-8"))
+ Err(error::const_io_error!(
+ ErrorKind::InvalidData,
+ "stream did not contain valid UTF-8"
+ ))
})
} else {
g.len = g.buf.len();
}
}
if !buf.is_empty() {
- Err(Error::new_const(ErrorKind::UnexpectedEof, &"failed to fill whole buffer"))
+ Err(error::const_io_error!(ErrorKind::UnexpectedEof, "failed to fill whole buffer"))
} else {
Ok(())
}
while !buf.is_empty() {
match self.write(buf) {
Ok(0) => {
- return Err(Error::new_const(
+ return Err(error::const_io_error!(
ErrorKind::WriteZero,
- &"failed to write whole buffer",
+ "failed to write whole buffer",
));
}
Ok(n) => buf = &buf[n..],
while !bufs.is_empty() {
match self.write_vectored(bufs) {
Ok(0) => {
- return Err(Error::new_const(
+ return Err(error::const_io_error!(
ErrorKind::WriteZero,
- &"failed to write whole buffer",
+ "failed to write whole buffer",
));
}
Ok(n) => IoSlice::advance_slices(&mut bufs, n),
if output.error.is_err() {
output.error
} else {
- Err(Error::new_const(ErrorKind::Uncategorized, &"formatter error"))
+ Err(error::const_io_error!(ErrorKind::Uncategorized, "formatter error"))
}
}
}
impl Read for R {
fn read(&mut self, _: &mut [u8]) -> io::Result<usize> {
- Err(io::Error::new_const(io::ErrorKind::Other, &""))
+ Err(io::const_io_error!(io::ErrorKind::Other, ""))
}
}
impl BufRead for R {
fn fill_buf(&mut self) -> io::Result<&[u8]> {
- Err(io::Error::new_const(io::ErrorKind::Other, &""))
+ Err(io::const_io_error!(io::ErrorKind::Other, ""))
}
fn consume(&mut self, _amt: usize) {}
}
#![stable(feature = "rust1", since = "1.0.0")]
-use crate::io::{self, Error, ErrorKind};
+use crate::io::{self, ErrorKind};
#[stable(feature = "rust1", since = "1.0.0")]
pub use self::addr::{SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs};
}
}
Err(last_err.unwrap_or_else(|| {
- Error::new_const(ErrorKind::InvalidInput, &"could not resolve to any addresses")
+ io::const_io_error!(ErrorKind::InvalidInput, "could not resolve to any addresses")
}))
}
mod tests;
use crate::fmt;
-use crate::io::{self, Error, ErrorKind};
+use crate::io::{self, ErrorKind};
use crate::net::{Ipv4Addr, Ipv6Addr, SocketAddr, ToSocketAddrs};
use crate::sys_common::net as net_imp;
use crate::sys_common::{AsInner, FromInner, IntoInner};
pub fn send_to<A: ToSocketAddrs>(&self, buf: &[u8], addr: A) -> io::Result<usize> {
match addr.to_socket_addrs()?.next() {
Some(addr) => self.0.send_to(buf, &addr),
- None => Err(Error::new_const(ErrorKind::InvalidInput, &"no addresses to send data to")),
+ None => {
+ Err(io::const_io_error!(ErrorKind::InvalidInput, "no addresses to send data to"))
+ }
}
}
#[cfg(target_os = "wasi")]
pub fn try_clone(&self) -> crate::io::Result<Self> {
- Err(crate::io::Error::new_const(
+ Err(crate::io::const_io_error!(
crate::io::ErrorKind::Unsupported,
- &"operation not supported on WASI yet",
+ "operation not supported on WASI yet",
))
}
}
}
}
if !buf.is_empty() {
- Err(io::Error::new_const(io::ErrorKind::UnexpectedEof, &"failed to fill whole buffer"))
+ Err(io::const_io_error!(io::ErrorKind::UnexpectedEof, "failed to fill whole buffer",))
} else {
Ok(())
}
while !buf.is_empty() {
match self.write_at(buf, offset) {
Ok(0) => {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
io::ErrorKind::WriteZero,
- &"failed to write whole buffer",
+ "failed to write whole buffer",
));
}
Ok(n) => {
let bytes = path.as_os_str().as_bytes();
if bytes.contains(&0) {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
io::ErrorKind::InvalidInput,
- &"paths must not contain interior null bytes",
+ "paths must not contain interior null bytes",
));
}
if bytes.len() >= addr.sun_path.len() {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
io::ErrorKind::InvalidInput,
- &"path must be shorter than SUN_LEN",
+ "path must be shorter than SUN_LEN",
));
}
// SAFETY: `bytes` and `addr.sun_path` are not overlapping and
// linux returns zero bytes of address
len = sun_path_offset(&addr) as libc::socklen_t; // i.e., zero-length address
} else if addr.sun_family != libc::AF_UNIX as libc::sa_family_t {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
io::ErrorKind::InvalidInput,
- &"file descriptor did not correspond to a Unix socket",
+ "file descriptor did not correspond to a Unix socket",
));
}
addr.sun_family = libc::AF_UNIX as libc::sa_family_t;
if namespace.len() + 1 > addr.sun_path.len() {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
io::ErrorKind::InvalidInput,
- &"namespace must be shorter than SUN_LEN",
+ "namespace must be shorter than SUN_LEN",
));
}
}
}
if !buf.is_empty() {
- Err(io::Error::new_const(io::ErrorKind::UnexpectedEof, &"failed to fill whole buffer"))
+ Err(io::const_io_error!(io::ErrorKind::UnexpectedEof, "failed to fill whole buffer"))
} else {
Ok(())
}
while !buf.is_empty() {
match self.write_at(buf, offset) {
Ok(0) => {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
io::ErrorKind::WriteZero,
- &"failed to write whole buffer",
+ "failed to write whole buffer",
));
}
Ok(n) => {
a if a == wasi::ADVICE_DONTNEED.raw() => wasi::ADVICE_DONTNEED,
a if a == wasi::ADVICE_NOREUSE.raw() => wasi::ADVICE_NOREUSE,
_ => {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
io::ErrorKind::InvalidInput,
- &"invalid parameter 'advice'",
+ "invalid parameter 'advice'",
));
}
};
fn osstr2str(f: &OsStr) -> io::Result<&str> {
f.to_str()
- .ok_or_else(|| io::Error::new_const(io::ErrorKind::Uncategorized, &"input must be utf-8"))
+ .ok_or_else(|| io::const_io_error!(io::ErrorKind::Uncategorized, "input must be utf-8"))
}
#[cfg(target_vendor = "uwp")]
pub(crate) fn set_no_inherit(&self) -> io::Result<()> {
- Err(io::Error::new_const(io::ErrorKind::Unsupported, &"Unavailable on UWP"))
+ Err(io::const_io_error!(io::ErrorKind::Unsupported, "Unavailable on UWP"))
}
}
(false, _, true) => Ok(O_WRONLY | O_APPEND),
(true, _, true) => Ok(O_RDWR | O_APPEND),
(false, false, false) => {
- Err(io::Error::new_const(ErrorKind::InvalidInput, &"invalid access mode"))
+ Err(io::const_io_error!(ErrorKind::InvalidInput, "invalid access mode"))
}
}
}
(true, false) => {}
(false, false) => {
if self.truncate || self.create || self.create_new {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
ErrorKind::InvalidInput,
- &"invalid creation mode",
+ "invalid creation mode",
));
}
}
(_, true) => {
if self.truncate && !self.create_new {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
ErrorKind::InvalidInput,
- &"invalid creation mode",
+ "invalid creation mode",
));
}
}
}
pub fn unsupported_err() -> crate::io::Error {
- crate::io::Error::new_const(
+ crate::io::const_io_error!(
crate::io::ErrorKind::Unsupported,
- &"operation not supported on HermitCore yet",
+ "operation not supported on HermitCore yet",
)
}
/// if not, starts it.
pub fn init() -> io::Result<()> {
if abi::network_init() < 0 {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
ErrorKind::Uncategorized,
- &"Unable to initialize network interface",
+ "Unable to initialize network interface",
));
}
match abi::tcpstream::connect(addr.ip().to_string().as_bytes(), addr.port(), None) {
Ok(handle) => Ok(TcpStream(Arc::new(Socket(handle)))),
- _ => Err(io::Error::new_const(
+ _ => Err(io::const_io_error!(
ErrorKind::Uncategorized,
- &"Unable to initiate a connection on a socket",
+ "Unable to initiate a connection on a socket",
)),
}
}
Some(duration.as_millis() as u64),
) {
Ok(handle) => Ok(TcpStream(Arc::new(Socket(handle)))),
- _ => Err(io::Error::new_const(
+ _ => Err(io::const_io_error!(
ErrorKind::Uncategorized,
- &"Unable to initiate a connection on a socket",
+ "Unable to initiate a connection on a socket",
)),
}
}
pub fn set_read_timeout(&self, duration: Option<Duration>) -> io::Result<()> {
abi::tcpstream::set_read_timeout(*self.0.as_inner(), duration.map(|d| d.as_millis() as u64))
.map_err(|_| {
- io::Error::new_const(ErrorKind::Uncategorized, &"Unable to set timeout value")
+ io::const_io_error!(ErrorKind::Uncategorized, "Unable to set timeout value")
})
}
*self.0.as_inner(),
duration.map(|d| d.as_millis() as u64),
)
- .map_err(|_| io::Error::new_const(ErrorKind::Uncategorized, &"Unable to set timeout value"))
+ .map_err(|_| io::const_io_error!(ErrorKind::Uncategorized, "Unable to set timeout value"))
}
pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
let duration = abi::tcpstream::get_read_timeout(*self.0.as_inner()).map_err(|_| {
- io::Error::new_const(ErrorKind::Uncategorized, &"Unable to determine timeout value")
+ io::const_io_error!(ErrorKind::Uncategorized, "Unable to determine timeout value")
})?;
Ok(duration.map(|d| Duration::from_millis(d)))
pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
let duration = abi::tcpstream::get_write_timeout(*self.0.as_inner()).map_err(|_| {
- io::Error::new_const(ErrorKind::Uncategorized, &"Unable to determine timeout value")
+ io::const_io_error!(ErrorKind::Uncategorized, "Unable to determine timeout value")
})?;
Ok(duration.map(|d| Duration::from_millis(d)))
pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
abi::tcpstream::peek(*self.0.as_inner(), buf)
- .map_err(|_| io::Error::new_const(ErrorKind::Uncategorized, &"peek failed"))
+ .map_err(|_| io::const_io_error!(ErrorKind::Uncategorized, "peek failed"))
}
pub fn read(&self, buffer: &mut [u8]) -> io::Result<usize> {
for i in ioslice.iter_mut() {
let ret = abi::tcpstream::read(*self.0.as_inner(), &mut i[0..]).map_err(|_| {
- io::Error::new_const(ErrorKind::Uncategorized, &"Unable to read on socket")
+ io::const_io_error!(ErrorKind::Uncategorized, "Unable to read on socket")
})?;
if ret != 0 {
for i in ioslice.iter() {
size += abi::tcpstream::write(*self.0.as_inner(), i).map_err(|_| {
- io::Error::new_const(ErrorKind::Uncategorized, &"Unable to write on socket")
+ io::const_io_error!(ErrorKind::Uncategorized, "Unable to write on socket")
})?;
}
pub fn peer_addr(&self) -> io::Result<SocketAddr> {
let (ipaddr, port) = abi::tcpstream::peer_addr(*self.0.as_inner())
- .map_err(|_| io::Error::new_const(ErrorKind::Uncategorized, &"peer_addr failed"))?;
+ .map_err(|_| io::const_io_error!(ErrorKind::Uncategorized, "peer_addr failed"))?;
let saddr = match ipaddr {
Ipv4(ref addr) => SocketAddr::new(IpAddr::V4(Ipv4Addr::from(addr.0)), port),
Ipv6(ref addr) => SocketAddr::new(IpAddr::V6(Ipv6Addr::from(addr.0)), port),
_ => {
- return Err(io::Error::new_const(ErrorKind::Uncategorized, &"peer_addr failed"));
+ return Err(io::const_io_error!(ErrorKind::Uncategorized, "peer_addr failed"));
}
};
}
pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
- abi::tcpstream::shutdown(*self.0.as_inner(), how as i32).map_err(|_| {
- io::Error::new_const(ErrorKind::Uncategorized, &"unable to shutdown socket")
- })
+ abi::tcpstream::shutdown(*self.0.as_inner(), how as i32)
+ .map_err(|_| io::const_io_error!(ErrorKind::Uncategorized, "unable to shutdown socket"))
}
pub fn duplicate(&self) -> io::Result<TcpStream> {
pub fn set_nodelay(&self, mode: bool) -> io::Result<()> {
abi::tcpstream::set_nodelay(*self.0.as_inner(), mode)
- .map_err(|_| io::Error::new_const(ErrorKind::Uncategorized, &"set_nodelay failed"))
+ .map_err(|_| io::const_io_error!(ErrorKind::Uncategorized, "set_nodelay failed"))
}
pub fn nodelay(&self) -> io::Result<bool> {
abi::tcpstream::nodelay(*self.0.as_inner())
- .map_err(|_| io::Error::new_const(ErrorKind::Uncategorized, &"nodelay failed"))
+ .map_err(|_| io::const_io_error!(ErrorKind::Uncategorized, "nodelay failed"))
}
pub fn set_ttl(&self, tll: u32) -> io::Result<()> {
abi::tcpstream::set_tll(*self.0.as_inner(), tll)
- .map_err(|_| io::Error::new_const(ErrorKind::Uncategorized, &"unable to set TTL"))
+ .map_err(|_| io::const_io_error!(ErrorKind::Uncategorized, "unable to set TTL"))
}
pub fn ttl(&self) -> io::Result<u32> {
abi::tcpstream::get_tll(*self.0.as_inner())
- .map_err(|_| io::Error::new_const(ErrorKind::Uncategorized, &"unable to get TTL"))
+ .map_err(|_| io::const_io_error!(ErrorKind::Uncategorized, "unable to get TTL"))
}
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
pub fn set_nonblocking(&self, mode: bool) -> io::Result<()> {
abi::tcpstream::set_nonblocking(*self.0.as_inner(), mode).map_err(|_| {
- io::Error::new_const(ErrorKind::Uncategorized, &"unable to set blocking mode")
+ io::const_io_error!(ErrorKind::Uncategorized, "unable to set blocking mode")
})
}
}
pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
let (handle, ipaddr, port) = abi::tcplistener::accept(self.0.port())
- .map_err(|_| io::Error::new_const(ErrorKind::Uncategorized, &"accept failed"))?;
+ .map_err(|_| io::const_io_error!(ErrorKind::Uncategorized, "accept failed"))?;
let saddr = match ipaddr {
Ipv4(ref addr) => SocketAddr::new(IpAddr::V4(Ipv4Addr::from(addr.0)), port),
Ipv6(ref addr) => SocketAddr::new(IpAddr::V6(Ipv6Addr::from(addr.0)), port),
_ => {
- return Err(io::Error::new_const(ErrorKind::Uncategorized, &"accept failed"));
+ return Err(io::const_io_error!(ErrorKind::Uncategorized, "accept failed"));
}
};
unsafe { len = abi::write(1, data.as_ptr() as *const u8, data.len()) }
if len < 0 {
- Err(io::Error::new_const(io::ErrorKind::Uncategorized, &"Stdout is not able to print"))
+ Err(io::const_io_error!(io::ErrorKind::Uncategorized, "Stdout is not able to print"))
} else {
Ok(len as usize)
}
unsafe { len = abi::write(1, data.as_ptr() as *const u8, data.len()) }
if len < 0 {
- Err(io::Error::new_const(io::ErrorKind::Uncategorized, &"Stdout is not able to print"))
+ Err(io::const_io_error!(io::ErrorKind::Uncategorized, "Stdout is not able to print"))
} else {
Ok(len as usize)
}
unsafe { len = abi::write(2, data.as_ptr() as *const u8, data.len()) }
if len < 0 {
- Err(io::Error::new_const(io::ErrorKind::Uncategorized, &"Stderr is not able to print"))
+ Err(io::const_io_error!(io::ErrorKind::Uncategorized, "Stderr is not able to print"))
} else {
Ok(len as usize)
}
unsafe { len = abi::write(2, data.as_ptr() as *const u8, data.len()) }
if len < 0 {
- Err(io::Error::new_const(io::ErrorKind::Uncategorized, &"Stderr is not able to print"))
+ Err(io::const_io_error!(io::ErrorKind::Uncategorized, "Stderr is not able to print"))
} else {
Ok(len as usize)
}
// The thread failed to start and as a result p was not consumed. Therefore, it is
// safe to reconstruct the box so that it gets deallocated.
drop(Box::from_raw(p));
- Err(io::Error::new_const(io::ErrorKind::Uncategorized, &"Unable to create thread!"))
+ Err(io::const_io_error!(io::ErrorKind::Uncategorized, "Unable to create thread!"))
} else {
Ok(Thread { tid: tid })
};
}
pub fn unsupported_err() -> crate::io::Error {
- crate::io::Error::new_const(ErrorKind::Unsupported, &"operation not supported on SGX yet")
+ crate::io::const_io_error!(ErrorKind::Unsupported, "operation not supported on SGX yet")
}
/// This function is used to implement various functions that doesn't exist,
pub fn sgx_ineffective<T>(v: T) -> crate::io::Result<T> {
static SGX_INEFFECTIVE_ERROR: AtomicBool = AtomicBool::new(false);
if SGX_INEFFECTIVE_ERROR.load(Ordering::Relaxed) {
- Err(crate::io::Error::new_const(
+ Err(crate::io::const_io_error!(
ErrorKind::Uncategorized,
- &"operation can't be trusted to have any effect on SGX",
+ "operation can't be trusted to have any effect on SGX",
))
} else {
Ok(v)
pub fn connect_timeout(addr: &SocketAddr, dur: Duration) -> io::Result<TcpStream> {
if dur == Duration::default() {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
io::ErrorKind::InvalidInput,
- &"cannot set a 0 duration timeout",
+ "cannot set a 0 duration timeout",
));
}
Self::connect(Ok(addr)) // FIXME: ignoring timeout
pub fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
match dur {
Some(dur) if dur == Duration::default() => {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
io::ErrorKind::InvalidInput,
- &"cannot set a 0 duration timeout",
+ "cannot set a 0 duration timeout",
));
}
_ => sgx_ineffective(()),
pub fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
match dur {
Some(dur) if dur == Duration::default() => {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
io::ErrorKind::InvalidInput,
- &"cannot set a 0 duration timeout",
+ "cannot set a 0 duration timeout",
));
}
_ => sgx_ineffective(()),
pub fn unlink(p: &Path) -> io::Result<()> {
if stat(p)?.file_type().is_dir() {
- Err(io::Error::new_const(io::ErrorKind::IsADirectory, &"is a directory"))
+ Err(io::const_io_error!(io::ErrorKind::IsADirectory, "is a directory"))
} else {
error::SolidError::err_if_negative(unsafe { abi::SOLID_FS_Unlink(cstr(p)?.as_ptr()) })
.map_err(|e| e.as_io_error())?;
.map_err(|e| e.as_io_error())?;
Ok(())
} else {
- Err(io::Error::new_const(io::ErrorKind::NotADirectory, &"not a directory"))
+ Err(io::const_io_error!(io::ErrorKind::NotADirectory, "not a directory"))
}
}
pub fn readlink(p: &Path) -> io::Result<PathBuf> {
// This target doesn't support symlinks
stat(p)?;
- Err(io::Error::new_const(io::ErrorKind::InvalidInput, &"not a symbolic link"))
+ Err(io::const_io_error!(io::ErrorKind::InvalidInput, "not a symbolic link"))
}
pub fn symlink(_original: &Path, _link: &Path) -> io::Result<()> {
}
pub fn unsupported_err() -> crate::io::Error {
- crate::io::Error::new_const(
+ crate::io::const_io_error!(
crate::io::ErrorKind::Unsupported,
- &"operation not supported on this platform",
+ "operation not supported on this platform",
)
}
}
if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
io::ErrorKind::InvalidInput,
- &"cannot set a 0 duration timeout",
+ "cannot set a 0 duration timeout",
));
}
};
match n {
- 0 => Err(io::Error::new_const(io::ErrorKind::TimedOut, &"connection timed out")),
+ 0 => Err(io::const_io_error!(io::ErrorKind::TimedOut, "connection timed out")),
_ => {
let can_write = writefds.num_fds != 0;
if !can_write {
let timeout = match dur {
Some(dur) => {
if dur.as_secs() == 0 && dur.subsec_nanos() == 0 {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
io::ErrorKind::InvalidInput,
- &"cannot set a 0 duration timeout",
+ "cannot set a 0 duration timeout",
));
}
/// In kmclib, `setenv` and `unsetenv` don't always set `errno`, so this
/// function just returns a generic error.
fn cvt_env(t: c_int) -> io::Result<c_int> {
- if t == -1 {
- Err(io::Error::new_const(io::ErrorKind::Uncategorized, &"failure"))
- } else {
- Ok(t)
- }
+ if t == -1 { Err(io::const_io_error!(io::ErrorKind::Uncategorized, "failure")) } else { Ok(t) }
}
pub fn temp_dir() -> PathBuf {
tv_nsec: ext.stx_btime.tv_nsec as _,
}))
} else {
- Err(io::Error::new_const(
+ Err(io::const_io_error!(
io::ErrorKind::Uncategorized,
- &"creation time is not available for the filesystem",
+ "creation time is not available for the filesystem",
))
};
}
}
- Err(io::Error::new_const(
+ Err(io::const_io_error!(
io::ErrorKind::Unsupported,
- &"creation time is not available on this platform \
+ "creation time is not available on this platform \
currently",
))
}
macro_rules! unimpl {
() => {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
io::ErrorKind::Unsupported,
- &"No networking available on L4Re.",
+ "No networking available on L4Re.",
));
};
}
}
pub fn unsupported_err() -> io::Error {
- io::Error::new_const(
- io::ErrorKind::Unsupported,
- &"operation not supported on this platform",
- )
+ io::const_io_error!(io::ErrorKind::Unsupported, "operation not supported on this platform",)
}
}
let mut pollfd = libc::pollfd { fd: self.as_raw_fd(), events: libc::POLLOUT, revents: 0 };
if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
io::ErrorKind::InvalidInput,
- &"cannot set a 0 duration timeout",
+ "cannot set a 0 duration timeout",
));
}
loop {
let elapsed = start.elapsed();
if elapsed >= timeout {
- return Err(io::Error::new_const(io::ErrorKind::TimedOut, &"connection timed out"));
+ return Err(io::const_io_error!(io::ErrorKind::TimedOut, "connection timed out"));
}
let timeout = timeout - elapsed;
// for POLLHUP rather than read readiness
if pollfd.revents & libc::POLLHUP != 0 {
let e = self.take_error()?.unwrap_or_else(|| {
- io::Error::new_const(
+ io::const_io_error!(
io::ErrorKind::Uncategorized,
- &"no error set after POLLHUP",
+ "no error set after POLLHUP",
)
});
return Err(e);
let timeout = match dur {
Some(dur) => {
if dur.as_secs() == 0 && dur.subsec_nanos() == 0 {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
io::ErrorKind::InvalidInput,
- &"cannot set a 0 duration timeout",
+ "cannot set a 0 duration timeout",
));
}
0,
))?;
if path_len <= 1 {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
io::ErrorKind::Uncategorized,
- &"KERN_PROC_PATHNAME sysctl returned zero-length string",
+ "KERN_PROC_PATHNAME sysctl returned zero-length string",
));
}
let mut path: Vec<u8> = Vec::with_capacity(path_len);
if curproc_exe.is_file() {
return crate::fs::read_link(curproc_exe);
}
- Err(io::Error::new_const(
+ Err(io::const_io_error!(
io::ErrorKind::Uncategorized,
- &"/proc/curproc/exe doesn't point to regular file.",
+ "/proc/curproc/exe doesn't point to regular file.",
))
}
sysctl().or_else(|_| procfs())
cvt(libc::sysctl(mib, 4, argv.as_mut_ptr() as *mut _, &mut argv_len, ptr::null_mut(), 0))?;
argv.set_len(argv_len as usize);
if argv[0].is_null() {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
io::ErrorKind::Uncategorized,
- &"no current exe available",
+ "no current exe available",
));
}
let argv0 = CStr::from_ptr(argv[0]).to_bytes();
#[cfg(any(target_os = "linux", target_os = "android", target_os = "emscripten"))]
pub fn current_exe() -> io::Result<PathBuf> {
match crate::fs::read_link("/proc/self/exe") {
- Err(ref e) if e.kind() == io::ErrorKind::NotFound => Err(io::Error::new_const(
+ Err(ref e) if e.kind() == io::ErrorKind::NotFound => Err(io::const_io_error!(
io::ErrorKind::Uncategorized,
- &"no /proc/self/exe available. Is /proc mounted?",
+ "no /proc/self/exe available. Is /proc mounted?",
)),
other => other,
}
);
if result != 0 {
use crate::io::ErrorKind;
- Err(io::Error::new_const(ErrorKind::Uncategorized, &"Error getting executable path"))
+ Err(io::const_io_error!(ErrorKind::Uncategorized, "Error getting executable path"))
} else {
let name = CStr::from_ptr((*info.as_ptr()).name.as_ptr()).to_bytes();
Ok(PathBuf::from(OsStr::from_bytes(name)))
#[cfg(any(target_os = "fuchsia", target_os = "l4re"))]
pub fn current_exe() -> io::Result<PathBuf> {
use crate::io::ErrorKind;
- Err(io::Error::new_const(ErrorKind::Unsupported, &"Not yet implemented!"))
+ Err(io::const_io_error!(ErrorKind::Unsupported, "Not yet implemented!"))
}
#[cfg(target_os = "vxworks")]
let envp = self.capture_env();
if self.saw_nul() {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
io::ErrorKind::InvalidInput,
- &"nul byte found in provided data",
+ "nul byte found in provided data",
));
}
pub fn exec(&mut self, default: Stdio) -> io::Error {
if self.saw_nul() {
- return io::Error::new_const(
+ return io::const_io_error!(
io::ErrorKind::InvalidInput,
- &"nul byte found in provided data",
+ "nul byte found in provided data",
);
}
))?;
}
if actual != 1 {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
io::ErrorKind::InvalidData,
- &"Failed to get exit status of process",
+ "Failed to get exit status of process",
));
}
Ok(ExitStatus(proc_info.return_code))
))?;
}
if actual != 1 {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
io::ErrorKind::InvalidData,
- &"Failed to get exit status of process",
+ "Failed to get exit status of process",
));
}
Ok(Some(ExitStatus(proc_info.return_code)))
let envp = self.capture_env();
if self.saw_nul() {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
ErrorKind::InvalidInput,
- &"nul byte found in provided data",
+ "nul byte found in provided data",
));
}
let envp = self.capture_env();
if self.saw_nul() {
- return io::Error::new_const(
- ErrorKind::InvalidInput,
- &"nul byte found in provided data",
- );
+ return io::const_io_error!(ErrorKind::InvalidInput, "nul byte found in provided data",);
}
match self.setup_io(default, true) {
// and used for another process, and we probably shouldn't be killing
// random processes, so just return an error.
if self.status.is_some() {
- Err(Error::new_const(
+ Err(io::const_io_error!(
ErrorKind::InvalidInput,
- &"invalid argument: can't kill an exited process",
+ "invalid argument: can't kill an exited process",
))
} else {
cvt(unsafe { libc::kill(self.pid, libc::SIGKILL) }).map(drop)
let envp = self.capture_env();
if self.saw_nul() {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
ErrorKind::InvalidInput,
- &"nul byte found in provided data",
+ "nul byte found in provided data",
));
}
let (ours, theirs) = self.setup_io(default, needs_stdin)?;
// and used for another process, and we probably shouldn't be killing
// random processes, so just return an error.
if self.status.is_some() {
- Err(Error::new_const(
+ Err(io::const_io_error!(
ErrorKind::InvalidInput,
- &"invalid argument: can't kill an exited process",
+ "invalid argument: can't kill an exited process",
))
} else {
cvt(unsafe { libc::kill(self.pid, libc::SIGKILL) }).map(drop)
}
match unsafe { libc::sysconf(libc::_SC_NPROCESSORS_ONLN) } {
-1 => Err(io::Error::last_os_error()),
- 0 => Err(io::Error::new_const(io::ErrorKind::NotFound, &"The number of hardware threads is not known for the target platform")),
+ 0 => Err(io::const_io_error!(io::ErrorKind::NotFound, "The number of hardware threads is not known for the target platform")),
cpus => Ok(unsafe { NonZeroUsize::new_unchecked(cpus as usize) }),
}
} else if #[cfg(any(target_os = "freebsd", target_os = "dragonfly", target_os = "netbsd"))] {
if res == -1 {
return Err(io::Error::last_os_error());
} else if cpus == 0 {
- return Err(io::Error::new_const(io::ErrorKind::NotFound, &"The number of hardware threads is not known for the target platform"));
+ return Err(io::const_io_error!(io::ErrorKind::NotFound, "The number of hardware threads is not known for the target platform"));
}
}
Ok(unsafe { NonZeroUsize::new_unchecked(cpus as usize) })
if res == -1 {
return Err(io::Error::last_os_error());
} else if cpus == 0 {
- return Err(io::Error::new_const(io::ErrorKind::NotFound, &"The number of hardware threads is not known for the target platform"));
+ return Err(io::const_io_error!(io::ErrorKind::NotFound, "The number of hardware threads is not known for the target platform"));
}
Ok(unsafe { NonZeroUsize::new_unchecked(cpus as usize) })
let res = libc::get_system_info(&mut sinfo);
if res != libc::B_OK {
- return Err(io::Error::new_const(io::ErrorKind::NotFound, &"The number of hardware threads is not known for the target platform"));
+ return Err(io::const_io_error!(io::ErrorKind::NotFound, "The number of hardware threads is not known for the target platform"));
}
Ok(NonZeroUsize::new_unchecked(sinfo.cpu_count as usize))
}
} else {
// FIXME: implement on vxWorks, Redox, l4re
- Err(io::Error::new_const(io::ErrorKind::Unsupported, &"Getting the number of hardware threads is not supported on the target platform"))
+ Err(io::const_io_error!(io::ErrorKind::Unsupported, "Getting the number of hardware threads is not supported on the target platform"))
}
}
}
}
pub fn unsupported_err() -> std_io::Error {
- std_io::Error::new_const(
+ std_io::const_io_error!(
std_io::ErrorKind::Unsupported,
- &"operation not supported on this platform",
+ "operation not supported on this platform",
)
}
}
pub fn setenv(_: &OsStr, _: &OsStr) -> io::Result<()> {
- Err(io::Error::new_const(io::ErrorKind::Unsupported, &"cannot set env vars on this platform"))
+ Err(io::const_io_error!(io::ErrorKind::Unsupported, "cannot set env vars on this platform"))
}
pub fn unsetenv(_: &OsStr) -> io::Result<()> {
- Err(io::Error::new_const(io::ErrorKind::Unsupported, &"cannot unset env vars on this platform"))
+ Err(io::const_io_error!(io::ErrorKind::Unsupported, "cannot unset env vars on this platform"))
}
pub fn temp_dir() -> PathBuf {
pub fn osstr2str(f: &OsStr) -> io::Result<&str> {
f.to_str()
- .ok_or_else(|| io::Error::new_const(io::ErrorKind::Uncategorized, &"input must be utf-8"))
+ .ok_or_else(|| io::const_io_error!(io::ErrorKind::Uncategorized, "input must be utf-8"))
}
pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
for entry in ReadDir::new(fd, dummy_root) {
let entry = entry?;
let path = crate::str::from_utf8(&entry.name).map_err(|_| {
- io::Error::new_const(io::ErrorKind::Uncategorized, &"invalid utf-8 file name found")
+ io::const_io_error!(io::ErrorKind::Uncategorized, "invalid utf-8 file name found")
})?;
if entry.file_type()?.is_dir() {
)
}
_ => {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
io::ErrorKind::Uncategorized,
- &"Unsupported reparse point type",
+ "Unsupported reparse point type",
));
}
};
#[cfg(target_vendor = "uwp")]
pub fn link(_original: &Path, _link: &Path) -> io::Result<()> {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
io::ErrorKind::Unsupported,
- &"hard link are not supported on UWP",
+ "hard link are not supported on UWP",
));
}
fn inner(s: &OsStr) -> crate::io::Result<Vec<u16>> {
let mut maybe_result: Vec<u16> = s.encode_wide().collect();
if unrolled_find_u16s(0, &maybe_result).is_some() {
- return Err(crate::io::Error::new_const(
+ return Err(crate::io::const_io_error!(
ErrorKind::InvalidInput,
- &"strings passed to WinAPI cannot contain NULs",
+ "strings passed to WinAPI cannot contain NULs",
));
}
maybe_result.push(0);
match result {
Err(ref error) if error.kind() == io::ErrorKind::WouldBlock => {
if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
io::ErrorKind::InvalidInput,
- &"cannot set a 0 duration timeout",
+ "cannot set a 0 duration timeout",
));
}
};
match count {
- 0 => {
- Err(io::Error::new_const(io::ErrorKind::TimedOut, &"connection timed out"))
- }
+ 0 => Err(io::const_io_error!(io::ErrorKind::TimedOut, "connection timed out")),
_ => {
if writefds.fd_count != 1 {
if let Some(e) = self.take_error()? {
Some(dur) => {
let timeout = sys::dur2timeout(dur);
if timeout == 0 {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
io::ErrorKind::InvalidInput,
- &"cannot set a 0 duration timeout",
+ "cannot set a 0 duration timeout",
));
}
timeout
fn ensure_no_nuls<T: AsRef<OsStr>>(str: T) -> io::Result<T> {
if str.as_ref().encode_wide().any(|b| b == 0) {
- Err(io::Error::new_const(ErrorKind::InvalidInput, &"nul byte found in provided data"))
+ Err(io::const_io_error!(ErrorKind::InvalidInput, "nul byte found in provided data"))
} else {
Ok(str)
}
) -> io::Result<PathBuf> {
// Early return if there is no filename.
if exe_path.is_empty() || path::has_trailing_slash(exe_path) {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
io::ErrorKind::InvalidInput,
- &"program path has no file name",
+ "program path has no file name",
));
}
// Test if the file name has the `exe` extension.
}
}
// If we get here then the executable cannot be found.
- Err(io::Error::new_const(io::ErrorKind::NotFound, &"program not found"))
+ Err(io::const_io_error!(io::ErrorKind::NotFound, "program not found"))
}
// Calls `f` for every path that should be used to find an executable.
if data[0] >> 6 != 0b10 {
// not a continuation byte - reject
incomplete_utf8.len = 0;
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
io::ErrorKind::InvalidData,
- &"Windows stdio in console mode does not support writing non-UTF-8 byte sequences",
+ "Windows stdio in console mode does not support writing non-UTF-8 byte sequences",
));
}
incomplete_utf8.bytes[incomplete_utf8.len as usize] = data[0];
return Ok(1);
}
Err(_) => {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
io::ErrorKind::InvalidData,
- &"Windows stdio in console mode does not support writing non-UTF-8 byte sequences",
+ "Windows stdio in console mode does not support writing non-UTF-8 byte sequences",
));
}
}
incomplete_utf8.len = 1;
return Ok(1);
} else {
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
io::ErrorKind::InvalidData,
- &"Windows stdio in console mode does not support writing non-UTF-8 byte sequences",
+ "Windows stdio in console mode does not support writing non-UTF-8 byte sequences",
));
}
}
}
Err(_) => {
// We can't really do any better than forget all data and return an error.
- return Err(io::Error::new_const(
+ return Err(io::const_io_error!(
io::ErrorKind::InvalidData,
- &"Windows stdin in console mode does not support non-UTF-16 input; \
+ "Windows stdin in console mode does not support non-UTF-16 input; \
encountered unpaired surrogate",
));
}
sysinfo.dwNumberOfProcessors as usize
};
match res {
- 0 => Err(io::Error::new_const(
+ 0 => Err(io::const_io_error!(
io::ErrorKind::NotFound,
- &"The number of hardware threads is not known for the target platform",
+ "The number of hardware threads is not known for the target platform",
)),
cpus => Ok(unsafe { NonZeroUsize::new_unchecked(cpus) }),
}
use crate::io::{self, Error, ErrorKind};
use crate::path::Path;
-pub(crate) const NOT_FILE_ERROR: Error = Error::new_const(
+pub(crate) const NOT_FILE_ERROR: Error = io::const_io_error!(
ErrorKind::InvalidInput,
- &"the source path is neither a regular file nor a symlink to a regular file",
+ "the source path is neither a regular file nor a symlink to a regular file",
);
pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
use crate::convert::{TryFrom, TryInto};
use crate::ffi::CString;
use crate::fmt;
-use crate::io::{self, Error, ErrorKind, IoSlice, IoSliceMut};
+use crate::io::{self, ErrorKind, IoSlice, IoSliceMut};
use crate::mem;
use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr};
use crate::ptr;
*(storage as *const _ as *const c::sockaddr_in6)
})))
}
- _ => Err(Error::new_const(ErrorKind::InvalidInput, &"invalid argument")),
+ _ => Err(io::const_io_error!(ErrorKind::InvalidInput, "invalid argument")),
}
}
($e:expr, $msg:expr) => {
match $e {
Some(r) => r,
- None => return Err(io::Error::new_const(io::ErrorKind::InvalidInput, &$msg)),
+ None => return Err(io::const_io_error!(io::ErrorKind::InvalidInput, $msg)),
}
};
}
pub passed: usize,
pub failed: usize,
pub ignored: usize,
- pub allowed_fail: usize,
pub filtered_out: usize,
pub measured: usize,
pub exec_time: Option<TestSuiteExecTime>,
passed: 0,
failed: 0,
ignored: 0,
- allowed_fail: 0,
filtered_out: 0,
measured: 0,
exec_time: None,
TestResult::TrFailed => "failed".to_owned(),
TestResult::TrFailedMsg(ref msg) => format!("failed: {}", msg),
TestResult::TrIgnored => "ignored".to_owned(),
- TestResult::TrAllowedFail => "failed (allowed)".to_owned(),
TestResult::TrBench(ref bs) => fmt_bench_samples(bs),
TestResult::TrTimedFail => "failed (time limit exceeded)".to_owned(),
},
}
fn current_test_count(&self) -> usize {
- self.passed + self.failed + self.ignored + self.measured + self.allowed_fail
+ self.passed + self.failed + self.ignored + self.measured
}
}
st.not_failures.push((test, stdout));
}
TestResult::TrIgnored => st.ignored += 1,
- TestResult::TrAllowedFail => st.allowed_fail += 1,
TestResult::TrBench(bs) => {
st.metrics.insert_metric(
test.name.as_slice(),
self.write_event("test", desc.name.as_slice(), "ignored", exec_time, stdout, None)
}
- TestResult::TrAllowedFail => self.write_event(
- "test",
- desc.name.as_slice(),
- "allowed_failure",
- exec_time,
- stdout,
- None,
- ),
-
TestResult::TrBench(ref bs) => {
let median = bs.ns_iter_summ.median as usize;
let deviation = (bs.ns_iter_summ.max - bs.ns_iter_summ.min) as usize;
\"event\": \"{}\", \
\"passed\": {}, \
\"failed\": {}, \
- \"allowed_fail\": {}, \
\"ignored\": {}, \
\"measured\": {}, \
\"filtered_out\": {}",
if state.failed == 0 { "ok" } else { "failed" },
state.passed,
- state.failed + state.allowed_fail,
- state.allowed_fail,
+ state.failed,
state.ignored,
state.measured,
state.filtered_out,
))?;
}
- TestResult::TrOk | TestResult::TrAllowedFail => {
+ TestResult::TrOk => {
self.write_message(&*format!(
"<testcase classname=\"{}\" \
name=\"{}\" time=\"{}\"/>",
self.write_short_result("ignored", term::color::YELLOW)
}
- pub fn write_allowed_fail(&mut self) -> io::Result<()> {
- self.write_short_result("FAILED (allowed)", term::color::YELLOW)
- }
-
pub fn write_time_failed(&mut self) -> io::Result<()> {
self.write_short_result("FAILED (time limit exceeded)", term::color::RED)
}
TestResult::TrOk => self.write_ok()?,
TestResult::TrFailed | TestResult::TrFailedMsg(_) => self.write_failed()?,
TestResult::TrIgnored => self.write_ignored()?,
- TestResult::TrAllowedFail => self.write_allowed_fail()?,
TestResult::TrBench(ref bs) => {
self.write_bench()?;
self.write_plain(&format!(": {}", fmt_bench_samples(bs)))?;
self.write_pretty("FAILED", term::color::RED)?;
}
- let s = if state.allowed_fail > 0 {
- format!(
- ". {} passed; {} failed ({} allowed); {} ignored; {} measured; {} filtered out",
- state.passed,
- state.failed + state.allowed_fail,
- state.allowed_fail,
- state.ignored,
- state.measured,
- state.filtered_out
- )
- } else {
- format!(
- ". {} passed; {} failed; {} ignored; {} measured; {} filtered out",
- state.passed, state.failed, state.ignored, state.measured, state.filtered_out
- )
- };
+ let s = format!(
+ ". {} passed; {} failed; {} ignored; {} measured; {} filtered out",
+ state.passed, state.failed, state.ignored, state.measured, state.filtered_out
+ );
self.write_plain(&s)?;
self.write_short_result("i", term::color::YELLOW)
}
- pub fn write_allowed_fail(&mut self) -> io::Result<()> {
- self.write_short_result("a", term::color::YELLOW)
- }
-
pub fn write_bench(&mut self) -> io::Result<()> {
self.write_pretty("bench", term::color::CYAN)
}
self.write_failed()
}
TestResult::TrIgnored => self.write_ignored(),
- TestResult::TrAllowedFail => self.write_allowed_fail(),
TestResult::TrBench(ref bs) => {
if self.is_multithreaded {
self.write_test_name(desc)?;
self.write_pretty("FAILED", term::color::RED)?;
}
- let s = if state.allowed_fail > 0 {
- format!(
- ". {} passed; {} failed ({} allowed); {} ignored; {} measured; {} filtered out",
- state.passed,
- state.failed + state.allowed_fail,
- state.allowed_fail,
- state.ignored,
- state.measured,
- state.filtered_out
- )
- } else {
- format!(
- ". {} passed; {} failed; {} ignored; {} measured; {} filtered out",
- state.passed, state.failed, state.ignored, state.measured, state.filtered_out
- )
- };
+ let s = format!(
+ ". {} passed; {} failed; {} ignored; {} measured; {} filtered out",
+ state.passed, state.failed, state.ignored, state.measured, state.filtered_out
+ );
self.write_plain(&s)?;
TrFailed,
TrFailedMsg(String),
TrIgnored,
- TrAllowedFail,
TrBench(BenchSamples),
TrTimedFail,
}
if maybe_panic_str.map(|e| e.contains(msg)).unwrap_or(false) {
TestResult::TrOk
- } else if desc.allow_fail {
- TestResult::TrAllowedFail
} else if let Some(panic_str) = maybe_panic_str {
TestResult::TrFailedMsg(format!(
r#"panic did not contain expected string
(&ShouldPanic::Yes, Ok(())) | (&ShouldPanic::YesWithMessage(_), Ok(())) => {
TestResult::TrFailedMsg("test did not panic as expected".to_string())
}
- _ if desc.allow_fail => TestResult::TrAllowedFail,
_ => TestResult::TrFailed,
};
time_opts: &Option<time::TestTimeOptions>,
exec_time: &Option<time::TestExecTime>,
) -> TestResult {
- let result = match (desc.allow_fail, code) {
- (_, TR_OK) => TestResult::TrOk,
- (true, TR_FAILED) => TestResult::TrAllowedFail,
- (false, TR_FAILED) => TestResult::TrFailed,
- (_, _) => TestResult::TrFailedMsg(format!("got unexpected return code {}", code)),
+ let result = match code {
+ TR_OK => TestResult::TrOk,
+ TR_FAILED => TestResult::TrFailed,
+ _ => TestResult::TrFailedMsg(format!("got unexpected return code {}", code)),
};
// If test is already failed (or allowed to fail), do not change the result.
name: StaticTestName("1"),
ignore: true,
should_panic: ShouldPanic::No,
- allow_fail: false,
compile_fail: false,
no_run: false,
test_type: TestType::Unknown,
+ #[cfg(bootstrap)]
+ allow_fail: false,
},
testfn: DynTestFn(Box::new(move || {})),
},
name: StaticTestName("2"),
ignore: false,
should_panic: ShouldPanic::No,
- allow_fail: false,
compile_fail: false,
no_run: false,
test_type: TestType::Unknown,
+ #[cfg(bootstrap)]
+ allow_fail: false,
},
testfn: DynTestFn(Box::new(move || {})),
},
name: StaticTestName("whatever"),
ignore: true,
should_panic: ShouldPanic::No,
- allow_fail: false,
compile_fail: false,
no_run: false,
test_type: TestType::Unknown,
+ #[cfg(bootstrap)]
+ allow_fail: false,
},
testfn: DynTestFn(Box::new(f)),
};
name: StaticTestName("whatever"),
ignore: true,
should_panic: ShouldPanic::No,
- allow_fail: false,
compile_fail: false,
no_run: false,
test_type: TestType::Unknown,
+ #[cfg(bootstrap)]
+ allow_fail: false,
},
testfn: DynTestFn(Box::new(f)),
};
name: StaticTestName("whatever"),
ignore: false,
should_panic: ShouldPanic::Yes,
- allow_fail: false,
compile_fail: false,
no_run: false,
test_type: TestType::Unknown,
+ #[cfg(bootstrap)]
+ allow_fail: false,
},
testfn: DynTestFn(Box::new(f)),
};
name: StaticTestName("whatever"),
ignore: false,
should_panic: ShouldPanic::YesWithMessage("error message"),
- allow_fail: false,
compile_fail: false,
no_run: false,
test_type: TestType::Unknown,
+ #[cfg(bootstrap)]
+ allow_fail: false,
},
testfn: DynTestFn(Box::new(f)),
};
name: StaticTestName("whatever"),
ignore: false,
should_panic: ShouldPanic::YesWithMessage(expected),
- allow_fail: false,
compile_fail: false,
no_run: false,
test_type: TestType::Unknown,
+ #[cfg(bootstrap)]
+ allow_fail: false,
},
testfn: DynTestFn(Box::new(f)),
};
name: StaticTestName("whatever"),
ignore: false,
should_panic: ShouldPanic::YesWithMessage(expected),
- allow_fail: false,
compile_fail: false,
no_run: false,
test_type: TestType::Unknown,
+ #[cfg(bootstrap)]
+ allow_fail: false,
},
testfn: DynTestFn(Box::new(f)),
};
name: StaticTestName("whatever"),
ignore: false,
should_panic,
- allow_fail: false,
compile_fail: false,
no_run: false,
test_type: TestType::Unknown,
+ #[cfg(bootstrap)]
+ allow_fail: false,
},
testfn: DynTestFn(Box::new(f)),
};
name: StaticTestName("whatever"),
ignore: false,
should_panic: ShouldPanic::No,
- allow_fail: false,
compile_fail: false,
no_run: false,
test_type: TestType::Unknown,
+ #[cfg(bootstrap)]
+ allow_fail: false,
},
testfn: DynTestFn(Box::new(f)),
};
name: StaticTestName("whatever"),
ignore: false,
should_panic: ShouldPanic::No,
- allow_fail: false,
compile_fail: false,
no_run: false,
test_type,
+ #[cfg(bootstrap)]
+ allow_fail: false,
},
testfn: DynTestFn(Box::new(f)),
};
name: StaticTestName("whatever"),
ignore: false,
should_panic: ShouldPanic::No,
- allow_fail: false,
compile_fail: false,
no_run: false,
test_type,
+ #[cfg(bootstrap)]
+ allow_fail: false,
}
}
name: StaticTestName("3"),
ignore: false,
should_panic: ShouldPanic::Yes,
- allow_fail: false,
compile_fail: false,
no_run: false,
test_type: TestType::Unknown,
+ #[cfg(bootstrap)]
+ allow_fail: false,
},
testfn: DynTestFn(Box::new(move || {})),
});
name: StaticTestName(name),
ignore: false,
should_panic: ShouldPanic::No,
- allow_fail: false,
compile_fail: false,
no_run: false,
test_type: TestType::Unknown,
+ #[cfg(bootstrap)]
+ allow_fail: false,
},
testfn: DynTestFn(Box::new(move || {})),
})
name: DynTestName((*name).clone()),
ignore: false,
should_panic: ShouldPanic::No,
- allow_fail: false,
compile_fail: false,
no_run: false,
test_type: TestType::Unknown,
+ #[cfg(bootstrap)]
+ allow_fail: false,
},
testfn: DynTestFn(Box::new(testfn)),
};
name: StaticTestName("f"),
ignore: false,
should_panic: ShouldPanic::No,
- allow_fail: false,
compile_fail: false,
no_run: false,
test_type: TestType::Unknown,
+ #[cfg(bootstrap)]
+ allow_fail: false,
};
crate::bench::benchmark(TestId(0), desc, tx, true, f);
name: StaticTestName("f"),
ignore: false,
should_panic: ShouldPanic::No,
- allow_fail: false,
compile_fail: false,
no_run: false,
test_type: TestType::Unknown,
+ #[cfg(bootstrap)]
+ allow_fail: false,
};
crate::bench::benchmark(TestId(0), desc, tx, true, f);
name: StaticTestName("a"),
ignore: false,
should_panic: ShouldPanic::No,
- allow_fail: false,
compile_fail: false,
no_run: false,
test_type: TestType::Unknown,
+ #[cfg(bootstrap)]
+ allow_fail: false,
};
let test_b = TestDesc {
name: StaticTestName("b"),
ignore: false,
should_panic: ShouldPanic::No,
- allow_fail: false,
compile_fail: false,
no_run: false,
test_type: TestType::Unknown,
+ #[cfg(bootstrap)]
+ allow_fail: false,
};
let mut out = PrettyFormatter::new(OutputLocation::Raw(Vec::new()), false, 10, false, None);
passed: 0,
failed: 0,
ignored: 0,
- allowed_fail: 0,
filtered_out: 0,
measured: 0,
exec_time: None,
pub name: TestName,
pub ignore: bool,
pub should_panic: options::ShouldPanic,
- pub allow_fail: bool,
pub compile_fail: bool,
pub no_run: bool,
pub test_type: TestType,
+ #[cfg(bootstrap)]
+ pub allow_fail: bool,
}
impl TestDesc {
}
options::ShouldPanic::No => {}
}
- if self.allow_fail {
- return Some("allow fail");
- }
if self.compile_fail {
return Some("compile fail");
}
println!("{}", suggestion);
}
+ let pre_commit = config.src.join(".git").join("hooks").join("pre-commit");
Build::new(config).build();
if suggest_setup {
println!("{}", suggestion);
}
+ // Give a warning if the pre-commit script is in pre-commit and not pre-push.
+ // HACK: Since the commit script uses hard links, we can't actually tell if it was installed by x.py setup or not.
+ // We could see if it's identical to src/etc/pre-push.sh, but pre-push may have been modified in the meantime.
+ // Instead, look for this comment, which is almost certainly not in any custom hook.
+ if std::fs::read_to_string(pre_commit).map_or(false, |contents| {
+ contents.contains("https://github.com/rust-lang/rust/issues/77620#issuecomment-705144570")
+ }) {
+ println!(
+ "warning: You have the pre-push script installed to .git/hooks/pre-commit. \
+ Consider moving it to .git/hooks/pre-push instead, which runs less often."
+ );
+ }
+
if suggest_setup || changelog_suggestion.is_some() {
println!("note: this message was printed twice to make it more likely to be seen");
}
cmd.arg("-Z").arg("force-unstable-if-unmarked");
}
+ if let Ok(flags) = env::var("MAGIC_EXTRA_RUSTFLAGS") {
+ for flag in flags.split(' ') {
+ cmd.arg(flag);
+ }
+ }
+
let is_test = args.iter().any(|a| a == "--test");
if verbose > 2 {
let rust_env_vars =
build.verbose = args.verbose
build.clean = args.clean
- # Read from `RUST_BOOTSTRAP_CONFIG`, then `--config`, then fallback to `config.toml` (if it
+ # Read from `--config`, then `RUST_BOOTSTRAP_CONFIG`, then fallback to `config.toml` (if it
# exists).
- toml_path = os.getenv('RUST_BOOTSTRAP_CONFIG') or args.config
+ toml_path = args.config or os.getenv('RUST_BOOTSTRAP_CONFIG')
if not toml_path and os.path.exists('config.toml'):
toml_path = 'config.toml'
fn main() {
println!("cargo:rerun-if-changed=build.rs");
+ println!("cargo:rerun-if-env-changed=RUSTC");
+ println!("cargo:rerun-if-env-changed=PATH");
println!("cargo:rustc-env=BUILD_TRIPLE={}", env::var("HOST").unwrap());
// This may not be a canonicalized path.
// Try passing `--progress` to start, then run git again without if that fails.
let update = |progress: bool| {
let mut git = Command::new("git");
- git.args(&["submodule", "update", "--init", "--recursive"]);
+ git.args(&["submodule", "update", "--init", "--recursive", "--depth=1"]);
if progress {
git.arg("--progress");
}
use crate::TargetSelection;
use crate::{t, VERSION};
+use std::env::consts::EXE_SUFFIX;
use std::fmt::Write as _;
-use std::path::{Path, PathBuf};
+use std::fs::File;
+use std::path::{Path, PathBuf, MAIN_SEPARATOR};
use std::process::Command;
use std::str::FromStr;
use std::{
println!("`x.py` will now use the configuration at {}", include_path.display());
let build = TargetSelection::from_user(&env!("BUILD_TRIPLE"));
- let stage_path = ["build", build.rustc_target_arg(), "stage1"].join("/");
+ let stage_path =
+ ["build", build.rustc_target_arg(), "stage1"].join(&MAIN_SEPARATOR.to_string());
println!();
return;
}
+ if !ensure_stage1_toolchain_placeholder_exists(stage_path) {
+ println!(
+ "Failed to create a template for stage 1 toolchain or confirm that it already exists"
+ );
+ return;
+ }
+
if try_link_toolchain(&stage_path[..]) {
println!(
"Added `stage1` rustup toolchain; try `cargo +stage1 build` on a separate rust project to run a newly-built toolchain"
.map_or(false, |output| output.status.success())
}
+fn ensure_stage1_toolchain_placeholder_exists(stage_path: &str) -> bool {
+ let pathbuf = PathBuf::from(stage_path);
+
+ if fs::create_dir_all(pathbuf.join("lib")).is_err() {
+ return false;
+ };
+
+ let pathbuf = pathbuf.join("bin");
+ if fs::create_dir_all(&pathbuf).is_err() {
+ return false;
+ };
+
+ let pathbuf = pathbuf.join(format!("rustc{}", EXE_SUFFIX));
+
+ if pathbuf.exists() {
+ return true;
+ }
+
+ // Take care not to overwrite the file
+ let result = File::options().append(true).create(true).open(&pathbuf);
+ if result.is_err() {
+ return false;
+ }
+
+ return true;
+}
+
// Used to get the path for `Subcommand::Setup`
pub fn interactive_path() -> io::Result<Profile> {
fn abbrev_all() -> impl Iterator<Item = ((String, String), Profile)> {
let mut input = String::new();
println!(
"Rust's CI will automatically fail if it doesn't pass `tidy`, the internal tool for ensuring code quality.
-If you'd like, x.py can install a git hook for you that will automatically run `tidy --bless` on each commit
-to ensure your code is up to par. If you decide later that this behavior is undesirable,
-simply delete the `pre-commit` file from .git/hooks."
+If you'd like, x.py can install a git hook for you that will automatically run `tidy --bless` before
+pushing your code to ensure your code is up to par. If you decide later that this behavior is
+undesirable, simply delete the `pre-push` file from .git/hooks."
);
let should_install = loop {
};
if should_install {
- let src = src_path.join("src").join("etc").join("pre-commit.sh");
+ let src = src_path.join("src").join("etc").join("pre-push.sh");
let git = t!(Command::new("git").args(&["rev-parse", "--git-common-dir"]).output().map(
|output| {
assert!(output.status.success(), "failed to run `git`");
PathBuf::from(t!(String::from_utf8(output.stdout)).trim())
}
));
- let dst = git.join("hooks").join("pre-commit");
+ let dst = git.join("hooks").join("pre-push");
match fs::hard_link(src, &dst) {
Err(e) => println!(
"error: could not create hook {}: do you already have the git hook installed?\n{}",
dst.display(),
e
),
- Ok(_) => println!("Linked `src/etc/pre-commit.sh` to `.git/hooks/pre-commit`"),
+ Ok(_) => println!("Linked `src/etc/pre-commit.sh` to `.git/hooks/pre-push`"),
};
} else {
println!("Ok, skipping installation!");
------------------------
-Introduces four new ABI strings: "C-unwind", "stdcall-unwind",
-"thiscall-unwind", and "system-unwind". These enable unwinding from other
-languages (such as C++) into Rust frames and from Rust into other languages.
+Introduces new ABI strings:
+- "C-unwind"
+- "cdecl-unwind"
+- "stdcall-unwind"
+- "fastcall-unwind"
+- "vectorcall-unwind"
+- "thiscall-unwind"
+- "aapcs-unwind"
+- "win64-unwind"
+- "sysv64-unwind"
+- "system-unwind"
+
+These enable unwinding from other languages (such as C++) into Rust frames and
+from Rust into other languages.
See [RFC 2945] for more information.
<If Condition="(base.table.table.ctrl.pointer[i] & 0x80) == 0">
<!-- Bucket is populated -->
<Exec>n--</Exec>
- <Item Name="{((tuple$<$T1, $T2>*)base.table.table.ctrl.pointer)[-(i + 1)].__0}">((tuple$<$T1, $T2>*)base.table.table.ctrl.pointer)[-(i + 1)].__1</Item>
+ <Item Name="{((tuple$<$T1,$T2>*)base.table.table.ctrl.pointer)[-(i + 1)].__0}">((tuple$<$T1,$T2>*)base.table.table.ctrl.pointer)[-(i + 1)].__1</Item>
</If>
<Exec>i++</Exec>
</Loop>
+++ /dev/null
-#!/usr/bin/env bash
-#
-# Call `tidy --bless` before each commit
-# Copy this script to .git/hooks to activate,
-# and remove it from .git/hooks to deactivate.
-#
-
-set -Eeuo pipefail
-
-# https://github.com/rust-lang/rust/issues/77620#issuecomment-705144570
-unset GIT_DIR
-ROOT_DIR="$(git rev-parse --show-toplevel)"
-COMMAND="$ROOT_DIR/x.py test tidy --bless"
-
-if [[ "$OSTYPE" == "msys" || "$OSTYPE" == "win32" ]]; then
- COMMAND="python $COMMAND"
-fi
-
-echo "Running pre-commit script '$COMMAND'"
-
-cd "$ROOT_DIR"
-
-$COMMAND
--- /dev/null
+#!/usr/bin/env bash
+#
+# Call `tidy --bless` before each commit
+# Copy this script to .git/hooks to activate,
+# and remove it from .git/hooks to deactivate.
+#
+
+set -Eeuo pipefail
+
+# https://github.com/rust-lang/rust/issues/77620#issuecomment-705144570
+unset GIT_DIR
+ROOT_DIR="$(git rev-parse --show-toplevel)"
+COMMAND="$ROOT_DIR/x.py test tidy --bless"
+
+if [[ "$OSTYPE" == "msys" || "$OSTYPE" == "win32" ]]; then
+ COMMAND="python $COMMAND"
+fi
+
+echo "Running pre-push script '$COMMAND'"
+
+cd "$ROOT_DIR"
+
+$COMMAND
| ty::PredicateKind::ObjectSafe(..)
| ty::PredicateKind::ClosureKind(..)
| ty::PredicateKind::ConstEquate(..)
+ | ty::PredicateKind::OpaqueType(..)
| ty::PredicateKind::TypeWellFormedFromEnv(..) => panic!("not user writable"),
}
}
},
// compiler failures are test failures
should_panic: test::ShouldPanic::No,
- allow_fail: config.allow_fail,
compile_fail: config.compile_fail,
no_run,
test_type: test::TestType::DocTest,
+ #[cfg(bootstrap)]
+ allow_fail: false,
},
testfn: test::DynTestFn(box move || {
let report_unused_externs = |uext| {
crate test_harness: bool,
crate compile_fail: bool,
crate error_codes: Vec<String>,
- crate allow_fail: bool,
crate edition: Option<Edition>,
}
test_harness: false,
compile_fail: false,
error_codes: Vec::new(),
- allow_fail: false,
edition: None,
}
}
seen_rust_tags = !seen_other_tags;
}
}
- "allow_fail" => {
- data.allow_fail = true;
- seen_rust_tags = !seen_other_tags;
- }
"rust" => {
data.rust = true;
seen_rust_tags = true;
"the code block will either not be tested if not marked as a rust one \
or will be run (which you might not want)",
))
- } else if s == "allow-fail" || s == "allow_fail" || s == "allowfail" {
- Some((
- "allow_fail",
- "the code block will either not be tested if not marked as a rust one \
- or will be run (which you might not want)",
- ))
} else if s == "test-harness" || s == "test_harness" || s == "testharness" {
Some((
"test_harness",
compile_fail: true,
..Default::default()
});
- t(LangString { original: "allow_fail".into(), allow_fail: true, ..Default::default() });
t(LangString { original: "no_run,example".into(), no_run: true, ..Default::default() });
t(LangString {
original: "sh,should_panic".into(),
.location a:first-of-type {
font-weight: 500;
}
-.location a:hover {
- text-decoration: underline;
-}
.block {
padding: 0;
}
.block ul, .block li {
padding: 0;
+ margin: 0;
list-style: none;
}
-.block a {
+.block a,
+h2.location a {
display: block;
- padding: 0.3em;
- margin-left: -0.3em;
+ padding: 0.3rem;
+ margin-left: -0.3rem;
text-overflow: ellipsis;
overflow: hidden;
font-weight: 500;
padding: 0;
margin: 0;
- margin-top: 1rem;
- margin-bottom: 1rem;
+ margin-top: 0.7rem;
+ margin-bottom: 0.7rem;
}
.sidebar h3 {
font-weight: 500;
padding: 0;
margin: 0;
- margin-top: 0.5rem;
- margin-bottom: 0.25rem;
}
.sidebar-links,
.mobile-topbar .location {
border: none;
- margin: 0;
- margin-left: auto;
- padding: 0.3em;
- padding-right: 0.6em;
+ margin: auto 0.5em auto auto;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
background-color: #5c6773;
}
-.sidebar .current {
+.sidebar .current,
+.sidebar a:hover {
background-color: transparent;
color: #ffb44c;
}
color: #ff7733;
}
-.sidebar-elems .location a {
- color: #fff;
-}
-
-.block a:hover {
- background: transparent;
- color: #ffb44c;
-}
-
.line-numbers span { color: #5c6773; }
.line-numbers .line-highlighted {
color: #708090;
.in-band a {
color: #c5c5c5;
}
+.sidebar h2 a,
+.sidebar h3 a {
+ color: white;
+}
.search-results a {
color: #0096cf;
}
background-color: rgba(32, 34, 37, .6);
}
-.sidebar .current {
- background-color: #333;
+.sidebar .current,
+.sidebar a:hover {
+ background: #444;
}
.source .sidebar {
background-color: #565656;
}
-.block a:hover {
- background: #444;
-}
-
.line-numbers span { color: #3B91E2; }
.line-numbers .line-highlighted {
background-color: #0a042f !important;
background-color: rgba(36, 37, 39, 0.6);
}
-.sidebar .current {
+.sidebar .current,
+.sidebar a:hover {
background-color: #fff;
}
background-color: #f1f1f1;
}
-.block a:hover {
- background: #F5F5F5;
-}
-
.line-numbers span { color: #c67e2d; }
.line-numbers .line-highlighted {
background-color: #FDFFD3 !important;
others.appendChild(div);
}
- function block(shortty, longty) {
+ /**
+ * Append to the sidebar a "block" of links - a heading along with a list (`<ul>`) of items.
+ *
+ * @param {string} shortty - A short type name, like "primitive", "mod", or "macro"
+ * @param {string} id - The HTML id of the corresponding section on the module page.
+ * @param {string} longty - A long, capitalized, plural name, like "Primitive Types",
+ * "Modules", or "Macros".
+ */
+ function block(shortty, id, longty) {
var filtered = items[shortty];
if (!filtered) {
return;
var div = document.createElement("div");
div.className = "block " + shortty;
var h3 = document.createElement("h3");
- h3.textContent = longty;
+ h3.innerHTML = `<a href="index.html#${id}">${longty}</a>`;
div.appendChild(h3);
var ul = document.createElement("ul");
var isModule = hasClass(document.body, "mod");
if (!isModule) {
- block("primitive", "Primitive Types");
- block("mod", "Modules");
- block("macro", "Macros");
- block("struct", "Structs");
- block("enum", "Enums");
- block("union", "Unions");
- block("constant", "Constants");
- block("static", "Statics");
- block("trait", "Traits");
- block("fn", "Functions");
- block("type", "Type Definitions");
- block("foreigntype", "Foreign Types");
- block("keyword", "Keywords");
- block("traitalias", "Trait Aliases");
+ block("primitive", "primitives", "Primitive Types");
+ block("mod", "modules", "Modules");
+ block("macro", "macros", "Macros");
+ block("struct", "structs", "Structs");
+ block("enum", "enums", "Enums");
+ block("union", "unions", "Unions");
+ block("constant", "constants", "Constants");
+ block("static", "static", "Statics");
+ block("trait", "traits", "Traits");
+ block("fn", "functions", "Functions");
+ block("type", "types", "Type Definitions");
+ block("foreigntype", "foreign-types", "Foreign Types");
+ block("keyword", "keywords", "Keywords");
+ block("traitalias", "trait-aliases", "Trait Aliases");
}
// `crates{version}.js` should always be loaded before this script, so we can use
#![feature(rustc_private)]
#![feature(array_methods)]
#![feature(assert_matches)]
+#![feature(bool_to_option)]
#![feature(box_patterns)]
#![feature(control_flow_enum)]
#![feature(box_syntax)]
//!
//! [RFC 1946]: https://github.com/rust-lang/rfcs/blob/master/text/1946-intra-rustdoc-links.md
-use rustc_ast as ast;
use rustc_data_structures::{fx::FxHashMap, stable_set::FxHashSet};
use rustc_errors::{Applicability, DiagnosticBuilder};
-use rustc_expand::base::SyntaxExtensionKind;
use rustc_hir::def::{
DefKind,
Namespace::{self, *},
use rustc_hir::def_id::{CrateNum, DefId, CRATE_DEF_ID};
use rustc_middle::ty::{DefIdTree, Ty, TyCtxt};
use rustc_middle::{bug, span_bug, ty};
-use rustc_resolve::ParentScope;
use rustc_session::lint::Lint;
use rustc_span::hygiene::MacroKind;
use rustc_span::symbol::{sym, Ident, Symbol};
path_str: &'a str,
module_id: DefId,
) -> Result<Res, ResolutionFailure<'a>> {
- let path = ast::Path::from_ident(Ident::from_str(path_str));
self.cx.enter_resolver(|resolver| {
- // FIXME(jynelson): does this really need 3 separate lookups?
- if let Ok((Some(ext), res)) = resolver.resolve_macro_path(
- &path,
- None,
- &ParentScope::module(resolver.graph_root(), resolver),
- false,
- false,
- ) {
- if let SyntaxExtensionKind::LegacyBang { .. } = ext.kind {
- return Ok(res.try_into().unwrap());
- }
- }
- if let Some(&res) = resolver.all_macros().get(&Symbol::intern(path_str)) {
- return Ok(res.try_into().unwrap());
- }
+ // NOTE: this needs 2 separate lookups because `resolve_str_path_error` doesn't take
+ // lexical scope into account (it ignores all macros not defined at the mod-level)
debug!("resolving {} as a macro in the module {:?}", path_str, module_id);
if let Ok((_, res)) =
resolver.resolve_str_path_error(DUMMY_SP, path_str, MacroNS, module_id)
return Ok(res);
}
}
+ if let Some(&res) = resolver.all_macros().get(&Symbol::intern(path_str)) {
+ return Ok(res.try_into().unwrap());
+ }
Err(ResolutionFailure::NotResolved {
module_id,
partial_res: None,
tags: &mut Vec<(String, Range<usize>)>,
tag_name: String,
range: Range<usize>,
- f: &impl Fn(&str, &Range<usize>),
+ f: &impl Fn(&str, &Range<usize>, bool),
) {
let tag_name_low = tag_name.to_lowercase();
if let Some(pos) = tags.iter().rposition(|(t, _)| t.to_lowercase() == tag_name_low) {
// `tags` is used as a queue, meaning that everything after `pos` is included inside it.
// So `<h2><h3></h2>` will look like `["h2", "h3"]`. So when closing `h2`, we will still
// have `h3`, meaning the tag wasn't closed as it should have.
- f(&format!("unclosed HTML tag `{}`", last_tag_name), &last_tag_span);
+ f(&format!("unclosed HTML tag `{}`", last_tag_name), &last_tag_span, true);
}
// Remove the `tag_name` that was originally closed
tags.pop();
} else {
// It can happen for example in this case: `<h2></script></h2>` (the `h2` tag isn't required
// but it helps for the visualization).
- f(&format!("unopened HTML tag `{}`", tag_name), &range);
+ f(&format!("unopened HTML tag `{}`", tag_name), &range, false);
+ }
+}
+
+fn extract_path_backwards(text: &str, end_pos: usize) -> Option<usize> {
+ use rustc_lexer::{is_id_continue, is_id_start};
+ let mut current_pos = end_pos;
+ loop {
+ if current_pos >= 2 && text[..current_pos].ends_with("::") {
+ current_pos -= 2;
+ }
+ let new_pos = text[..current_pos]
+ .char_indices()
+ .rev()
+ .take_while(|(_, c)| is_id_start(*c) || is_id_continue(*c))
+ .reduce(|_accum, item| item)
+ .and_then(|(new_pos, c)| is_id_start(c).then_some(new_pos));
+ if let Some(new_pos) = new_pos {
+ if current_pos != new_pos {
+ current_pos = new_pos;
+ continue;
+ }
+ }
+ break;
+ }
+ if current_pos == end_pos {
+ return None;
+ } else {
+ return Some(current_pos);
}
}
range: &Range<usize>,
start_pos: usize,
iter: &mut Peekable<CharIndices<'_>>,
- f: &impl Fn(&str, &Range<usize>),
+ f: &impl Fn(&str, &Range<usize>, bool),
) {
let mut tag_name = String::new();
let mut is_closing = false;
text: &str,
range: Range<usize>,
is_in_comment: &mut Option<Range<usize>>,
- f: &impl Fn(&str, &Range<usize>),
+ f: &impl Fn(&str, &Range<usize>, bool),
) {
let mut iter = text.char_indices().peekable();
};
let dox = item.attrs.collapsed_doc_value().unwrap_or_default();
if !dox.is_empty() {
- let report_diag = |msg: &str, range: &Range<usize>| {
+ let report_diag = |msg: &str, range: &Range<usize>, is_open_tag: bool| {
let sp = match super::source_span_for_markdown_range(tcx, &dox, range, &item.attrs)
{
Some(sp) => sp,
None => item.attr_span(tcx),
};
tcx.struct_span_lint_hir(crate::lint::INVALID_HTML_TAGS, hir_id, sp, |lint| {
- lint.build(msg).emit()
+ use rustc_lint_defs::Applicability;
+ let mut diag = lint.build(msg);
+ // If a tag looks like `<this>`, it might actually be a generic.
+ // We don't try to detect stuff `<like, this>` because that's not valid HTML,
+ // and we don't try to detect stuff `<like this>` because that's not valid Rust.
+ if let Some(Some(generics_start)) = (is_open_tag
+ && dox[..range.end].ends_with(">"))
+ .then(|| extract_path_backwards(&dox, range.start))
+ {
+ let generics_sp = match super::source_span_for_markdown_range(
+ tcx,
+ &dox,
+ &(generics_start..range.end),
+ &item.attrs,
+ ) {
+ Some(sp) => sp,
+ None => item.attr_span(tcx),
+ };
+ // multipart form is chosen here because ``Vec<i32>`` would be confusing.
+ diag.multipart_suggestion(
+ "try marking as source code",
+ vec![
+ (generics_sp.shrink_to_lo(), String::from("`")),
+ (generics_sp.shrink_to_hi(), String::from("`")),
+ ],
+ Applicability::MaybeIncorrect,
+ );
+ }
+ diag.emit()
});
};
let t = t.to_lowercase();
!ALLOWED_UNCLOSED.contains(&t.as_str())
}) {
- report_diag(&format!("unclosed HTML tag `{}`", tag), range);
+ report_diag(&format!("unclosed HTML tag `{}`", tag), range, true);
}
if let Some(range) = is_in_comment {
- report_diag("Unclosed HTML comment", &range);
+ report_diag("Unclosed HTML comment", &range, false);
}
}
return;
}
- let file = tcx.sess.source_map().lookup_char_pos(span.lo()).file;
+ let source_map = tcx.sess.source_map();
+ let file = source_map.lookup_char_pos(span.lo()).file;
let file_path = match file.name.clone() {
FileName::Real(real_filename) => real_filename.into_local_path(),
_ => None,
let fn_entries = self.calls.entry(fn_key).or_default();
trace!("Including expr: {:?}", span);
+ let enclosing_item_span =
+ source_map.span_extend_to_prev_char(enclosing_item_span, '\n', false);
let location = CallLocation::new(span, enclosing_item_span, &file);
fn_entries.entry(abs_path).or_insert_with(mk_call_data).locations.push(location);
}
--- /dev/null
+// needs-llvm-components: arm
+// compile-flags: --target=armv7-unknown-linux-gnueabihf --crate-type=rlib -Cno-prepopulate-passes
+#![no_core]
+#![feature(no_core, lang_items, c_unwind)]
+#[lang="sized"]
+trait Sized { }
+
+// Test that `nounwind` atributes are correctly applied to exported `aapcs` and
+// `aapcs-unwind` extern functions. `aapcs-unwind` functions MUST NOT have this attribute. We
+// disable optimizations above to prevent LLVM from inferring the attribute.
+
+// CHECK: @rust_item_that_cannot_unwind() unnamed_addr #0 {
+#[no_mangle]
+pub extern "aapcs" fn rust_item_that_cannot_unwind() {
+}
+
+// CHECK: @rust_item_that_can_unwind() unnamed_addr #1 {
+#[no_mangle]
+pub extern "aapcs-unwind" fn rust_item_that_can_unwind() {
+}
+
+// Now, make some assertions that the LLVM attributes for these functions are correct. First, make
+// sure that the first item is correctly marked with the `nounwind` attribute:
+//
+// CHECK: attributes #0 = { {{.*}}nounwind{{.*}} }
+//
+// Next, let's assert that the second item, which CAN unwind, does not have this attribute.
+//
+// CHECK: attributes #1 = {
+// CHECK-NOT: nounwind
+// CHECK: }
--- /dev/null
+// compile-flags: -C opt-level=0
+
+// Test that `nounwind` atributes are correctly applied to exported `cdecl` and
+// `cdecl-unwind` extern functions. `cdecl-unwind` functions MUST NOT have this attribute. We
+// disable optimizations above to prevent LLVM from inferring the attribute.
+
+#![crate_type = "lib"]
+#![feature(c_unwind)]
+
+// CHECK: @rust_item_that_cannot_unwind() unnamed_addr #0 {
+#[no_mangle]
+pub extern "cdecl" fn rust_item_that_cannot_unwind() {
+}
+
+// CHECK: @rust_item_that_can_unwind() unnamed_addr #1 {
+#[no_mangle]
+pub extern "cdecl-unwind" fn rust_item_that_can_unwind() {
+}
+
+// Now, make some assertions that the LLVM attributes for these functions are correct. First, make
+// sure that the first item is correctly marked with the `nounwind` attribute:
+//
+// CHECK: attributes #0 = { {{.*}}nounwind{{.*}} }
+//
+// Next, let's assert that the second item, which CAN unwind, does not have this attribute.
+//
+// CHECK: attributes #1 = {
+// CHECK-NOT: nounwind
+// CHECK: }
--- /dev/null
+// needs-llvm-components: x86
+// compile-flags: --target=i686-pc-windows-msvc --crate-type=rlib -Cno-prepopulate-passes
+#![no_core]
+#![feature(no_core, lang_items, c_unwind)]
+#[lang="sized"]
+trait Sized { }
+
+// Test that `nounwind` atributes are correctly applied to exported `fastcall` and
+// `fastcall-unwind` extern functions. `fastcall-unwind` functions MUST NOT have this attribute. We
+// disable optimizations above to prevent LLVM from inferring the attribute.
+
+// CHECK: @rust_item_that_cannot_unwind() unnamed_addr #0 {
+#[no_mangle]
+pub extern "fastcall" fn rust_item_that_cannot_unwind() {
+}
+
+// CHECK: @rust_item_that_can_unwind() unnamed_addr #1 {
+#[no_mangle]
+pub extern "fastcall-unwind" fn rust_item_that_can_unwind() {
+}
+
+// Now, make some assertions that the LLVM attributes for these functions are correct. First, make
+// sure that the first item is correctly marked with the `nounwind` attribute:
+//
+// CHECK: attributes #0 = { {{.*}}nounwind{{.*}} }
+//
+// Next, let's assert that the second item, which CAN unwind, does not have this attribute.
+//
+// CHECK: attributes #1 = {
+// CHECK-NOT: nounwind
+// CHECK: }
--- /dev/null
+// needs-llvm-components: x86
+// compile-flags: --target=x86_64-unknown-linux-gnu --crate-type=rlib -Cno-prepopulate-passes
+#![no_core]
+#![feature(no_core, lang_items, c_unwind)]
+#[lang="sized"]
+trait Sized { }
+
+// Test that `nounwind` atributes are correctly applied to exported `sysv64` and
+// `sysv64-unwind` extern functions. `sysv64-unwind` functions MUST NOT have this attribute. We
+// disable optimizations above to prevent LLVM from inferring the attribute.
+
+// CHECK: @rust_item_that_cannot_unwind() unnamed_addr #0 {
+#[no_mangle]
+pub extern "sysv64" fn rust_item_that_cannot_unwind() {
+}
+
+// CHECK: @rust_item_that_can_unwind() unnamed_addr #1 {
+#[no_mangle]
+pub extern "sysv64-unwind" fn rust_item_that_can_unwind() {
+}
+
+// Now, make some assertions that the LLVM attributes for these functions are correct. First, make
+// sure that the first item is correctly marked with the `nounwind` attribute:
+//
+// CHECK: attributes #0 = { {{.*}}nounwind{{.*}} }
+//
+// Next, let's assert that the second item, which CAN unwind, does not have this attribute.
+//
+// CHECK: attributes #1 = {
+// CHECK-NOT: nounwind
+// CHECK: }
--- /dev/null
+// needs-llvm-components: x86
+// compile-flags: --target=i686-pc-windows-msvc --crate-type=rlib -Cno-prepopulate-passes
+#![no_core]
+#![feature(no_core, lang_items, c_unwind, abi_vectorcall)]
+#[lang="sized"]
+trait Sized { }
+
+// Test that `nounwind` atributes are correctly applied to exported `vectorcall` and
+// `vectorcall-unwind` extern functions. `vectorcall-unwind` functions MUST NOT have this attribute.
+// We disable optimizations above to prevent LLVM from inferring the attribute.
+
+// CHECK: @rust_item_that_cannot_unwind() unnamed_addr #0 {
+#[no_mangle]
+pub extern "vectorcall" fn rust_item_that_cannot_unwind() {
+}
+
+// CHECK: @rust_item_that_can_unwind() unnamed_addr #1 {
+#[no_mangle]
+pub extern "vectorcall-unwind" fn rust_item_that_can_unwind() {
+}
+
+// Now, make some assertions that the LLVM attributes for these functions are correct. First, make
+// sure that the first item is correctly marked with the `nounwind` attribute:
+//
+// CHECK: attributes #0 = { {{.*}}nounwind{{.*}} }
+//
+// Next, let's assert that the second item, which CAN unwind, does not have this attribute.
+//
+// CHECK: attributes #1 = {
+// CHECK-NOT: nounwind
+// CHECK: }
--- /dev/null
+// needs-llvm-components: x86
+// compile-flags: --target=x86_64-unknown-linux-gnu --crate-type=rlib -Cno-prepopulate-passes
+#![no_core]
+#![feature(no_core, lang_items, c_unwind)]
+#[lang="sized"]
+trait Sized { }
+
+// Test that `nounwind` atributes are correctly applied to exported `win64` and
+// `win64-unwind` extern functions. `win64-unwind` functions MUST NOT have this attribute. We
+// disable optimizations above to prevent LLVM from inferring the attribute.
+
+// CHECK: @rust_item_that_cannot_unwind() unnamed_addr #0 {
+#[no_mangle]
+pub extern "win64" fn rust_item_that_cannot_unwind() {
+}
+
+// CHECK: @rust_item_that_can_unwind() unnamed_addr #1 {
+#[no_mangle]
+pub extern "win64-unwind" fn rust_item_that_can_unwind() {
+}
+
+// Now, make some assertions that the LLVM attributes for these functions are correct. First, make
+// sure that the first item is correctly marked with the `nounwind` attribute:
+//
+// CHECK: attributes #0 = { {{.*}}nounwind{{.*}} }
+//
+// Next, let's assert that the second item, which CAN unwind, does not have this attribute.
+//
+// CHECK: attributes #1 = {
+// CHECK-NOT: nounwind
+// CHECK: }
}
#[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(cfg = "cfail2", except = "hir_owner, hir_owner_nodes, typeck, fn_sig")]
+#[rustc_clean(cfg = "cfail2", except = "hir_owner, hir_owner_nodes, typeck, fn_sig, optimized_mir")]
#[rustc_clean(cfg = "cfail3")]
#[rustc_clean(cfg = "cfail5", except = "hir_owner, hir_owner_nodes, typeck, fn_sig, optimized_mir")]
#[rustc_clean(cfg = "cfail6")]
6| | println!("called but not covered");
7| |}
8| |
- 9| |#[no_coverage]
- 10| |fn do_not_add_coverage_2() {
+ 9| |fn do_not_add_coverage_2() {
+ 10| | #![no_coverage]
11| | println!("called but not covered");
12| |}
13| |
28| 0| println!("not called but covered");
29| 0|}
30| |
- 31| 1|fn main() {
- 32| 1| do_not_add_coverage_1();
- 33| 1| do_not_add_coverage_2();
- 34| 1| add_coverage_1();
- 35| 1| add_coverage_2();
- 36| 1|}
+ 31| |// FIXME: These test-cases illustrate confusing results of nested functions.
+ 32| |// See https://github.com/rust-lang/rust/issues/93319
+ 33| |mod nested_fns {
+ 34| | #[no_coverage]
+ 35| | pub fn outer_not_covered(is_true: bool) {
+ 36| 1| fn inner(is_true: bool) {
+ 37| 1| if is_true {
+ 38| 1| println!("called and covered");
+ 39| 1| } else {
+ 40| 0| println!("absolutely not covered");
+ 41| 0| }
+ 42| 1| }
+ 43| | println!("called but not covered");
+ 44| | inner(is_true);
+ 45| | }
+ 46| |
+ 47| 1| pub fn outer(is_true: bool) {
+ 48| 1| println!("called and covered");
+ 49| 1| inner_not_covered(is_true);
+ 50| 1|
+ 51| 1| #[no_coverage]
+ 52| 1| fn inner_not_covered(is_true: bool) {
+ 53| 1| if is_true {
+ 54| 1| println!("called but not covered");
+ 55| 1| } else {
+ 56| 1| println!("absolutely not covered");
+ 57| 1| }
+ 58| 1| }
+ 59| 1| }
+ 60| |
+ 61| 1| pub fn outer_both_covered(is_true: bool) {
+ 62| 1| println!("called and covered");
+ 63| 1| inner(is_true);
+ 64| 1|
+ 65| 1| fn inner(is_true: bool) {
+ 66| 1| if is_true {
+ 67| 1| println!("called and covered");
+ 68| 1| } else {
+ 69| 0| println!("absolutely not covered");
+ 70| 0| }
+ 71| 1| }
+ 72| 1| }
+ 73| |}
+ 74| |
+ 75| 1|fn main() {
+ 76| 1| let is_true = std::env::args().len() == 1;
+ 77| 1|
+ 78| 1| do_not_add_coverage_1();
+ 79| 1| do_not_add_coverage_2();
+ 80| 1| add_coverage_1();
+ 81| 1| add_coverage_2();
+ 82| 1|
+ 83| 1| nested_fns::outer_not_covered(is_true);
+ 84| 1| nested_fns::outer(is_true);
+ 85| 1| nested_fns::outer_both_covered(is_true);
+ 86| 1|}
println!("called but not covered");
}
-#[no_coverage]
fn do_not_add_coverage_2() {
+ #![no_coverage]
println!("called but not covered");
}
println!("not called but covered");
}
+// FIXME: These test-cases illustrate confusing results of nested functions.
+// See https://github.com/rust-lang/rust/issues/93319
+mod nested_fns {
+ #[no_coverage]
+ pub fn outer_not_covered(is_true: bool) {
+ fn inner(is_true: bool) {
+ if is_true {
+ println!("called and covered");
+ } else {
+ println!("absolutely not covered");
+ }
+ }
+ println!("called but not covered");
+ inner(is_true);
+ }
+
+ pub fn outer(is_true: bool) {
+ println!("called and covered");
+ inner_not_covered(is_true);
+
+ #[no_coverage]
+ fn inner_not_covered(is_true: bool) {
+ if is_true {
+ println!("called but not covered");
+ } else {
+ println!("absolutely not covered");
+ }
+ }
+ }
+
+ pub fn outer_both_covered(is_true: bool) {
+ println!("called and covered");
+ inner(is_true);
+
+ fn inner(is_true: bool) {
+ if is_true {
+ println!("called and covered");
+ } else {
+ println!("absolutely not covered");
+ }
+ }
+ }
+}
+
fn main() {
+ let is_true = std::env::args().len() == 1;
+
do_not_add_coverage_1();
do_not_add_coverage_2();
add_coverage_1();
add_coverage_2();
+
+ nested_fns::outer_not_covered(is_true);
+ nested_fns::outer(is_true);
+ nested_fns::outer_both_covered(is_true);
}
{ "type": "test", "name": "c", "event": "ok" }
{ "type": "test", "event": "started", "name": "d" }
{ "type": "test", "name": "d", "event": "ignored" }
-{ "type": "suite", "event": "failed", "passed": 2, "failed": 1, "allowed_fail": 0, "ignored": 1, "measured": 0, "filtered_out": 0, "exec_time": $TIME }
+{ "type": "suite", "event": "failed", "passed": 2, "failed": 1, "ignored": 1, "measured": 0, "filtered_out": 0, "exec_time": $TIME }
{ "type": "test", "name": "c", "event": "ok", "stdout": "thread 'main' panicked at 'assertion failed: false', f.rs:15:5\n" }
{ "type": "test", "event": "started", "name": "d" }
{ "type": "test", "name": "d", "event": "ignored" }
-{ "type": "suite", "event": "failed", "passed": 2, "failed": 1, "allowed_fail": 0, "ignored": 1, "measured": 0, "filtered_out": 0, "exec_time": $TIME }
+{ "type": "suite", "event": "failed", "passed": 2, "failed": 1, "ignored": 1, "measured": 0, "filtered_out": 0, "exec_time": $TIME }
--- /dev/null
+deps := ex
+
+-include ../rustdoc-scrape-examples-multiple/scrape.mk
+
+all: scrape
--- /dev/null
+struct Foo;
+impl Foo {
+ fn bar() { foobar::ok(); }
+}
+
+fn main() {
+ Foo::bar();
+}
--- /dev/null
+// @has foobar/fn.ok.html '//*[@class="docblock scraped-example-list"]//code' ' '
+
+pub fn ok() {}
"flex-direction": "column"
})
-assert-property: (".mobile-topbar h2.location", {"offsetHeight": 45})
+assert-property: (".mobile-topbar h2.location", {"offsetHeight": 48})
// Note: We can't use assert-text here because the 'Since' is set by CSS and
// is therefore not part of the DOM.
// Check that the bottom-most item on the sidebar menu can be scrolled fully into view.
click: ".sidebar-menu-toggle"
scroll-to: ".block.keyword li:nth-child(1)"
-assert-position: (".block.keyword li:nth-child(1)", {"y": 542.96875})
+compare-elements-position-near: (".block.keyword li:nth-child(1)", ".mobile-topbar", {"y": 543})
// Links to trait implementations in the sidebar should not wrap even if they are long.
goto: file://|DOC_PATH|/lib2/struct.HasALongTraitWithParams.html
-assert-property: (".sidebar-links a", {"offsetHeight": 29})
+assert-property: (".sidebar-links a", {"offsetHeight": 30})
+
+// Test that clicking on of the "In <module>" headings in the sidebar links to the
+// appropriate anchor in index.html.
+goto: file://|DOC_PATH|/test_docs/struct.Foo.html
+click: ".block.mod h3 a"
+// PAGE: index.html
+assert-css: ("#modules", {"background-color": "rgb(253, 255, 211)"})
size: (600, 600)
goto: file://|DOC_PATH|/lib2/too_long/struct.SuperIncrediblyLongLongLongLongLongLongLongGigaGigaGigaMegaLongLongLongStructName.html
// It shouldn't have an overflow in the topbar either.
-assert-property: (".mobile-topbar .location", {"scrollWidth": "986"})
-assert-property: (".mobile-topbar .location", {"clientWidth": "504"})
+assert-property: (".mobile-topbar .location", {"scrollWidth": "493"})
+assert-property: (".mobile-topbar .location", {"clientWidth": "493"})
assert-css: (".mobile-topbar .location", {"overflow-x": "hidden"})
--- /dev/null
+// check-pass
+// compile-flags:--test
+
+// This test ensures that no code block is detected in the doc comments.
+
+pub mod Wormhole {
+ /** # Returns
+ *
+ */
+ pub fn foofoo() {}
+ /**
+ * # Returns
+ *
+ */
+ pub fn barbar() {}
+}
--- /dev/null
+
+running 0 tests
+
+test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
+
/// ```
pub fn foobar() {}
-/// barfoo
-///
-/// ```allow-fail,allowfail,allOw_fail
-/// boo
-/// ```
-pub fn barfoo() {}
-
/// b
///
/// ```test-harness,testharness,tesT_harness
|
= help: the code block will either not be tested if not marked as a rust one or will be run (which you might not want)
-error: unknown attribute `allow-fail`. Did you mean `allow_fail`?
+error: unknown attribute `test-harness`. Did you mean `test_harness`?
--> $DIR/check-attr-test.rs:26:1
|
-26 | / /// barfoo
+26 | / /// b
27 | | ///
-28 | | /// ```allow-fail,allowfail,allOw_fail
+28 | | /// ```test-harness,testharness,tesT_harness
29 | | /// boo
30 | | /// ```
| |_______^
|
- = help: the code block will either not be tested if not marked as a rust one or will be run (which you might not want)
+ = help: the code block will either not be tested if not marked as a rust one or the code will be wrapped inside a main function
-error: unknown attribute `allowfail`. Did you mean `allow_fail`?
+error: unknown attribute `testharness`. Did you mean `test_harness`?
--> $DIR/check-attr-test.rs:26:1
|
-26 | / /// barfoo
+26 | / /// b
27 | | ///
-28 | | /// ```allow-fail,allowfail,allOw_fail
+28 | | /// ```test-harness,testharness,tesT_harness
29 | | /// boo
30 | | /// ```
| |_______^
|
- = help: the code block will either not be tested if not marked as a rust one or will be run (which you might not want)
+ = help: the code block will either not be tested if not marked as a rust one or the code will be wrapped inside a main function
-error: unknown attribute `allOw_fail`. Did you mean `allow_fail`?
+error: unknown attribute `tesT_harness`. Did you mean `test_harness`?
--> $DIR/check-attr-test.rs:26:1
|
-26 | / /// barfoo
+26 | / /// b
27 | | ///
-28 | | /// ```allow-fail,allowfail,allOw_fail
+28 | | /// ```test-harness,testharness,tesT_harness
29 | | /// boo
30 | | /// ```
- | |_______^
- |
- = help: the code block will either not be tested if not marked as a rust one or will be run (which you might not want)
-
-error: unknown attribute `test-harness`. Did you mean `test_harness`?
- --> $DIR/check-attr-test.rs:33:1
- |
-33 | / /// b
-34 | | ///
-35 | | /// ```test-harness,testharness,tesT_harness
-36 | | /// boo
-37 | | /// ```
- | |_______^
- |
- = help: the code block will either not be tested if not marked as a rust one or the code will be wrapped inside a main function
-
-error: unknown attribute `testharness`. Did you mean `test_harness`?
- --> $DIR/check-attr-test.rs:33:1
- |
-33 | / /// b
-34 | | ///
-35 | | /// ```test-harness,testharness,tesT_harness
-36 | | /// boo
-37 | | /// ```
- | |_______^
- |
- = help: the code block will either not be tested if not marked as a rust one or the code will be wrapped inside a main function
-
-error: unknown attribute `tesT_harness`. Did you mean `test_harness`?
- --> $DIR/check-attr-test.rs:33:1
- |
-33 | / /// b
-34 | | ///
-35 | | /// ```test-harness,testharness,tesT_harness
-36 | | /// boo
-37 | | /// ```
| |_______^
|
= help: the code block will either not be tested if not marked as a rust one or the code will be wrapped inside a main function
-error: aborting due to 15 previous errors
+error: aborting due to 12 previous errors
/// ```
pub fn foobar() {}
-/// barfoo
-//~^ ERROR
-//~^^ ERROR
-//~^^^ ERROR
-///
-/// ```allow-fail,allowfail,alLow_fail
-/// boo
-/// ```
-pub fn barfoo() {}
-
/// b
//~^ ERROR
//~^^ ERROR
|
= help: the code block will either not be tested if not marked as a rust one or will be run (which you might not want)
-error: unknown attribute `allow-fail`. Did you mean `allow_fail`?
- --> $DIR/check-attr.rs:33:1
- |
-LL | / /// barfoo
-LL | |
-LL | |
-LL | |
-... |
-LL | | /// boo
-LL | | /// ```
- | |_______^
- |
- = help: the code block will either not be tested if not marked as a rust one or will be run (which you might not want)
-
-error: unknown attribute `allowfail`. Did you mean `allow_fail`?
- --> $DIR/check-attr.rs:33:1
- |
-LL | / /// barfoo
-LL | |
-LL | |
-LL | |
-... |
-LL | | /// boo
-LL | | /// ```
- | |_______^
- |
- = help: the code block will either not be tested if not marked as a rust one or will be run (which you might not want)
-
-error: unknown attribute `alLow_fail`. Did you mean `allow_fail`?
- --> $DIR/check-attr.rs:33:1
- |
-LL | / /// barfoo
-LL | |
-LL | |
-LL | |
-... |
-LL | | /// boo
-LL | | /// ```
- | |_______^
- |
- = help: the code block will either not be tested if not marked as a rust one or will be run (which you might not want)
-
error: unknown attribute `test-harness`. Did you mean `test_harness`?
- --> $DIR/check-attr.rs:43:1
+ --> $DIR/check-attr.rs:33:1
|
LL | / /// b
LL | |
= help: the code block will either not be tested if not marked as a rust one or the code will be wrapped inside a main function
error: unknown attribute `testharness`. Did you mean `test_harness`?
- --> $DIR/check-attr.rs:43:1
+ --> $DIR/check-attr.rs:33:1
|
LL | / /// b
LL | |
= help: the code block will either not be tested if not marked as a rust one or the code will be wrapped inside a main function
error: unknown attribute `teSt_harness`. Did you mean `test_harness`?
- --> $DIR/check-attr.rs:43:1
+ --> $DIR/check-attr.rs:33:1
|
LL | / /// b
LL | |
|
= help: the code block will either not be tested if not marked as a rust one or the code will be wrapped inside a main function
-error: aborting due to 15 previous errors
+error: aborting due to 12 previous errors
--- /dev/null
+// check-pass
+#![allow(rustdoc::private_intra_doc_links)]
+
+macro_rules! foo {
+ () => {};
+}
+
+/// [foo!]
+pub fn baz() {}
--- /dev/null
+#![deny(rustdoc::invalid_html_tags)]
+
+/// This Vec<32> thing!
+// Numbers aren't valid HTML tags, so no error.
+pub struct ConstGeneric;
+
+/// This Vec<i32, i32> thing!
+// HTML tags cannot contain commas, so no error.
+pub struct MultipleGenerics;
+
+/// This Vec<i32 class="test"> thing!
+//~^ERROR unclosed HTML tag `i32`
+// HTML attributes shouldn't be treated as Rust syntax, so no suggestions.
+pub struct TagWithAttributes;
+
+/// This Vec<i32></i32> thing!
+// There should be no error, and no suggestion, since the tags are balanced.
+pub struct DoNotWarnOnMatchingTags;
+
+/// This Vec</i32> thing!
+//~^ERROR unopened HTML tag `i32`
+// This should produce an error, but no suggestion.
+pub struct EndTagsAreNotValidRustSyntax;
+
+/// This 123<i32> thing!
+//~^ERROR unclosed HTML tag `i32`
+// This should produce an error, but no suggestion.
+pub struct NumbersAreNotPaths;
+
+/// This Vec:<i32> thing!
+//~^ERROR unclosed HTML tag `i32`
+// This should produce an error, but no suggestion.
+pub struct InvalidTurbofish;
+
+/// This [link](https://rust-lang.org)<i32> thing!
+//~^ERROR unclosed HTML tag `i32`
+// This should produce an error, but no suggestion.
+pub struct BareTurbofish;
--- /dev/null
+error: unclosed HTML tag `i32`
+ --> $DIR/html-as-generics-no-suggestions.rs:11:13
+ |
+LL | /// This Vec<i32 class="test"> thing!
+ | ^^^^
+ |
+note: the lint level is defined here
+ --> $DIR/html-as-generics-no-suggestions.rs:1:9
+ |
+LL | #![deny(rustdoc::invalid_html_tags)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: unopened HTML tag `i32`
+ --> $DIR/html-as-generics-no-suggestions.rs:20:13
+ |
+LL | /// This Vec</i32> thing!
+ | ^^^^^^
+
+error: unclosed HTML tag `i32`
+ --> $DIR/html-as-generics-no-suggestions.rs:25:13
+ |
+LL | /// This 123<i32> thing!
+ | ^^^^^
+
+error: unclosed HTML tag `i32`
+ --> $DIR/html-as-generics-no-suggestions.rs:30:14
+ |
+LL | /// This Vec:<i32> thing!
+ | ^^^^^
+
+error: unclosed HTML tag `i32`
+ --> $DIR/html-as-generics-no-suggestions.rs:35:39
+ |
+LL | /// This [link](https://rust-lang.org)<i32> thing!
+ | ^^^^^
+
+error: aborting due to 5 previous errors
+
--- /dev/null
+// run-rustfix
+#![deny(rustdoc::invalid_html_tags)]
+
+/// This `Vec<i32>` thing!
+//~^ERROR unclosed HTML tag `i32`
+//~|HELP try marking as source
+pub struct Generic;
+
+/// This `vec::Vec<i32>` thing!
+//~^ERROR unclosed HTML tag `i32`
+//~|HELP try marking as source
+pub struct GenericPath;
+
+/// This `i32<i32>` thing!
+//~^ERROR unclosed HTML tag `i32`
+//~|HELP try marking as source
+pub struct PathsCanContainTrailingNumbers;
+
+/// This `Vec::<i32>` thing!
+//~^ERROR unclosed HTML tag `i32`
+//~|HELP try marking as source
+pub struct Turbofish;
+
+/// This [link](https://rust-lang.org)`::<i32>` thing!
+//~^ERROR unclosed HTML tag `i32`
+//~|HELP try marking as source
+pub struct BareTurbofish;
+
+/// This <span>`Vec::<i32>`</span> thing!
+//~^ERROR unclosed HTML tag `i32`
+//~|HELP try marking as source
+pub struct Nested;
--- /dev/null
+// run-rustfix
+#![deny(rustdoc::invalid_html_tags)]
+
+/// This Vec<i32> thing!
+//~^ERROR unclosed HTML tag `i32`
+//~|HELP try marking as source
+pub struct Generic;
+
+/// This vec::Vec<i32> thing!
+//~^ERROR unclosed HTML tag `i32`
+//~|HELP try marking as source
+pub struct GenericPath;
+
+/// This i32<i32> thing!
+//~^ERROR unclosed HTML tag `i32`
+//~|HELP try marking as source
+pub struct PathsCanContainTrailingNumbers;
+
+/// This Vec::<i32> thing!
+//~^ERROR unclosed HTML tag `i32`
+//~|HELP try marking as source
+pub struct Turbofish;
+
+/// This [link](https://rust-lang.org)::<i32> thing!
+//~^ERROR unclosed HTML tag `i32`
+//~|HELP try marking as source
+pub struct BareTurbofish;
+
+/// This <span>Vec::<i32></span> thing!
+//~^ERROR unclosed HTML tag `i32`
+//~|HELP try marking as source
+pub struct Nested;
--- /dev/null
+error: unclosed HTML tag `i32`
+ --> $DIR/html-as-generics.rs:4:13
+ |
+LL | /// This Vec<i32> thing!
+ | ^^^^^
+ |
+note: the lint level is defined here
+ --> $DIR/html-as-generics.rs:2:9
+ |
+LL | #![deny(rustdoc::invalid_html_tags)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: try marking as source code
+ |
+LL | /// This `Vec<i32>` thing!
+ | + +
+
+error: unclosed HTML tag `i32`
+ --> $DIR/html-as-generics.rs:9:18
+ |
+LL | /// This vec::Vec<i32> thing!
+ | ^^^^^
+ |
+help: try marking as source code
+ |
+LL | /// This `vec::Vec<i32>` thing!
+ | + +
+
+error: unclosed HTML tag `i32`
+ --> $DIR/html-as-generics.rs:14:13
+ |
+LL | /// This i32<i32> thing!
+ | ^^^^^
+ |
+help: try marking as source code
+ |
+LL | /// This `i32<i32>` thing!
+ | + +
+
+error: unclosed HTML tag `i32`
+ --> $DIR/html-as-generics.rs:19:15
+ |
+LL | /// This Vec::<i32> thing!
+ | ^^^^^
+ |
+help: try marking as source code
+ |
+LL | /// This `Vec::<i32>` thing!
+ | + +
+
+error: unclosed HTML tag `i32`
+ --> $DIR/html-as-generics.rs:24:41
+ |
+LL | /// This [link](https://rust-lang.org)::<i32> thing!
+ | ^^^^^
+ |
+help: try marking as source code
+ |
+LL | /// This [link](https://rust-lang.org)`::<i32>` thing!
+ | + +
+
+error: unclosed HTML tag `i32`
+ --> $DIR/html-as-generics.rs:29:21
+ |
+LL | /// This <span>Vec::<i32></span> thing!
+ | ^^^^^
+ |
+help: try marking as source code
+ |
+LL | /// This <span>`Vec::<i32>`</span> thing!
+ | + +
+
+error: aborting due to 6 previous errors
+
#![crate_name = "foo"]
-// The goal of this test is to answer that it won't be generated as a list because
+// The goal of this test is to ensure that it won't be generated as a list because
// block doc comments can have their lines starting with a star.
// @has foo/fn.foo.html
error[E0277]: the trait bound `usize: GlobalAlloc` is not satisfied
- --> $DIR/not-an-allocator.rs:2:1
+ --> $DIR/not-an-allocator.rs:2:11
|
LL | #[global_allocator]
| ------------------- in this procedural macro expansion
LL | static A: usize = 0;
- | ^^^^^^^^^^^^^^^^^^^^ the trait `GlobalAlloc` is not implemented for `usize`
+ | ^^^^^ the trait `GlobalAlloc` is not implemented for `usize`
|
= note: this error originates in the attribute macro `global_allocator` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0277]: the trait bound `usize: GlobalAlloc` is not satisfied
- --> $DIR/not-an-allocator.rs:2:1
+ --> $DIR/not-an-allocator.rs:2:11
|
LL | #[global_allocator]
| ------------------- in this procedural macro expansion
LL | static A: usize = 0;
- | ^^^^^^^^^^^^^^^^^^^^ the trait `GlobalAlloc` is not implemented for `usize`
+ | ^^^^^ the trait `GlobalAlloc` is not implemented for `usize`
|
= note: this error originates in the attribute macro `global_allocator` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0277]: the trait bound `usize: GlobalAlloc` is not satisfied
- --> $DIR/not-an-allocator.rs:2:1
+ --> $DIR/not-an-allocator.rs:2:11
|
LL | #[global_allocator]
| ------------------- in this procedural macro expansion
LL | static A: usize = 0;
- | ^^^^^^^^^^^^^^^^^^^^ the trait `GlobalAlloc` is not implemented for `usize`
+ | ^^^^^ the trait `GlobalAlloc` is not implemented for `usize`
|
= note: this error originates in the attribute macro `global_allocator` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0277]: the trait bound `usize: GlobalAlloc` is not satisfied
- --> $DIR/not-an-allocator.rs:2:1
+ --> $DIR/not-an-allocator.rs:2:11
|
LL | #[global_allocator]
| ------------------- in this procedural macro expansion
LL | static A: usize = 0;
- | ^^^^^^^^^^^^^^^^^^^^ the trait `GlobalAlloc` is not implemented for `usize`
+ | ^^^^^ the trait `GlobalAlloc` is not implemented for `usize`
|
= note: this error originates in the attribute macro `global_allocator` (in Nightly builds, run with -Z macro-backtrace for more info)
type Out = Box<dyn Bar<Assoc: Copy>>;
fn func() -> Self::Out {
- //~^ ERROR the trait bound `String: Copy` is not satisfied
Box::new(AssocNoCopy)
+ //~^ ERROR the trait bound `String: Copy` is not satisfied
}
}
error[E0277]: the trait bound `String: Copy` is not satisfied
- --> $DIR/assoc-type-eq-with-dyn-atb-fail.rs:32:18
+ --> $DIR/assoc-type-eq-with-dyn-atb-fail.rs:33:9
|
-LL | fn func() -> Self::Out {
- | ^^^^^^^^^ the trait `Copy` is not implemented for `String`
+LL | Box::new(AssocNoCopy)
+ | ^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `String`
+ |
+ = note: required for the cast to the object type `dyn Bar<Assoc = <AssocNoCopy as Thing>::Out::{opaque#0}>`
error: aborting due to previous error
}
fn baz() -> impl Bar<Item = i32> {
-//~^ ERROR type mismatch resolving `<impl Bar as Foo>::Item == i32`
bar()
+ //~^ ERROR type mismatch resolving `<impl Bar as Foo>::Item == i32`
}
fn main() {
error[E0271]: type mismatch resolving `<impl Bar as Foo>::Item == i32`
- --> $DIR/impl-trait-return-missing-constraint.rs:25:13
+ --> $DIR/impl-trait-return-missing-constraint.rs:26:5
|
LL | fn bar() -> impl Bar {
- | -------- the found opaque type
+ | -------- the expected opaque type
...
-LL | fn baz() -> impl Bar<Item = i32> {
- | ^^^^^^^^^^^^^^^^^^^^ expected `i32`, found associated type
+LL | bar()
+ | ^^^^^ expected associated type, found `i32`
|
- = note: expected type `i32`
- found associated type `<impl Bar as Foo>::Item`
+ = note: expected associated type `<impl Bar as Foo>::Item`
+ found type `i32`
+ = help: consider constraining the associated type `<impl Bar as Foo>::Item` to `i32` or calling a method that returns `<impl Bar as Foo>::Item`
+ = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
help: consider constraining the associated type `<impl Bar as Foo>::Item` to `i32`
|
LL | fn bar() -> impl Bar<Item = i32> {
| may outlive borrowed value `x`
|
note: async block is returned here
- --> $DIR/async-borrowck-escaping-block-error.rs:4:20
+ --> $DIR/async-borrowck-escaping-block-error.rs:6:5
|
-LL | fn test_boxed() -> Box<impl std::future::Future<Output = u32>> {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | Box::new(async { x } )
+ | ^^^^^^^^^^^^^^^^^^^^^^
help: to force the async block to take ownership of `x` (and any other referenced variables), use the `move` keyword
|
LL | Box::new(async move { x } )
async fn get() { }
pub fn foo() -> impl Future + Send {
- //~^ ERROR future cannot be sent between threads safely
let client = Client(Box::new(true));
async move {
+ //~^ ERROR future cannot be sent between threads safely
match client.status() {
200 => {
let _x = get().await;
error: future cannot be sent between threads safely
- --> $DIR/issue-64130-4-async-move.rs:15:17
+ --> $DIR/issue-64130-4-async-move.rs:17:5
|
-LL | pub fn foo() -> impl Future + Send {
- | ^^^^^^^^^^^^^^^^^^ future created by async block is not `Send`
+LL | async move {
+ | ^^^^^^^^^^ future created by async block is not `Send`
|
= help: the trait `Sync` is not implemented for `(dyn Any + Send + 'static)`
note: future is not `Send` as this value is used across an await
use std::future::Future;
fn foo<T: Send, U>(ty: T, ty1: U) -> impl Future<Output = (T, U)> + Send {
-//~^ Error future cannot be sent between threads safely
async { (ty, ty1) }
+ //~^ Error future cannot be sent between threads safely
}
fn main() {}
error: future cannot be sent between threads safely
- --> $DIR/issue-70818.rs:4:38
+ --> $DIR/issue-70818.rs:5:5
|
-LL | fn foo<T: Send, U>(ty: T, ty1: U) -> impl Future<Output = (T, U)> + Send {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future created by async block is not `Send`
+LL | async { (ty, ty1) }
+ | ^^^^^ future created by async block is not `Send`
|
note: captured value is not `Send`
- --> $DIR/issue-70818.rs:6:18
+ --> $DIR/issue-70818.rs:5:18
|
LL | async { (ty, ty1) }
| ^^^ has type `U` which is not `Send`
}
fn foo(tx: std::sync::mpsc::Sender<i32>) -> impl Future + Send {
- //~^ ERROR: future cannot be sent between threads safely
async move {
+ //~^ ERROR: future cannot be sent between threads safely
baz(|| async{
foo(tx.clone());
}).await;
error: future cannot be sent between threads safely
- --> $DIR/issue-70935-complex-spans.rs:10:45
+ --> $DIR/issue-70935-complex-spans.rs:11:5
|
-LL | fn foo(tx: std::sync::mpsc::Sender<i32>) -> impl Future + Send {
- | ^^^^^^^^^^^^^^^^^^ future created by async block is not `Send`
+LL | async move {
+ | ^^^^^^^^^^ future created by async block is not `Send`
|
= help: the trait `Sync` is not implemented for `Sender<i32>`
note: future is not `Send` as this value is used across an await
= help: consider adding the following bound: `'a: 'b`
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
- --> $DIR/ret-impl-trait-one.rs:16:65
+ --> $DIR/ret-impl-trait-one.rs:16:80
|
-LL | async fn async_ret_impl_trait1<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> {
- | -- ^^^^^^^^^^^^^^
- | |
- | hidden type `(&'a u8, &'b u8)` captures the lifetime `'b` as defined here
+LL | async fn async_ret_impl_trait1<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> {
+ | ____________________________________--__________________________________________^
+ | | |
+ | | hidden type `(&'a u8, &'b u8)` captures the lifetime `'b` as defined here
+LL | |
+LL | | (a, b)
+LL | | }
+ | |_^
|
help: to declare that the `impl Trait` captures `'b`, you can add an explicit `'b` lifetime bound
|
error[E0623]: lifetime mismatch
- --> $DIR/ret-impl-trait-one.rs:10:65
+ --> $DIR/ret-impl-trait-one.rs:10:85
|
-LL | async fn async_ret_impl_trait3<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> + 'b {
- | ------ ^^^^^^^^^^^^^^^^^^^
- | | |
- | | ...but data from `a` is returned here
- | this parameter and the return type are declared with different lifetimes...
+LL | async fn async_ret_impl_trait3<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> + 'b {
+ | ______________________________________________________------_____-------------------_^
+ | | |
+ | | this parameter and the return type are declared with different lifetimes...
+LL | |
+LL | | (a, b)
+LL | | }
+ | |_^ ...but data from `a` is returned here
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
- --> $DIR/ret-impl-trait-one.rs:16:65
+ --> $DIR/ret-impl-trait-one.rs:16:80
|
-LL | async fn async_ret_impl_trait1<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> {
- | -- ^^^^^^^^^^^^^^
- | |
- | hidden type `(&'a u8, &'b u8)` captures the lifetime `'b` as defined here
+LL | async fn async_ret_impl_trait1<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> {
+ | ____________________________________--__________________________________________^
+ | | |
+ | | hidden type `(&'a u8, &'b u8)` captures the lifetime `'b` as defined here
+LL | |
+LL | | (a, b)
+LL | | }
+ | |_^
|
help: to declare that the `impl Trait` captures `'b`, you can add an explicit `'b` lifetime bound
|
pub const async fn x() {}
//~^ ERROR functions cannot be both `const` and `async`
+//~| ERROR cycle detected
| | `async` because of this
| `const` because of this
-error: aborting due to previous error
+error[E0391]: cycle detected when computing type of `x::{opaque#0}`
+ --> $DIR/no-const-async.rs:4:24
+ |
+LL | pub const async fn x() {}
+ | ^
+ |
+note: ...which requires borrow-checking `x`...
+ --> $DIR/no-const-async.rs:4:1
+ |
+LL | pub const async fn x() {}
+ | ^^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires processing `x`...
+ --> $DIR/no-const-async.rs:4:1
+ |
+LL | pub const async fn x() {}
+ | ^^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires const checking `x`...
+ --> $DIR/no-const-async.rs:4:1
+ |
+LL | pub const async fn x() {}
+ | ^^^^^^^^^^^^^^^^^^^^^^
+ = note: ...which requires computing whether `impl core::future::future::Future<Output = ()>` is freeze...
+ = note: ...which requires evaluating trait selection obligation `impl core::future::future::Future<Output = ()>: core::marker::Freeze`...
+ = note: ...which again requires computing type of `x::{opaque#0}`, completing the cycle
+note: cycle used when checking item types in top-level module
+ --> $DIR/no-const-async.rs:4:1
+ |
+LL | pub const async fn x() {}
+ | ^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+For more information about this error, try `rustc --explain E0391`.
// Test that impl trait does not allow creating recursive types that are
// otherwise forbidden when using `async` and `await`.
-async fn recursive_async_function() -> () { //~ ERROR
+async fn recursive_async_function() -> () {
+ //~^ ERROR recursion in an `async fn` requires boxing
recursive_async_function().await;
}
async fn suggest_await_in_async_fn_return() {
dummy()
//~^ ERROR mismatched types [E0308]
- //~| HELP consider using a semicolon here
//~| HELP consider `await`ing on the `Future`
//~| SUGGESTION .await
}
|
LL | dummy().await
| ++++++
-help: consider using a semicolon here
- |
-LL | dummy();
- | +
error[E0308]: `if` and `else` have incompatible types
- --> $DIR/suggest-missing-await.rs:35:9
+ --> $DIR/suggest-missing-await.rs:34:9
|
LL | let _x = if true {
| ______________-
LL | | };
| |_____- `if` and `else` have incompatible types
|
- = note: expected type `impl Future<Output = ()>`
- found unit type `()`
+note: while checking the return type of the `async fn`
+ --> $DIR/suggest-missing-await.rs:18:18
+ |
+LL | async fn dummy() {}
+ | ^ checked the `Output` of this `async fn`, expected opaque type
+ = note: expected opaque type `impl Future<Output = ()>`
+ found unit type `()`
help: consider `await`ing on the `Future`
|
LL | dummy().await
| ++++++
error[E0308]: `match` arms have incompatible types
- --> $DIR/suggest-missing-await.rs:45:14
+ --> $DIR/suggest-missing-await.rs:44:14
|
LL | let _x = match 0usize {
| ______________-
|
error[E0308]: mismatched types
- --> $DIR/suggest-missing-await.rs:53:9
+ --> $DIR/suggest-missing-await.rs:52:9
|
LL | () => {}
| ^^ expected opaque type, found `()`
| ++++++
error[E0308]: mismatched types
- --> $DIR/suggest-missing-await.rs:67:9
+ --> $DIR/suggest-missing-await.rs:66:9
|
LL | Ok(_) => {}
| ^^^^^ expected opaque type, found enum `Result`
|
note: while checking the return type of the `async fn`
- --> $DIR/suggest-missing-await.rs:57:28
+ --> $DIR/suggest-missing-await.rs:56:28
|
LL | async fn dummy_result() -> Result<(), ()> {
| ^^^^^^^^^^^^^^ checked the `Output` of this `async fn`, expected opaque type
| ++++++
error[E0308]: mismatched types
- --> $DIR/suggest-missing-await.rs:69:9
+ --> $DIR/suggest-missing-await.rs:68:9
|
LL | Err(_) => {}
| ^^^^^^ expected opaque type, found enum `Result`
|
note: while checking the return type of the `async fn`
- --> $DIR/suggest-missing-await.rs:57:28
+ --> $DIR/suggest-missing-await.rs:56:28
|
LL | async fn dummy_result() -> Result<(), ()> {
| ^^^^^^^^^^^^^^ checked the `Output` of this `async fn`, expected opaque type
// this is an `*mut fmt::Debug` in practice
let mut b_raw = Box::into_raw(b);
// ... and they should not be mixable
- b_raw = f_raw as *mut _; //~ ERROR is invalid
+ b_raw = f_raw as *mut _; //~ ERROR mismatched types
}
-error[E0606]: casting `*mut impl Debug + ?Sized` as `*mut impl Debug + ?Sized` is invalid
+error[E0308]: mismatched types
--> $DIR/casts-differing-anon.rs:21:13
|
+LL | fn foo() -> Box<impl fmt::Debug+?Sized> {
+ | ---------------------- the found opaque type
+...
+LL | fn bar() -> Box<impl fmt::Debug+?Sized> {
+ | ---------------------- the expected opaque type
+...
LL | b_raw = f_raw as *mut _;
- | ^^^^^^^^^^^^^^^
+ | ^^^^^ expected opaque type, found a different opaque type
|
- = note: vtable kinds may not match
+ = note: expected opaque type `impl Debug + ?Sized` (opaque type at <$DIR/casts-differing-anon.rs:7:17>)
+ found opaque type `impl Debug + ?Sized` (opaque type at <$DIR/casts-differing-anon.rs:3:17>)
+ = note: distinct uses of `impl Trait` result in different opaque types
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0606`.
+For more information about this error, try `rustc --explain E0308`.
| - `p` is borrowed here
|
note: closure is returned here
- --> $DIR/borrowck-4.rs:8:14
+ --> $DIR/borrowck-4.rs:15:5
|
-LL | fn foo () -> impl FnMut()->() {
- | ^^^^^^^^^^^^^^^^
+LL | c
+ | ^
help: to force the closure to take ownership of `p` (and any other referenced variables), use the `move` keyword
|
LL | let mut c = move || {
LL | extern "路濫狼á́́" fn foo() {}
| ^^^^^^^^^ invalid ABI
|
- = help: valid ABIs: Rust, C, C-unwind, cdecl, stdcall, stdcall-unwind, fastcall, vectorcall, thiscall, thiscall-unwind, aapcs, win64, sysv64, ptx-kernel, msp430-interrupt, x86-interrupt, amdgpu-kernel, efiapi, avr-interrupt, avr-non-blocking-interrupt, C-cmse-nonsecure-call, wasm, system, system-unwind, rust-intrinsic, rust-call, platform-intrinsic, unadjusted
+ = help: valid ABIs: Rust, C, C-unwind, cdecl, cdecl-unwind, stdcall, stdcall-unwind, fastcall, fastcall-unwind, vectorcall, vectorcall-unwind, thiscall, thiscall-unwind, aapcs, aapcs-unwind, win64, win64-unwind, sysv64, sysv64-unwind, ptx-kernel, msp430-interrupt, x86-interrupt, amdgpu-kernel, efiapi, avr-interrupt, avr-non-blocking-interrupt, C-cmse-nonsecure-call, wasm, system, system-unwind, rust-intrinsic, rust-call, platform-intrinsic, unadjusted
error: aborting due to previous error
error[E0277]: `()` is not an iterator
- --> $DIR/conservative_impl_trait.rs:3:33
+ --> $DIR/conservative_impl_trait.rs:3:60
|
-LL | fn will_ice(something: &u32) -> impl Iterator<Item = &u32> {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^ `()` is not an iterator
+LL | fn will_ice(something: &u32) -> impl Iterator<Item = &u32> {
+ | ____________________________________________________________^
+LL | |
+LL | | }
+ | |_^ `()` is not an iterator
|
= help: the trait `Iterator` is not implemented for `()`
impl<const N: u32> Trait for Uwu<N> {}
fn rawr() -> impl Trait {
- //~^ error: the trait bound `Uwu<10_u32, 12_u32>: Trait` is not satisfied
Uwu::<10, 12>
+ //~^ error: the trait bound `Uwu<10_u32, 12_u32>: Trait` is not satisfied
}
trait Traitor<const N: u8 = 1, const M: u8 = N> { }
fn uwu<const N: u8>() -> impl Traitor<N> {
- //~^ error: the trait bound `u32: Traitor<N, N>` is not satisfied
1_u32
+ //~^ error: the trait bound `u32: Traitor<N, N>` is not satisfied
}
fn owo() -> impl Traitor {
- //~^ error: the trait bound `u64: Traitor<1_u8, 1_u8>` is not satisfied
1_u64
+ //~^ error: the trait bound `u64: Traitor<1_u8, 1_u8>` is not satisfied
}
fn main() {
error[E0277]: the trait bound `Uwu<10_u32, 12_u32>: Trait` is not satisfied
- --> $DIR/rp_impl_trait_fail.rs:6:14
+ --> $DIR/rp_impl_trait_fail.rs:7:5
|
-LL | fn rawr() -> impl Trait {
- | ^^^^^^^^^^ the trait `Trait` is not implemented for `Uwu<10_u32, 12_u32>`
+LL | Uwu::<10, 12>
+ | ^^^^^^^^^^^^^ the trait `Trait` is not implemented for `Uwu<10_u32, 12_u32>`
|
= help: the following implementations were found:
<Uwu<N> as Trait>
error[E0277]: the trait bound `u32: Traitor<N, N>` is not satisfied
- --> $DIR/rp_impl_trait_fail.rs:17:26
+ --> $DIR/rp_impl_trait_fail.rs:18:5
|
-LL | fn uwu<const N: u8>() -> impl Traitor<N> {
- | ^^^^^^^^^^^^^^^ the trait `Traitor<N, N>` is not implemented for `u32`
+LL | 1_u32
+ | ^^^^^ the trait `Traitor<N, N>` is not implemented for `u32`
|
= help: the following implementations were found:
<u32 as Traitor<N, 2_u8>>
error[E0277]: the trait bound `u64: Traitor<1_u8, 1_u8>` is not satisfied
- --> $DIR/rp_impl_trait_fail.rs:22:13
+ --> $DIR/rp_impl_trait_fail.rs:23:5
|
-LL | fn owo() -> impl Traitor {
- | ^^^^^^^^^^^^ the trait `Traitor<1_u8, 1_u8>` is not implemented for `u64`
+LL | 1_u64
+ | ^^^^^ the trait `Traitor<1_u8, 1_u8>` is not implemented for `u64`
|
= help: the following implementations were found:
<u64 as Traitor<1_u8, 2_u8>>
|
= note: expected tuple `(usize,)`
found type `usize`
+help: use a trailing comma to create a tuple with one element
+ |
+LL | const TUP: (usize,) = (5usize << 64,);
+ | + ++
error: aborting due to previous error
LL | const fn test1<T: std::ops::Add>() {}
| ^
|
- = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
+ = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
= help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
error[E0658]: trait objects in const fn are unstable
LL | const fn test2(_x: &dyn Send) {}
| ^^
|
- = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
+ = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
= help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
error[E0658]: trait objects in const fn are unstable
LL | const fn test3() -> &'static dyn Send { loop {} }
| ^^^^^^^^^^^^^^^^^
|
- = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
+ = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
= help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
error: aborting due to 3 previous errors
LL | const fn foo11<T: std::fmt::Display>(t: T) -> T { t }
| ^
|
- = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
+ = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
= help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
error[E0658]: trait bounds other than `Sized` on const fn parameters are unstable
LL | const fn foo11_2<T: Send>(t: T) -> T { t }
| ^
|
- = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
+ = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
= help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
error[E0013]: constant functions cannot refer to statics
LL | const fn foo(&self) {}
| ------------------- function declared as const here
|
- = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
+ = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
= help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
error[E0658]: trait bounds other than `Sized` on const fn parameters are unstable
LL | const fn foo2(&self) {}
| -------------------- function declared as const here
|
- = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
+ = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
= help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
error[E0658]: trait bounds other than `Sized` on const fn parameters are unstable
LL | const fn foo3(&self) {}
| -------------------- function declared as const here
|
- = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
+ = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
= help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
error[E0658]: trait bounds other than `Sized` on const fn parameters are unstable
LL | const fn no_apit2(_x: AlanTuring<impl std::fmt::Debug>) {}
| ^^^^^^^^^^^^^^^^^^^^
|
- = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
+ = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
= help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
error[E0493]: destructors cannot be evaluated at compile-time
LL | const fn no_apit(_x: impl std::fmt::Debug) {}
| ^^^^^^^^^^^^^^^^^^^^
|
- = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
+ = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
= help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
error[E0493]: destructors cannot be evaluated at compile-time
LL | const fn no_dyn_trait(_x: &dyn std::fmt::Debug) {}
| ^^
|
- = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
+ = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
= help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
error[E0658]: trait objects in const fn are unstable
LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
+ = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
= help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
error[E0658]: trait objects in const fn are unstable
| |
| function declared as const here
|
- = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
+ = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
= help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
error[E0658]: trait objects in const fn are unstable
| |
| function declared as const here
|
- = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
+ = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
= help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
error[E0658]: trait objects in const fn are unstable
| |
| function declared as const here
|
- = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
+ = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
= help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
error[E0658]: function pointers cannot appear in constant functions
LL | x.0.field;
| ^^^^^^^^^
|
- = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
+ = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
= help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
error[E0658]: trait objects in const fn are unstable
| |
| function declared as const here
|
- = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
+ = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
= help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
error: aborting due to 2 previous errors
//~^^^ ERROR `main` function not found in crate
pub mod foo {
type MainFn = impl Fn();
- //~^ ERROR could not find defining uses
fn bar() {}
pub const BAR: MainFn = bar;
- //~^ ERROR mismatched types [E0308]
}
use foo::BAR as main;
| |
| non-function item at `crate::main` is found
-error[E0308]: mismatched types
- --> $DIR/imported_main_const_fn_item_type_forbidden.rs:10:29
- |
-LL | type MainFn = impl Fn();
- | --------- the expected opaque type
-...
-LL | pub const BAR: MainFn = bar;
- | ^^^ expected opaque type, found fn item
- |
- = note: expected opaque type `impl Fn()`
- found fn item `fn() {bar}`
-
-error: could not find defining uses
- --> $DIR/imported_main_const_fn_item_type_forbidden.rs:6:19
- |
-LL | type MainFn = impl Fn();
- | ^^^^^^^^^
-
-error: aborting due to 3 previous errors
+error: aborting due to previous error
-Some errors have detailed explanations: E0308, E0601.
-For more information about an error, try `rustc --explain E0308`.
+For more information about this error, try `rustc --explain E0601`.
+++ /dev/null
-// check that #[allow_fail] is feature-gated
-
-#[allow_fail] //~ ERROR the `#[allow_fail]` attribute is an experimental feature
-fn ok_to_fail() {
- assert!(false);
-}
-
-fn main() {}
+++ /dev/null
-error[E0658]: the `#[allow_fail]` attribute is an experimental feature
- --> $DIR/feature-gate-allow_fail.rs:3:1
- |
-LL | #[allow_fail]
- | ^^^^^^^^^^^^^
- |
- = note: see issue #46488 <https://github.com/rust-lang/rust/issues/46488> for more information
- = help: add `#![feature(allow_fail)]` to the crate attributes to enable
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.
// ignore-compare-mode-chalk
+// check-pass
#![feature(type_alias_impl_trait)]
use std::fmt::Debug;
type Foo = impl Debug;
-//~^ ERROR could not find defining uses
struct Bar(Foo);
fn define() -> Bar {
- Bar(42) //~ ERROR mismatched types
+ Bar(42)
}
type Foo2 = impl Debug;
}
type Foo3 = impl Debug;
-//~^ ERROR could not find defining uses
fn define3(x: Foo3) {
- let y: i32 = x; //~ ERROR mismatched types
+ let y: i32 = x;
}
fn define3_1() {
- define3(42) //~ ERROR mismatched types
+ define3(42)
}
type Foo4 = impl Debug;
-//~^ ERROR could not find defining uses
fn define4() {
let y: Foo4 = 42;
- //~^ ERROR mismatched types [E0308]
}
fn main() {}
+++ /dev/null
-error[E0308]: mismatched types
- --> $DIR/feature-gate-type_alias_impl_trait.rs:10:9
- |
-LL | type Foo = impl Debug;
- | ---------- the expected opaque type
-...
-LL | Bar(42)
- | ^^ expected opaque type, found integer
- |
- = note: expected opaque type `impl Debug`
- found type `{integer}`
-
-error[E0308]: mismatched types
- --> $DIR/feature-gate-type_alias_impl_trait.rs:23:18
- |
-LL | type Foo3 = impl Debug;
- | ---------- the found opaque type
-...
-LL | let y: i32 = x;
- | --- ^ expected `i32`, found opaque type
- | |
- | expected due to this
- |
- = note: expected type `i32`
- found opaque type `impl Debug`
-
-error[E0308]: mismatched types
- --> $DIR/feature-gate-type_alias_impl_trait.rs:26:13
- |
-LL | type Foo3 = impl Debug;
- | ---------- the expected opaque type
-...
-LL | define3(42)
- | ^^ expected opaque type, found integer
- |
- = note: expected opaque type `impl Debug`
- found type `{integer}`
-
-error[E0308]: mismatched types
- --> $DIR/feature-gate-type_alias_impl_trait.rs:33:19
- |
-LL | type Foo4 = impl Debug;
- | ---------- the expected opaque type
-...
-LL | let y: Foo4 = 42;
- | ---- ^^ expected opaque type, found integer
- | |
- | expected due to this
- |
- = note: expected opaque type `impl Debug`
- found type `{integer}`
-
-error: could not find defining uses
- --> $DIR/feature-gate-type_alias_impl_trait.rs:5:12
- |
-LL | type Foo = impl Debug;
- | ^^^^^^^^^^
-
-error: could not find defining uses
- --> $DIR/feature-gate-type_alias_impl_trait.rs:19:13
- |
-LL | type Foo3 = impl Debug;
- | ^^^^^^^^^^
-
-error: could not find defining uses
- --> $DIR/feature-gate-type_alias_impl_trait.rs:29:13
- |
-LL | type Foo4 = impl Debug;
- | ^^^^^^^^^^
-
-error: aborting due to 7 previous errors
-
-For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+fn main() {
+ let a = "a";
+ let b = "b";
+
+ println!("{a} {b} {} {} {c} {}", c = "c");
+ //~^ ERROR: invalid reference to positional arguments 1 and 2 (there is 1 argument)
+
+ let n = 1;
+ println!("{a:.n$} {b:.*}");
+ //~^ ERROR: invalid reference to positional argument 0 (no arguments were given)
+}
--- /dev/null
+error: invalid reference to positional arguments 1 and 2 (there is 1 argument)
+ --> $DIR/format-args-capture-issue-93378.rs:5:26
+ |
+LL | println!("{a} {b} {} {} {c} {}", c = "c");
+ | ^^ ^^
+ |
+ = note: positional arguments are zero-based
+
+error: invalid reference to positional argument 0 (no arguments were given)
+ --> $DIR/format-args-capture-issue-93378.rs:9:23
+ |
+LL | println!("{a:.n$} {b:.*}");
+ | ------- ^^^--^
+ | | |
+ | | this precision flag adds an extra required argument at position 0, which is why there are 3 arguments expected
+ | this parameter corresponds to the precision flag
+ |
+ = note: positional arguments are zero-based
+ = note: for information about formatting flags, visit https://doc.rust-lang.org/std/fmt/index.html
+
+error: aborting due to 2 previous errors
+
named_argument_takes_precedence_to_captured();
formatting_parameters_can_be_captured();
capture_raw_strings_and_idents();
+ repeated_capture();
#[cfg(panic = "unwind")]
{
let s = format!("{x:-^width$.precision$}");
assert_eq!(&s, "--7.000--");
}
+
+fn repeated_capture() {
+ let a = 1;
+ let b = 2;
+ let s = format!("{a} {b} {a}");
+ assert_eq!(&s, "1 2 1");
+}
use std::ops::Generator;
fn foo(bar: bool) -> impl Generator<(bool,)> {
-//~^ ERROR: type mismatch in generator arguments [E0631]
-//~| NOTE: expected signature of `fn((bool,)) -> _`
|bar| {
//~^ NOTE: found signature of `fn(bool) -> _`
+ //~| ERROR: type mismatch in generator arguments [E0631]
+ //~| NOTE: expected signature of `fn((bool,)) -> _`
if bar {
yield bar;
}
error[E0631]: type mismatch in generator arguments
- --> $DIR/issue-88653.rs:8:22
+ --> $DIR/issue-88653.rs:9:5
|
-LL | fn foo(bar: bool) -> impl Generator<(bool,)> {
- | ^^^^^^^^^^^^^^^^^^^^^^^ expected signature of `fn((bool,)) -> _`
-...
LL | |bar| {
- | ----- found signature of `fn(bool) -> _`
+ | ^^^^^
+ | |
+ | expected signature of `fn((bool,)) -> _`
+ | found signature of `fn(bool) -> _`
error: aborting due to previous error
use std::ops::Generator;
-fn foo() -> impl Generator<Return = i32> { //~ ERROR type mismatch
- || {
+fn foo() -> impl Generator<Return = i32> {
+ || { //~ ERROR type mismatch
if false {
return Ok(6);
}
| ^^^^^
error[E0271]: type mismatch resolving `<[generator@$DIR/type-mismatch-signature-deduction.rs:6:5: 14:6] as Generator>::Return == i32`
- --> $DIR/type-mismatch-signature-deduction.rs:5:13
+ --> $DIR/type-mismatch-signature-deduction.rs:6:5
|
-LL | fn foo() -> impl Generator<Return = i32> {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found enum `Result`
+LL | / || {
+LL | | if false {
+LL | | return Ok(6);
+LL | | }
+... |
+LL | | 5
+LL | | }
+ | |_____^ expected enum `Result`, found `i32`
|
- = note: expected type `i32`
- found enum `Result<{integer}, _>`
+ = note: expected enum `Result<{integer}, _>`
+ found type `i32`
error: aborting due to 2 previous errors
impl<'c, S: Trait2> Trait2 for &'c mut S {
type FooFuture<'a> = impl Trait1;
- fn foo<'a>() -> Self::FooFuture<'a> { //~ ERROR
+ //~^ ERROR unconstrained opaque type
+ fn foo<'a>() -> Self::FooFuture<'a> {
Struct(unimplemented!())
}
}
-error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
- --> $DIR/issue-87258_a.rs:19:21
+error: unconstrained opaque type
+ --> $DIR/issue-87258_a.rs:18:26
|
-LL | fn foo<'a>() -> Self::FooFuture<'a> {
- | ^^^^^^^^^^^^^^^^^^^
+LL | type FooFuture<'a> = impl Trait1;
+ | ^^^^^^^^^^^
|
- = note: hidden type `Struct<'_>` captures lifetime '_#7r
+ = note: `FooFuture` must be used in combination with a concrete type within the same module
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0700`.
}
type Helper<'xenon, 'yttrium, KABOOM: Trait2> = impl Trait1;
+//~^ ERROR unconstrained opaque type
impl<'c, S: Trait2> Trait2 for &'c mut S {
type FooFuture<'a> = Helper<'c, 'a, S>;
- fn foo<'a>() -> Self::FooFuture<'a> { //~ ERROR
+ fn foo<'a>() -> Self::FooFuture<'a> {
Struct(unimplemented!())
}
}
-error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
- --> $DIR/issue-87258_b.rs:21:21
+error: unconstrained opaque type
+ --> $DIR/issue-87258_b.rs:17:49
|
-LL | fn foo<'a>() -> Self::FooFuture<'a> {
- | ^^^^^^^^^^^^^^^^^^^
+LL | type Helper<'xenon, 'yttrium, KABOOM: Trait2> = impl Trait1;
+ | ^^^^^^^^^^^
|
- = note: hidden type `Struct<'_>` captures lifetime '_#7r
+ = note: `Helper` must be used in combination with a concrete type within the same module
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0700`.
impl<'a> A<'a> for C {
type B<'b> = impl Clone;
//~^ ERROR: lifetime bound not satisfied
- //~| ERROR: could not find defining uses
fn a(&'a self) -> Self::B<'a> {} //~ ERROR: non-defining opaque type use in defining scope
}
| ^^
error: non-defining opaque type use in defining scope
- --> $DIR/issue-88595.rs:23:23
+ --> $DIR/issue-88595.rs:22:35
|
LL | fn a(&'a self) -> Self::B<'a> {}
- | ^^^^^^^^^^^
+ | ^^
|
note: lifetime used multiple times
--> $DIR/issue-88595.rs:18:6
LL | type B<'b> = impl Clone;
| ^^
-error: could not find defining uses
- --> $DIR/issue-88595.rs:19:18
- |
-LL | type B<'b> = impl Clone;
- | ^^^^^^^^^^
-
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0478`.
error[E0311]: the parameter type `C` may not live long enough
- --> $DIR/issue-92096.rs:20:33
+ --> $DIR/issue-92096.rs:24:5
|
LL | fn call_connect<C>(c: &'_ C) -> impl '_ + Future + Send
- | - ^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `C` will meet its required lifetime bounds
- | |
- | help: consider adding an explicit lifetime bound...: `C: 'a`
+ | - help: consider adding an explicit lifetime bound...: `C: 'a`
+...
+LL | async move { c.connect().await }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `C` will meet its required lifetime bounds
error[E0311]: the parameter type `C` may not live long enough
- --> $DIR/issue-92096.rs:20:33
+ --> $DIR/issue-92096.rs:24:5
|
LL | fn call_connect<C>(c: &'_ C) -> impl '_ + Future + Send
- | - ^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `C` will meet its required lifetime bounds
- | |
- | help: consider adding an explicit lifetime bound...: `C: 'a`
+ | - help: consider adding an explicit lifetime bound...: `C: 'a`
+...
+LL | async move { c.connect().await }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `C` will meet its required lifetime bounds
error: aborting due to 2 previous errors
}
fn call_connect<C>(c: &'_ C) -> impl '_ + Future + Send
-//[migrate]~^ ERROR the parameter
-//[migrate]~| ERROR the parameter
where
C: Client + Send + Sync,
{
async move { c.connect().await }
+ //[migrate]~^ ERROR the parameter
+ //[migrate]~| ERROR the parameter
}
fn main() {}
// return type, which can't depend on the obligation.
fn cycle1() -> impl Clone {
//~^ ERROR cycle detected
+ //~| ERROR cycle detected
send(cycle2().clone());
Rc::new(Cell::new(5))
LL | fn cycle1() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires type-checking `cycle1`...
- --> $DIR/auto-trait-leak.rs:14:5
+ --> $DIR/auto-trait-leak.rs:12:1
+ |
+LL | fn cycle1() -> impl Clone {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires computing type of `cycle2::{opaque#0}`...
+ --> $DIR/auto-trait-leak.rs:20:16
+ |
+LL | fn cycle2() -> impl Clone {
+ | ^^^^^^^^^^
+note: ...which requires borrow-checking `cycle2`...
+ --> $DIR/auto-trait-leak.rs:20:1
+ |
+LL | fn cycle2() -> impl Clone {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires processing `cycle2`...
+ --> $DIR/auto-trait-leak.rs:20:1
+ |
+LL | fn cycle2() -> impl Clone {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires processing MIR for `cycle2`...
+ --> $DIR/auto-trait-leak.rs:20:1
+ |
+LL | fn cycle2() -> impl Clone {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires unsafety-checking `cycle2`...
+ --> $DIR/auto-trait-leak.rs:20:1
+ |
+LL | fn cycle2() -> impl Clone {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires building MIR for `cycle2`...
+ --> $DIR/auto-trait-leak.rs:20:1
+ |
+LL | fn cycle2() -> impl Clone {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires type-checking `cycle2`...
+ --> $DIR/auto-trait-leak.rs:20:1
+ |
+LL | fn cycle2() -> impl Clone {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+ = note: ...which again requires computing type of `cycle1::{opaque#0}`, completing the cycle
+note: cycle used when checking item types in top-level module
+ --> $DIR/auto-trait-leak.rs:1:1
+ |
+LL | / use std::cell::Cell;
+LL | | use std::rc::Rc;
+LL | |
+LL | | fn send<T: Send>(_: T) {}
+... |
+LL | | Rc::new(String::from("foo"))
+LL | | }
+ | |_^
+
+error[E0391]: cycle detected when computing type of `cycle1::{opaque#0}`
+ --> $DIR/auto-trait-leak.rs:12:16
|
-LL | send(cycle2().clone());
- | ^^^^
- = note: ...which requires evaluating trait selection obligation `impl core::clone::Clone: core::marker::Send`...
+LL | fn cycle1() -> impl Clone {
+ | ^^^^^^^^^^
+ |
+note: ...which requires borrow-checking `cycle1`...
+ --> $DIR/auto-trait-leak.rs:12:1
+ |
+LL | fn cycle1() -> impl Clone {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires processing `cycle1`...
+ --> $DIR/auto-trait-leak.rs:12:1
+ |
+LL | fn cycle1() -> impl Clone {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires processing MIR for `cycle1`...
+ --> $DIR/auto-trait-leak.rs:12:1
+ |
+LL | fn cycle1() -> impl Clone {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires unsafety-checking `cycle1`...
+ --> $DIR/auto-trait-leak.rs:12:1
+ |
+LL | fn cycle1() -> impl Clone {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires building MIR for `cycle1`...
+ --> $DIR/auto-trait-leak.rs:12:1
+ |
+LL | fn cycle1() -> impl Clone {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires type-checking `cycle1`...
+ --> $DIR/auto-trait-leak.rs:12:1
+ |
+LL | fn cycle1() -> impl Clone {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires computing type of `cycle2::{opaque#0}`...
- --> $DIR/auto-trait-leak.rs:19:16
+ --> $DIR/auto-trait-leak.rs:20:16
|
LL | fn cycle2() -> impl Clone {
| ^^^^^^^^^^
note: ...which requires borrow-checking `cycle2`...
- --> $DIR/auto-trait-leak.rs:19:1
+ --> $DIR/auto-trait-leak.rs:20:1
|
LL | fn cycle2() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires processing `cycle2`...
- --> $DIR/auto-trait-leak.rs:19:1
+ --> $DIR/auto-trait-leak.rs:20:1
|
LL | fn cycle2() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires processing MIR for `cycle2`...
- --> $DIR/auto-trait-leak.rs:19:1
+ --> $DIR/auto-trait-leak.rs:20:1
|
LL | fn cycle2() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires unsafety-checking `cycle2`...
- --> $DIR/auto-trait-leak.rs:19:1
+ --> $DIR/auto-trait-leak.rs:20:1
|
LL | fn cycle2() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires building MIR for `cycle2`...
- --> $DIR/auto-trait-leak.rs:19:1
+ --> $DIR/auto-trait-leak.rs:20:1
|
LL | fn cycle2() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires type-checking `cycle2`...
- --> $DIR/auto-trait-leak.rs:20:5
+ --> $DIR/auto-trait-leak.rs:20:1
|
-LL | send(cycle1().clone());
- | ^^^^
- = note: ...which requires evaluating trait selection obligation `impl core::clone::Clone: core::marker::Send`...
+LL | fn cycle2() -> impl Clone {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
= note: ...which again requires computing type of `cycle1::{opaque#0}`, completing the cycle
note: cycle used when checking item types in top-level module
--> $DIR/auto-trait-leak.rs:1:1
LL | | }
| |_^
-error: aborting due to previous error
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0391`.
// (We treat opaque types as "foreign types" that could grow more impls
// in the future.)
impl AnotherTrait for D<OpaqueType> {
- //~^ ERROR conflicting implementations of trait `AnotherTrait` for type `D<impl OpaqueTrait>`
+ //~^ ERROR conflicting implementations of trait `AnotherTrait` for type `D<OpaqueType>`
}
fn main() {}
-error[E0119]: conflicting implementations of trait `AnotherTrait` for type `D<impl OpaqueTrait>`
+error[E0119]: conflicting implementations of trait `AnotherTrait` for type `D<OpaqueType>`
--> $DIR/auto-trait.rs:21:1
|
LL | impl<T: Send> AnotherTrait for T {}
| -------------------------------- first implementation here
...
LL | impl AnotherTrait for D<OpaqueType> {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `D<impl OpaqueTrait>`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `D<OpaqueType>`
error: aborting due to previous error
/// `T::Assoc` can't be normalized any further here.
fn foo_fail<T: Trait>() -> impl FooLike<Output = T::Assoc> {
- //~^ ERROR: type mismatch
Foo(())
+ //~^ ERROR: type mismatch
}
}
/// Missing bound constraining `Assoc`, `T::Assoc` can't be normalized further.
fn foo2_fail<'a, T: Trait<'a>>() -> impl FooLike<Output = T::Assoc> {
- //~^ ERROR: type mismatch
- //~^^ ERROR `impl Trait` return type cannot contain a projection or `Self` that references lifetimes from a parent scope
+ //~^ ERROR `impl Trait` return type cannot contain a projection or `Self` that references lifetimes from a parent scope
Foo(())
+ //~^ ERROR: type mismatch
}
}
error[E0271]: type mismatch resolving `<Foo<()> as FooLike>::Output == <T as impl_trait::Trait>::Assoc`
- --> $DIR/bound-normalization-fail.rs:25:32
+ --> $DIR/bound-normalization-fail.rs:26:9
|
-LL | fn foo_fail<T: Trait>() -> impl FooLike<Output = T::Assoc> {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type mismatch resolving `<Foo<()> as FooLike>::Output == <T as impl_trait::Trait>::Assoc`
+LL | Foo(())
+ | ^^^^^^^ type mismatch resolving `<Foo<()> as FooLike>::Output == <T as impl_trait::Trait>::Assoc`
|
-note: expected this to be `<T as impl_trait::Trait>::Assoc`
+note: expected this to be `()`
--> $DIR/bound-normalization-fail.rs:14:19
|
LL | type Output = T;
| ^
- = note: expected associated type `<T as impl_trait::Trait>::Assoc`
- found unit type `()`
+ = note: expected unit type `()`
+ found associated type `<T as impl_trait::Trait>::Assoc`
help: consider constraining the associated type `<T as impl_trait::Trait>::Assoc` to `()`
|
LL | fn foo_fail<T: Trait<Assoc = ()>>() -> impl FooLike<Output = T::Assoc> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0271]: type mismatch resolving `<Foo<()> as FooLike>::Output == <T as lifetimes::Trait<'static>>::Assoc`
- --> $DIR/bound-normalization-fail.rs:41:41
+ --> $DIR/bound-normalization-fail.rs:43:9
|
-LL | fn foo2_fail<'a, T: Trait<'a>>() -> impl FooLike<Output = T::Assoc> {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type mismatch resolving `<Foo<()> as FooLike>::Output == <T as lifetimes::Trait<'static>>::Assoc`
+LL | Foo(())
+ | ^^^^^^^ type mismatch resolving `<Foo<()> as FooLike>::Output == <T as lifetimes::Trait<'static>>::Assoc`
|
-note: expected this to be `<T as lifetimes::Trait<'static>>::Assoc`
+note: expected this to be `()`
--> $DIR/bound-normalization-fail.rs:14:19
|
LL | type Output = T;
| ^
- = note: expected associated type `<T as lifetimes::Trait<'static>>::Assoc`
- found unit type `()`
+ = note: expected unit type `()`
+ found associated type `<T as lifetimes::Trait<'static>>::Assoc`
help: consider constraining the associated type `<T as lifetimes::Trait<'static>>::Assoc` to `()`
|
LL | fn foo2_fail<'a, T: Trait<'a, Assoc = ()>>() -> impl FooLike<Output = T::Assoc> {
| may outlive borrowed value `prefix`
|
note: closure is returned here
- --> $DIR/does-not-live-long-enough.rs:5:55
+ --> $DIR/does-not-live-long-enough.rs:6:9
|
-LL | fn started_with<'a>(&'a self, prefix: &'a str) -> impl Iterator<Item=&'a str> {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | self.data.iter().filter(|s| s.starts_with(prefix)).map(|s| s.as_ref())
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: to force the closure to take ownership of `prefix` (and any other referenced variables), use the `move` keyword
|
LL | self.data.iter().filter(move |s| s.starts_with(prefix)).map(|s| s.as_ref())
//~| expected `i32`, found `u32`
}
-fn sum_to(n: u32) -> impl Foo { //~ ERROR type annotations needed
- if n == 0 {
+fn sum_to(n: u32) -> impl Foo {
+ if n == 0 { //~ ERROR type annotations needed
0
} else {
n + sum_to(n - 1)
--> $DIR/equality.rs:15:5
|
LL | fn two(x: bool) -> impl Foo {
- | -------- expected because this return type...
-LL | if x {
-LL | return 1_i32;
- | ----- ...is found to be `i32` here
-LL | }
+ | -------- the expected opaque type
+...
LL | 0_u32
| ^^^^^ expected `i32`, found `u32`
|
- = note: to return `impl Trait`, all returned values must be of the same type
- = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
- = help: if the trait `Foo` were object safe, you could return a boxed trait object
- = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
- = help: you could instead create a new `enum` with a variant for each returned type
+ = note: expected opaque type `impl Foo`
+ found type `u32`
error[E0277]: cannot add `impl Foo` to `u32`
--> $DIR/equality.rs:24:11
= help: the trait `Add<impl Foo>` is not implemented for `u32`
error[E0283]: type annotations needed
- --> $DIR/equality.rs:20:22
- |
-LL | fn sum_to(n: u32) -> impl Foo {
- | ^^^^^^^^ cannot infer type for type `{integer}`
+ --> $DIR/equality.rs:21:5
+ |
+LL | / if n == 0 {
+LL | | 0
+LL | | } else {
+LL | | n + sum_to(n - 1)
+LL | |
+LL | | }
+ | |_____^ cannot infer type for type `{integer}`
|
= note: multiple `impl`s satisfying `{integer}: ToString` found in the `alloc` crate:
- impl ToString for i8;
| -------- the found opaque type
...
LL | let _: u32 = hide(0_u32);
- | --- ^^^^^^^^^^^ expected `u32`, found opaque type
- | |
- | expected due to this
+ | ^^^^^^^^^^^ expected `u32`, found opaque type
|
= note: expected type `u32`
found opaque type `impl Foo`
--- /dev/null
+// check-pass
+
+fn take_edge_counters(
+ x: &mut Option<Vec<i32>>,
+) -> Option<impl Iterator<Item = i32>> {
+ x.take().map_or(None, |m| Some(m.into_iter()))
+}
+
+fn main() {}
// Here we are hiding `'b` making the caller believe that `&'a mut &'s T` and
// `&'a mut &'l T` are the same type.
fn hide_ref<'a, 'b, T: 'static>(x: &'a mut &'b T) -> impl Swap + 'a {
- //~^ ERROR hidden type
x
+ //~^ ERROR hidden type
}
fn dangle_ref() -> &'static [i32; 3] {
// This is different to the previous example because the concrete return type
// only has a single lifetime.
fn hide_rc_refcell<'a, 'b: 'a, T: 'static>(x: Rc<RefCell<&'b T>>) -> impl Swap + 'a {
- //~^ ERROR hidden type
x
+ //~^ ERROR hidden type
}
fn dangle_rc_refcell() -> &'static [i32; 3] {
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
- --> $DIR/hidden-lifetimes.rs:28:54
+ --> $DIR/hidden-lifetimes.rs:29:5
|
LL | fn hide_ref<'a, 'b, T: 'static>(x: &'a mut &'b T) -> impl Swap + 'a {
- | -- ^^^^^^^^^^^^^^
- | |
- | hidden type `&'a mut &'b T` captures the lifetime `'b` as defined here
+ | -- hidden type `&'a mut &'b T` captures the lifetime `'b` as defined here
+LL | x
+ | ^
|
help: to declare that the `impl Trait` captures `'b`, you can add an explicit `'b` lifetime bound
|
| ++++
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
- --> $DIR/hidden-lifetimes.rs:45:70
+ --> $DIR/hidden-lifetimes.rs:46:5
|
LL | fn hide_rc_refcell<'a, 'b: 'a, T: 'static>(x: Rc<RefCell<&'b T>>) -> impl Swap + 'a {
- | -- ^^^^^^^^^^^^^^
- | |
- | hidden type `Rc<RefCell<&'b T>>` captures the lifetime `'b` as defined here
+ | -- hidden type `Rc<RefCell<&'b T>>` captures the lifetime `'b` as defined here
+LL | x
+ | ^
|
help: to declare that the `impl Trait` captures `'b`, you can add an explicit `'b` lifetime bound
|
type E = impl Copy;
fn foo<T: Default>() -> Self::E {
- //~^ ERROR type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias
- //~| ERROR impl has stricter requirements than trait
- //~| ERROR the trait bound `S: Copy` is not satisfied in `(S, T)` [E0277]
- //~| ERROR the trait bound `T: Copy` is not satisfied in `(S, T)` [E0277]
+ //~^ ERROR impl has stricter requirements than trait
(S::default(), T::default())
+ //~^ ERROR the trait bound `S: Copy` is not satisfied in `(S, T)` [E0277]
+ //~| ERROR the trait bound `T: Copy` is not satisfied in `(S, T)` [E0277]
}
}
| ^^^^^^^ impl has extra requirement `T: Default`
error[E0277]: the trait bound `S: Copy` is not satisfied in `(S, T)`
- --> $DIR/issue-55872-1.rs:12:29
+ --> $DIR/issue-55872-1.rs:14:9
|
-LL | fn foo<T: Default>() -> Self::E {
- | ^^^^^^^ within `(S, T)`, the trait `Copy` is not implemented for `S`
+LL | (S::default(), T::default())
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ within `(S, T)`, the trait `Copy` is not implemented for `S`
|
= note: required because it appears within the type `(S, T)`
help: consider further restricting this bound
| +++++++++++++++++++
error[E0277]: the trait bound `T: Copy` is not satisfied in `(S, T)`
- --> $DIR/issue-55872-1.rs:12:29
+ --> $DIR/issue-55872-1.rs:14:9
|
-LL | fn foo<T: Default>() -> Self::E {
- | ^^^^^^^ within `(S, T)`, the trait `Copy` is not implemented for `T`
+LL | (S::default(), T::default())
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ within `(S, T)`, the trait `Copy` is not implemented for `T`
|
= note: required because it appears within the type `(S, T)`
help: consider further restricting this bound
LL | fn foo<T: Default + std::marker::Copy>() -> Self::E {
| +++++++++++++++++++
-error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias
- --> $DIR/issue-55872-1.rs:12:37
- |
-LL | fn foo<T: Default>() -> Self::E {
- | _____________________________________^
-LL | |
-LL | |
-LL | |
-LL | |
-LL | | (S::default(), T::default())
-LL | | }
- | |_____^
-
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
Some errors have detailed explanations: E0276, E0277.
For more information about an error, try `rustc --explain E0276`.
#![feature(type_alias_impl_trait)]
pub trait Bar {
- type E: Copy;
+ type E: Send;
fn foo<T>() -> Self::E;
}
impl<S> Bar for S {
- type E = impl std::marker::Copy;
+ type E = impl std::marker::Send;
fn foo<T>() -> Self::E {
- //~^ ERROR type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias
- //~| ERROR the trait bound `impl Future<Output = [async output]>: Copy` is not satisfied
async {}
+ //~^ ERROR type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias
}
}
-error[E0277]: the trait bound `impl Future<Output = [async output]>: Copy` is not satisfied
- --> $DIR/issue-55872-2.rs:14:20
- |
-LL | fn foo<T>() -> Self::E {
- | ^^^^^^^ the trait `Copy` is not implemented for `impl Future<Output = [async output]>`
-
error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias
- --> $DIR/issue-55872-2.rs:14:28
+ --> $DIR/issue-55872-2.rs:15:9
|
-LL | fn foo<T>() -> Self::E {
- | ____________________________^
-LL | |
-LL | |
-LL | | async {}
-LL | | }
- | |_____^
+LL | async {}
+ | ^^^^^^^^
-error: aborting due to 2 previous errors
+error: aborting due to previous error
-For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+// edition:2018
+// ignore-compare-mode-chalk
+
+#![feature(type_alias_impl_trait)]
+
+pub trait Bar {
+ type E: Copy;
+
+ fn foo<T>() -> Self::E;
+}
+
+impl<S> Bar for S {
+ type E = impl std::marker::Copy;
+ fn foo<T>() -> Self::E {
+ async {}
+ //~^ ERROR the trait bound `impl Future<Output = [async output]>: Copy` is not satisfied [E0277]
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0277]: the trait bound `impl Future<Output = [async output]>: Copy` is not satisfied
+ --> $DIR/issue-55872-3.rs:15:9
+ |
+LL | async {}
+ | ^^^^^^^^ the trait `Copy` is not implemented for `impl Future<Output = [async output]>`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
type E = impl Copy;
fn foo<T>() -> Self::E {
- //~^ ERROR type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias
|| ()
+ //~^ ERROR type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias
}
}
error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias
- --> $DIR/issue-55872.rs:13:28
+ --> $DIR/issue-55872.rs:14:9
|
-LL | fn foo<T>() -> Self::E {
- | ____________________________^
-LL | |
-LL | | || ()
-LL | | }
- | |_____^
+LL | || ()
+ | ^^^^^
error: aborting due to previous error
impl Lint {}
pub fn gather_all() -> impl Iterator<Item = Lint> {
- //~^ ERROR: cannot resolve opaque type
+ //~^ ERROR `()` is not an iterator
lint_files().flat_map(|f| gather_from_file(&f))
}
LL | fn lint_files() -> impl Iterator<Item = foo::MissingItem> {
| ^^^ use of undeclared crate or module `foo`
-error[E0720]: cannot resolve opaque type
+error[E0277]: `()` is not an iterator
--> $DIR/issue-72911.rs:7:24
|
LL | pub fn gather_all() -> impl Iterator<Item = Lint> {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^ recursive opaque type
-LL |
-LL | lint_files().flat_map(|f| gather_from_file(&f))
- | -----------------------------------------------
- | |
- | returning here with type `FlatMap<impl Iterator<Item = [type error]>, [type error], [closure@$DIR/issue-72911.rs:9:27: 9:51]>`
- | returning here with type `FlatMap<impl Iterator<Item = [type error]>, [type error], [closure@$DIR/issue-72911.rs:9:27: 9:51]>`
-...
-LL | fn gather_from_file(dir_entry: &foo::MissingItem) -> impl Iterator<Item = Lint> {
- | -------------------------- returning this opaque type `FlatMap<impl Iterator<Item = [type error]>, [type error], [closure@$DIR/issue-72911.rs:9:27: 9:51]>`
-...
-LL | fn lint_files() -> impl Iterator<Item = foo::MissingItem> {
- | -------------------------------------- returning this opaque type `FlatMap<impl Iterator<Item = [type error]>, [type error], [closure@$DIR/issue-72911.rs:9:27: 9:51]>`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ `()` is not an iterator
+ |
+ = help: the trait `Iterator` is not implemented for `()`
error: aborting due to 3 previous errors
-Some errors have detailed explanations: E0433, E0720.
-For more information about an error, try `rustc --explain E0433`.
+Some errors have detailed explanations: E0277, E0433.
+For more information about an error, try `rustc --explain E0277`.
type FooRet = impl std::fmt::Debug;
type FooItem = Box<dyn Fn(FooArg) -> FooRet>;
-type Foo = impl Iterator<Item = FooItem>; //~ ERROR: type mismatch
+type Foo = impl Iterator<Item = FooItem>;
#[repr(C)]
struct Bar(u8);
fn oof() -> impl std::fmt::Debug {
let mut bar = ham();
let func = bar.next().unwrap();
- return func(&"oof");
+ return func(&"oof"); //~ ERROR opaque type's hidden type cannot be another opaque type
}
fn main() {
-error[E0271]: type mismatch resolving `<Bar as Iterator>::Item == Box<(dyn for<'r> Fn(&'r (dyn ToString + 'r)) -> Option<String> + 'static)>`
- --> $DIR/issue-70877.rs:7:12
+error: opaque type's hidden type cannot be another opaque type from the same scope
+ --> $DIR/issue-70877.rs:31:12
|
-LL | type FooRet = impl std::fmt::Debug;
- | -------------------- the found opaque type
-...
-LL | type Foo = impl Iterator<Item = FooItem>;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type mismatch resolving `<Bar as Iterator>::Item == Box<(dyn for<'r> Fn(&'r (dyn ToString + 'r)) -> Option<String> + 'static)>`
+LL | return func(&"oof");
+ | ^^^^^^^^^^^^ one of the two opaque types used here has to be outside its defining scope
+ |
+note: opaque type whose hidden type is being assigned
+ --> $DIR/issue-70877.rs:28:13
|
-note: expected this to be `Box<(dyn for<'r> Fn(&'r (dyn ToString + 'r)) -> Option<String> + 'static)>`
- --> $DIR/issue-70877.rs:13:17
+LL | fn oof() -> impl std::fmt::Debug {
+ | ^^^^^^^^^^^^^^^^^^^^
+note: opaque type being used as hidden type
+ --> $DIR/issue-70877.rs:4:15
|
-LL | type Item = FooItem;
- | ^^^^^^^
- = note: expected struct `Box<(dyn for<'r> Fn(&'r (dyn ToString + 'r)) -> Option<String> + 'static)>`
- found struct `Box<(dyn for<'r> Fn(&'r (dyn ToString + 'r)) -> impl Debug + 'static)>`
+LL | type FooRet = impl std::fmt::Debug;
+ | ^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0271`.
async {}
}
let f: F = async { 1 };
- //~^ ERROR mismatched types [E0308]
+ //~^ ERROR `async` blocks are not allowed in constants
+ //~| ERROR destructors cannot be evaluated at compile-time
1
}],
}
-error[E0308]: mismatched types
+error[E0658]: `async` blocks are not allowed in constants
--> $DIR/issue-78722.rs:12:20
|
-LL | type F = impl core::future::Future<Output = u8>;
- | -------------------------------------- the expected opaque type
-...
LL | let f: F = async { 1 };
- | - ^^^^^^^^^^^ expected opaque type, found a different opaque type
- | |
- | expected due to this
- |
- ::: $SRC_DIR/core/src/future/mod.rs:LL:COL
+ | ^^^^^^^^^^^
|
-LL | pub const fn from_generator<T>(gen: T) -> impl Future<Output = T::Return>
- | ------------------------------- the found opaque type
+ = note: see issue #85368 <https://github.com/rust-lang/rust/issues/85368> for more information
+ = help: add `#![feature(const_async_blocks)]` to the crate attributes to enable
+
+error[E0493]: destructors cannot be evaluated at compile-time
+ --> $DIR/issue-78722.rs:12:13
|
- = note: expected opaque type `impl Future<Output = u8>`
- found opaque type `impl Future<Output = [async output]>`
- = note: distinct uses of `impl Trait` result in different opaque types
+LL | let f: F = async { 1 };
+ | ^ constants cannot evaluate destructors
+...
+LL | }],
+ | - value is dropped here
-error: aborting due to previous error
+error: aborting due to 2 previous errors
-For more information about this error, try `rustc --explain E0308`.
+Some errors have detailed explanations: E0493, E0658.
+For more information about an error, try `rustc --explain E0493`.
#![feature(unboxed_closures)]
#![feature(type_alias_impl_trait)]
+// check-pass
+
type FunType = impl Fn<()>;
-//~^ ERROR could not find defining uses
static STATIC_FN: FunType = some_fn;
-//~^ ERROR mismatched types
fn some_fn() {}
+++ /dev/null
-error[E0308]: mismatched types
- --> $DIR/issue-86201.rs:6:29
- |
-LL | type FunType = impl Fn<()>;
- | ----------- the expected opaque type
-LL |
-LL | static STATIC_FN: FunType = some_fn;
- | ^^^^^^^ expected opaque type, found fn item
- |
- = note: expected opaque type `impl Fn<()>`
- found fn item `fn() {some_fn}`
-
-error: could not find defining uses
- --> $DIR/issue-86201.rs:4:16
- |
-LL | type FunType = impl Fn<()>;
- | ^^^^^^^^^^^
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+error: higher-ranked subtype error
+ --> $DIR/issue-88236-2.rs:17:5
+ |
+LL | &()
+ | ^^^
+
+error: higher-ranked subtype error
+ --> $DIR/issue-88236-2.rs:17:5
+ |
+LL | &()
+ | ^^^
+
+error: lifetime may not live long enough
+ --> $DIR/issue-88236-2.rs:20:5
+ |
+LL | fn make_bad_impl<'b>(x: &'b ()) -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> {
+ | -- lifetime `'b` defined here
+LL | x
+ | ^ returning this value requires that `'b` must outlive `'static`
+ |
+help: to allow this `impl Trait` to capture borrowed data with lifetime `'b`, add `'b` as a bound
+ |
+LL | fn make_bad_impl<'b>(x: &'b ()) -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> + 'b {
+ | ++++
+
+error: higher-ranked subtype error
+ --> $DIR/issue-88236-2.rs:20:5
+ |
+LL | x
+ | ^
+
+error: higher-ranked subtype error
+ --> $DIR/issue-88236-2.rs:20:5
+ |
+LL | x
+ | ^
+
+error: aborting due to 5 previous errors
+
--- /dev/null
+// this used to cause stack overflows
+
+trait Hrtb<'a> {
+ type Assoc;
+}
+
+impl<'a> Hrtb<'a> for () {
+ type Assoc = ();
+}
+
+impl<'a> Hrtb<'a> for &'a () {
+ type Assoc = ();
+}
+
+fn make_impl() -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> {}
+fn make_weird_impl<'b>(x: &'b ()) -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> {
+ &() //~ ERROR implementation of `Hrtb` is not general enough
+}
+fn make_bad_impl<'b>(x: &'b ()) -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> {
+ x //~ ERROR implementation of `Hrtb` is not general enough
+}
+
+fn main() {}
--- /dev/null
+error: implementation of `Hrtb` is not general enough
+ --> $DIR/issue-88236-2.rs:17:5
+ |
+LL | &()
+ | ^^^ implementation of `Hrtb` is not general enough
+ |
+ = note: `Hrtb<'0>` would have to be implemented for the type `&()`, for any lifetime `'0`...
+ = note: ...but `Hrtb<'1>` is actually implemented for the type `&'1 ()`, for some specific lifetime `'1`
+
+error: implementation of `Hrtb` is not general enough
+ --> $DIR/issue-88236-2.rs:20:5
+ |
+LL | x
+ | ^ implementation of `Hrtb` is not general enough
+ |
+ = note: `&()` must implement `Hrtb<'0>`, for any lifetime `'0`...
+ = note: ...but `Hrtb<'_>` is actually implemented for the type `&()`
+
+error: aborting due to 2 previous errors
+
--- /dev/null
+// check-pass
+
+// this used to cause stack overflows
+
+trait Hrtb<'a> {
+ type Assoc;
+}
+
+impl<'a> Hrtb<'a> for () {
+ type Assoc = ();
+}
+
+impl<'a> Hrtb<'a> for &'a () {
+ type Assoc = ();
+}
+
+fn make_impl() -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> {}
+
+fn main() {}
--- /dev/null
+// check-pass
+
+pub fn keys<'a>(x: &'a Result<u32, u32>) -> impl std::fmt::Debug + 'a {
+ match x {
+ Ok(map) => Ok(map),
+ Err(map) => Err(map),
+ }
+}
+
+fn main() {}
type E<'a, 'b> = impl Sized;
fn foo<'a: 'b, 'b, 'c>(x: &'static i32, mut y: &'a i32) -> E<'b, 'c> {
- //~^ ERROR hidden type for `impl Trait` captures lifetime that does not appear in bounds
let v = CopyIfEq::<*mut _, *mut _>(&mut { x }, &mut y);
// This assignment requires that `x` and `y` have the same type due to the
let _: &'b i32 = *u.0;
}
u.0
+ //~^ ERROR hidden type for `impl Trait` captures lifetime that does not appear in bounds
}
fn main() {}
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
- --> $DIR/error-handling-2.rs:10:60
+ --> $DIR/error-handling-2.rs:22:5
|
LL | fn foo<'a: 'b, 'b, 'c>(x: &'static i32, mut y: &'a i32) -> E<'b, 'c> {
- | -- ^^^^^^^^^
- | |
- | hidden type `*mut &'a i32` captures the lifetime `'a` as defined here
+ | -- hidden type `*mut &'a i32` captures the lifetime `'a` as defined here
+...
+LL | u.0
+ | ^^^
error: aborting due to previous error
// by both `'a` and `'b`.
fn upper_bounds<'a, 'b, 'c, 'd, 'e>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'d, 'e>
-//~^ ERROR hidden type for `impl Trait` captures lifetime that does not appear in bounds
where
'a: 'e,
'b: 'd,
// 'a in ['d, 'e]
// ```
if condition() { a } else { b }
+ //~^ ERROR hidden type for `impl Trait` captures lifetime that does not appear in bounds
}
fn condition() -> bool {
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
- --> $DIR/ordinary-bounds-unrelated.rs:16:74
+ --> $DIR/ordinary-bounds-unrelated.rs:28:33
|
LL | fn upper_bounds<'a, 'b, 'c, 'd, 'e>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'d, 'e>
- | -- ^^^^^^^^^^^^^^^^^^
- | |
- | hidden type `Ordinary<'b>` captures the lifetime `'b` as defined here
+ | -- hidden type `Ordinary<'b>` captures the lifetime `'b` as defined here
+...
+LL | if condition() { a } else { b }
+ | ^
|
help: to declare that the `impl Trait` captures `'b`, you can add an explicit `'b` lifetime bound
|
// consider the loans for both `'a` and `'b` alive.
fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b>
-//~^ ERROR hidden type for `impl Trait` captures lifetime that does not appear in bounds
{
// We return a value:
//
//
// We are forced to pick that '0 = 'e, because only 'e is outlived by *both* 'a and 'b.
if condition() { a } else { b }
+ //~^ ERROR hidden type for `impl Trait` captures lifetime that does not appear in bounds
}
fn condition() -> bool {
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
- --> $DIR/ordinary-bounds-unsuited.rs:18:62
+ --> $DIR/ordinary-bounds-unsuited.rs:31:33
|
LL | fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b>
- | -- ^^^^^^^^^^^^^^^^^^
- | |
- | hidden type `Ordinary<'b>` captures the lifetime `'b` as defined here
+ | -- hidden type `Ordinary<'b>` captures the lifetime `'b` as defined here
+...
+LL | if condition() { a } else { b }
+ | ^
|
help: to declare that the `impl Trait` captures `'b`, you can add an explicit `'b` lifetime bound
|
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
- --> $DIR/must_outlive_least_region_or_bound.rs:3:23
+ --> $DIR/must_outlive_least_region_or_bound.rs:3:35
|
LL | fn elided(x: &i32) -> impl Copy { x }
- | ---- ^^^^^^^^^
+ | ---- ^
| |
| hidden type `&i32` captures the anonymous lifetime defined here
|
| ++++
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
- --> $DIR/must_outlive_least_region_or_bound.rs:6:32
+ --> $DIR/must_outlive_least_region_or_bound.rs:6:44
|
LL | fn explicit<'a>(x: &'a i32) -> impl Copy { x }
- | -- ^^^^^^^^^
+ | -- ^
| |
| hidden type `&'a i32` captures the lifetime `'a` as defined here
|
= help: consider replacing `'a` with `'static`
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
- --> $DIR/must_outlive_least_region_or_bound.rs:33:61
+ --> $DIR/must_outlive_least_region_or_bound.rs:34:5
|
LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32) {
- | -- ^^^^^^^^^^^^^^^^
- | |
- | hidden type `[closure@$DIR/must_outlive_least_region_or_bound.rs:35:5: 35:31]` captures the lifetime `'b` as defined here
+ | -- hidden type `[closure@$DIR/must_outlive_least_region_or_bound.rs:34:5: 34:31]` captures the lifetime `'b` as defined here
+LL | move |_| println!("{}", y)
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: to declare that the `impl Trait` captures `'b`, you can add an explicit `'b` lifetime bound
|
| ++++
error[E0310]: the parameter type `T` may not live long enough
- --> $DIR/must_outlive_least_region_or_bound.rs:38:51
+ --> $DIR/must_outlive_least_region_or_bound.rs:39:5
|
-LL | fn ty_param_wont_outlive_static<T:Debug>(x: T) -> impl Debug + 'static {
- | ^^^^^^^^^^^^^^^^^^^^
+LL | x
+ | ^
|
= help: consider adding an explicit lifetime bound `T: 'static`...
// Tests that a closure type containing 'b cannot be returned from a type where
// only 'a was expected.
fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32) {
- //~^ ERROR: captures lifetime that does not appear in bounds
move |_| println!("{}", y)
+ //~^ ERROR: captures lifetime that does not appear in bounds
}
fn ty_param_wont_outlive_static<T:Debug>(x: T) -> impl Debug + 'static {
- //~^ ERROR the parameter type `T` may not live long enough
x
+ //~^ ERROR the parameter type `T` may not live long enough
}
fn main() {}
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
- --> $DIR/must_outlive_least_region_or_bound.rs:3:23
+ --> $DIR/must_outlive_least_region_or_bound.rs:3:35
|
LL | fn elided(x: &i32) -> impl Copy { x }
- | ---- ^^^^^^^^^
+ | ---- ^
| |
| hidden type `&i32` captures the anonymous lifetime defined here
|
| ++++
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
- --> $DIR/must_outlive_least_region_or_bound.rs:6:32
+ --> $DIR/must_outlive_least_region_or_bound.rs:6:44
|
LL | fn explicit<'a>(x: &'a i32) -> impl Copy { x }
- | -- ^^^^^^^^^
+ | -- ^
| |
| hidden type `&'a i32` captures the lifetime `'a` as defined here
|
--> $DIR/must_outlive_least_region_or_bound.rs:9:46
|
LL | fn elided2(x: &i32) -> impl Copy + 'static { x }
- | ---- ^ ...is used here...
+ | ---- ^ ...is used and required to live as long as `'static` here
| |
| this data with an anonymous lifetime `'_`...
|
-note: ...and is required to live as long as `'static` here
- --> $DIR/must_outlive_least_region_or_bound.rs:9:24
- |
-LL | fn elided2(x: &i32) -> impl Copy + 'static { x }
- | ^^^^^^^^^^^^^^^^^^^
help: consider changing the `impl Trait`'s explicit `'static` bound to the lifetime of argument `x`
|
LL | fn elided2(x: &i32) -> impl Copy + '_ { x }
--> $DIR/must_outlive_least_region_or_bound.rs:11:55
|
LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x }
- | ------- ^ ...is used here...
+ | ------- ^ ...is used and required to live as long as `'static` here
| |
| this data with lifetime `'a`...
|
-note: ...and is required to live as long as `'static` here
- --> $DIR/must_outlive_least_region_or_bound.rs:11:33
- |
-LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x }
- | ^^^^^^^^^^^^^^^^^^^
help: consider changing the `impl Trait`'s explicit `'static` bound to the lifetime of argument `x`
|
LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'a { x }
| ~~~~~~~~~~~~
error[E0621]: explicit lifetime required in the type of `x`
- --> $DIR/must_outlive_least_region_or_bound.rs:13:24
+ --> $DIR/must_outlive_least_region_or_bound.rs:13:41
|
LL | fn foo<'a>(x: &i32) -> impl Copy + 'a { x }
- | ---- ^^^^^^^^^^^^^^ lifetime `'a` required
+ | ---- ^ lifetime `'a` required
| |
| help: add explicit lifetime `'a` to the type of `x`: `&'a i32`
--> $DIR/must_outlive_least_region_or_bound.rs:29:69
|
LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x }
- | ------- this data with lifetime `'a`... ^ ...is used here...
- |
-note: ...and is required to live as long as `'static` here
- --> $DIR/must_outlive_least_region_or_bound.rs:29:34
+ | ------- this data with lifetime `'a`... ^ ...is used and required to live as long as `'static` here
|
-LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: consider changing the `impl Trait`'s explicit `'static` bound to the lifetime of argument `x`
|
LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'a { x }
| ~~~~~~~~~~~~
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
- --> $DIR/must_outlive_least_region_or_bound.rs:33:61
+ --> $DIR/must_outlive_least_region_or_bound.rs:34:5
|
LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32) {
- | -- ^^^^^^^^^^^^^^^^
- | |
- | hidden type `[closure@$DIR/must_outlive_least_region_or_bound.rs:35:5: 35:31]` captures the lifetime `'b` as defined here
+ | -- hidden type `[closure@$DIR/must_outlive_least_region_or_bound.rs:34:5: 34:31]` captures the lifetime `'b` as defined here
+LL | move |_| println!("{}", y)
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: to declare that the `impl Trait` captures `'b`, you can add an explicit `'b` lifetime bound
|
| ++++
error[E0310]: the parameter type `T` may not live long enough
- --> $DIR/must_outlive_least_region_or_bound.rs:38:51
+ --> $DIR/must_outlive_least_region_or_bound.rs:39:5
|
LL | fn ty_param_wont_outlive_static<T:Debug>(x: T) -> impl Debug + 'static {
- | -- ^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
- | |
- | help: consider adding an explicit lifetime bound...: `T: 'static +`
+ | -- help: consider adding an explicit lifetime bound...: `T: 'static +`
+LL | x
+ | ^ ...so that the type `T` will meet its required lifetime bounds
error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
--> $DIR/must_outlive_least_region_or_bound.rs:16:50
// This is in error, because we cannot assume that `OpaqueType: !Debug`
impl AnotherTrait for D<OpaqueType> {
- //~^ ERROR conflicting implementations of trait `AnotherTrait` for type `D<impl OpaqueTrait>`
+ //~^ ERROR conflicting implementations of trait `AnotherTrait` for type `D<OpaqueType>`
}
fn main() {}
-error[E0119]: conflicting implementations of trait `AnotherTrait` for type `D<impl OpaqueTrait>`
+error[E0119]: conflicting implementations of trait `AnotherTrait` for type `D<OpaqueType>`
--> $DIR/negative-reasoning.rs:19:1
|
LL | impl<T: std::fmt::Debug> AnotherTrait for T {}
| ------------------------------------------- first implementation here
...
LL | impl AnotherTrait for D<OpaqueType> {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `D<impl OpaqueTrait>`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `D<OpaqueType>`
|
- = note: upstream crates may add a new impl of trait `std::fmt::Debug` for type `impl OpaqueTrait` in future versions
+ = note: upstream crates may add a new impl of trait `std::fmt::Debug` for type `OpaqueType` in future versions
error: aborting due to previous error
fn bad_in_ret_position(x: impl Into<u32>) -> impl Into<impl Debug> { x }
//~^ ERROR nested `impl Trait` is not allowed
+//~| ERROR `impl Into<u32>` doesn't implement `Debug`
fn bad_in_fn_syntax(x: fn() -> impl Into<impl Debug>) {}
//~^ ERROR nested `impl Trait` is not allowed
impl X {
fn bad(x: impl Into<u32>) -> impl Into<impl Debug> { x }
//~^ ERROR nested `impl Trait` is not allowed
+ //~| ERROR `impl Into<u32>` doesn't implement `Debug`
}
fn allowed_in_assoc_type() -> impl Iterator<Item=impl Fn()> {
| outer `impl Trait`
error[E0666]: nested `impl Trait` is not allowed
- --> $DIR/nested_impl_trait.rs:8:42
+ --> $DIR/nested_impl_trait.rs:9:42
|
LL | fn bad_in_fn_syntax(x: fn() -> impl Into<impl Debug>) {}
| ----------^^^^^^^^^^-
| outer `impl Trait`
error[E0666]: nested `impl Trait` is not allowed
- --> $DIR/nested_impl_trait.rs:12:37
+ --> $DIR/nested_impl_trait.rs:13:37
|
LL | fn bad_in_arg_position(_: impl Into<impl Debug>) { }
| ----------^^^^^^^^^^-
| outer `impl Trait`
error[E0666]: nested `impl Trait` is not allowed
- --> $DIR/nested_impl_trait.rs:17:44
+ --> $DIR/nested_impl_trait.rs:18:44
|
LL | fn bad(x: impl Into<u32>) -> impl Into<impl Debug> { x }
| ----------^^^^^^^^^^-
| outer `impl Trait`
error[E0562]: `impl Trait` not allowed outside of function and method return types
- --> $DIR/nested_impl_trait.rs:8:32
+ --> $DIR/nested_impl_trait.rs:9:32
|
LL | fn bad_in_fn_syntax(x: fn() -> impl Into<impl Debug>) {}
| ^^^^^^^^^^^^^^^^^^^^^
error[E0562]: `impl Trait` not allowed outside of function and method return types
- --> $DIR/nested_impl_trait.rs:25:42
+ --> $DIR/nested_impl_trait.rs:27:42
|
LL | fn allowed_in_ret_type() -> impl Fn() -> impl Into<u32> {
| ^^^^^^^^^^^^^^
-error: aborting due to 6 previous errors
+error[E0277]: `impl Into<u32>` doesn't implement `Debug`
+ --> $DIR/nested_impl_trait.rs:5:70
+ |
+LL | fn bad_in_ret_position(x: impl Into<u32>) -> impl Into<impl Debug> { x }
+ | ^ `impl Into<u32>` cannot be formatted using `{:?}` because it doesn't implement `Debug`
+ |
+help: consider further restricting this bound
+ |
+LL | fn bad_in_ret_position(x: impl Into<u32> + std::fmt::Debug) -> impl Into<impl Debug> { x }
+ | +++++++++++++++++
+
+error[E0277]: `impl Into<u32>` doesn't implement `Debug`
+ --> $DIR/nested_impl_trait.rs:18:58
+ |
+LL | fn bad(x: impl Into<u32>) -> impl Into<impl Debug> { x }
+ | ^ `impl Into<u32>` cannot be formatted using `{:?}` because it doesn't implement `Debug`
+ |
+help: consider further restricting this bound
+ |
+LL | fn bad(x: impl Into<u32> + std::fmt::Debug) -> impl Into<impl Debug> { x }
+ | +++++++++++++++++
+
+error: aborting due to 8 previous errors
-Some errors have detailed explanations: E0562, E0666.
-For more information about an error, try `rustc --explain E0562`.
+Some errors have detailed explanations: E0277, E0562, E0666.
+For more information about an error, try `rustc --explain E0277`.
--> $DIR/object-unsafe-trait-in-return-position-impl-trait.rs:36:5
|
LL | fn can() -> impl NotObjectSafe {
- | ------------------ expected because this return type...
-LL | if true {
-LL | return A;
- | - ...is found to be `A` here
-LL | }
+ | ------------------ the expected opaque type
+...
LL | B
| ^ expected struct `A`, found struct `B`
|
- = note: to return `impl Trait`, all returned values must be of the same type
- = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
- = help: if the trait `NotObjectSafe` were object safe, you could return a boxed trait object
- = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
- = help: you could instead create a new `enum` with a variant for each returned type
+ = note: expected opaque type `impl NotObjectSafe`
+ found struct `B`
error[E0308]: mismatched types
--> $DIR/object-unsafe-trait-in-return-position-impl-trait.rs:43:5
|
LL | fn cat() -> impl ObjectSafe {
- | --------------- expected because this return type...
-LL | if true {
-LL | return A;
- | - ...is found to be `A` here
-LL | }
+ | --------------- the expected opaque type
+...
LL | B
| ^ expected struct `A`, found struct `B`
|
- = note: to return `impl Trait`, all returned values must be of the same type
- = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
- = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
- = help: you could instead create a new `enum` with a variant for each returned type
-help: you could change the return type to be a boxed trait object
- |
-LL | fn cat() -> Box<dyn ObjectSafe> {
- | ~~~~~~~ +
-help: if you change the return type to expect trait objects, box the returned expressions
- |
-LL ~ return Box::new(A);
-LL | }
-LL ~ Box::new(B)
- |
+ = note: expected opaque type `impl ObjectSafe`
+ found struct `B`
error: aborting due to 2 previous errors
}
fn baz() -> impl std::fmt::Display {
- if false {
+ if false { //~ ERROR mismatched types
return 0i32;
} else {
- 1u32 //~ ERROR mismatched types
+ 1u32
}
}
}
fn bat() -> impl std::fmt::Display {
- match 13 {
+ match 13 { //~ ERROR mismatched types
0 => return 0i32,
- _ => 1u32, //~ ERROR mismatched types
+ _ => 1u32,
}
}
}
fn cat() -> impl std::fmt::Display {
- match 13 {
+ match 13 { //~ ERROR mismatched types
0 => {
return 0i32;
}
_ => {
- 1u32 //~ ERROR mismatched types
+ 1u32
}
}
}
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:5:5
|
LL | fn foo() -> impl std::fmt::Display {
- | ---------------------- expected because this return type...
-LL | if false {
-LL | return 0i32;
- | ---- ...is found to be `i32` here
-LL | }
+ | ---------------------- the expected opaque type
+...
LL | 1u32
| ^^^^ expected `i32`, found `u32`
|
- = note: to return `impl Trait`, all returned values must be of the same type
- = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
- = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
- = help: you could instead create a new `enum` with a variant for each returned type
-help: you could change the return type to be a boxed trait object
- |
-LL | fn foo() -> Box<dyn std::fmt::Display> {
- | ~~~~~~~ +
-help: if you change the return type to expect trait objects, box the returned expressions
- |
-LL ~ return Box::new(0i32);
-LL | }
-LL ~ Box::new(1u32)
- |
+ = note: expected opaque type `impl std::fmt::Display`
+ found type `u32`
error[E0308]: mismatched types
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:12:16
|
LL | fn bar() -> impl std::fmt::Display {
- | ---------------------- expected because this return type...
-LL | if false {
-LL | return 0i32;
- | ---- ...is found to be `i32` here
-LL | } else {
+ | ---------------------- the expected opaque type
+...
LL | return 1u32;
| ^^^^ expected `i32`, found `u32`
|
- = note: to return `impl Trait`, all returned values must be of the same type
- = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
- = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
- = help: you could instead create a new `enum` with a variant for each returned type
-help: you could change the return type to be a boxed trait object
- |
-LL | fn bar() -> Box<dyn std::fmt::Display> {
- | ~~~~~~~ +
-help: if you change the return type to expect trait objects, box the returned expressions
- |
-LL ~ return Box::new(0i32);
-LL | } else {
-LL ~ return Box::new(1u32);
- |
+ = note: expected opaque type `impl std::fmt::Display`
+ found type `u32`
error[E0308]: mismatched types
- --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:20:9
- |
-LL | fn baz() -> impl std::fmt::Display {
- | ---------------------- expected because this return type...
-LL | if false {
-LL | return 0i32;
- | ---- ...is found to be `i32` here
-LL | } else {
-LL | 1u32
- | ^^^^ expected `i32`, found `u32`
- |
- = note: to return `impl Trait`, all returned values must be of the same type
- = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
- = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
- = help: you could instead create a new `enum` with a variant for each returned type
-help: you could change the return type to be a boxed trait object
- |
-LL | fn baz() -> Box<dyn std::fmt::Display> {
- | ~~~~~~~ +
-help: if you change the return type to expect trait objects, box the returned expressions
+ --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:17:5
|
-LL ~ return Box::new(0i32);
-LL | } else {
-LL ~ Box::new(1u32)
+LL | fn baz() -> impl std::fmt::Display {
+ | ---------------------- the expected opaque type
+LL | / if false {
+LL | | return 0i32;
+LL | | } else {
+LL | | 1u32
+LL | | }
+ | |_____^ expected `i32`, found `u32`
|
+ = note: expected opaque type `impl std::fmt::Display`
+ found type `u32`
error[E0308]: `if` and `else` have incompatible types
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:28:9
|
error[E0308]: mismatched types
- --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:35:14
- |
-LL | fn bat() -> impl std::fmt::Display {
- | ---------------------- expected because this return type...
-LL | match 13 {
-LL | 0 => return 0i32,
- | ---- ...is found to be `i32` here
-LL | _ => 1u32,
- | ^^^^ expected `i32`, found `u32`
- |
- = note: to return `impl Trait`, all returned values must be of the same type
- = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
- = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
- = help: you could instead create a new `enum` with a variant for each returned type
-help: you could change the return type to be a boxed trait object
- |
-LL | fn bat() -> Box<dyn std::fmt::Display> {
- | ~~~~~~~ +
-help: if you change the return type to expect trait objects, box the returned expressions
+ --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:33:5
|
-LL ~ 0 => return Box::new(0i32),
-LL ~ _ => Box::new(1u32),
+LL | fn bat() -> impl std::fmt::Display {
+ | ---------------------- the expected opaque type
+LL | / match 13 {
+LL | | 0 => return 0i32,
+LL | | _ => 1u32,
+LL | | }
+ | |_____^ expected `i32`, found `u32`
|
+ = note: expected opaque type `impl std::fmt::Display`
+ found type `u32`
error[E0308]: mismatched types
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:40:5
|
LL | fn can() -> impl std::fmt::Display {
- | ---------------------- expected because this return type...
+ | ---------------------- the expected opaque type
LL | / match 13 {
LL | | 0 => return 0i32,
- | | ---- ...is found to be `i32` here
LL | | 1 => 1u32,
LL | | _ => 2u32,
LL | | }
| |_____^ expected `i32`, found `u32`
|
- = note: to return `impl Trait`, all returned values must be of the same type
- = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
- = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
- = help: you could instead create a new `enum` with a variant for each returned type
-help: you could change the return type to be a boxed trait object
- |
-LL | fn can() -> Box<dyn std::fmt::Display> {
- | ~~~~~~~ +
-help: if you change the return type to expect trait objects, box the returned expressions
- |
-LL ~ Box::new(match 13 {
-LL ~ 0 => return Box::new(0i32),
-LL | 1 => 1u32,
-LL | _ => 2u32,
-LL ~ })
- |
+ = note: expected opaque type `impl std::fmt::Display`
+ found type `u32`
error[E0308]: mismatched types
- --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:53:13
+ --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:48:5
|
-LL | fn cat() -> impl std::fmt::Display {
- | ---------------------- expected because this return type...
-...
-LL | return 0i32;
- | ---- ...is found to be `i32` here
-...
-LL | 1u32
- | ^^^^ expected `i32`, found `u32`
- |
- = note: to return `impl Trait`, all returned values must be of the same type
- = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
- = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
- = help: you could instead create a new `enum` with a variant for each returned type
-help: you could change the return type to be a boxed trait object
- |
-LL | fn cat() -> Box<dyn std::fmt::Display> {
- | ~~~~~~~ +
-help: if you change the return type to expect trait objects, box the returned expressions
- |
-LL ~ return Box::new(0i32);
-LL | }
-LL | _ => {
-LL ~ Box::new(1u32)
+LL | fn cat() -> impl std::fmt::Display {
+ | ---------------------- the expected opaque type
+LL | / match 13 {
+LL | | 0 => {
+LL | | return 0i32;
+LL | | }
+... |
+LL | | }
+LL | | }
+ | |_____^ expected `i32`, found `u32`
|
+ = note: expected opaque type `impl std::fmt::Display`
+ found type `u32`
error[E0308]: `match` arms have incompatible types
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:61:14
LL | | _ => 2u32,
LL | | }
| |_____- `match` arms have incompatible types
- |
-help: you could change the return type to be a boxed trait object
- |
-LL | fn dog() -> Box<dyn std::fmt::Display> {
- | ~~~~~~~ +
-help: if you change the return type to expect trait objects, box the returned expressions
- |
-LL ~ 0 => Box::new(0i32),
-LL ~ 1 => Box::new(1u32),
- |
error[E0308]: `if` and `else` have incompatible types
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:97:9
| | ^^^^ expected `i32`, found `u32`
LL | | }
| |_____- `if` and `else` have incompatible types
- |
-help: you could change the return type to be a boxed trait object
- |
-LL | fn apt() -> Box<dyn std::fmt::Display> {
- | ~~~~~~~ +
-help: if you change the return type to expect trait objects, box the returned expressions
- |
-LL ~ Box::new(0i32)
-LL | } else {
-LL ~ Box::new(1u32)
- |
error[E0746]: return type cannot have an unboxed trait object
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:66:13
impl<T> Test for T where T: Super<Assoc = ()> {}
fn test() -> impl Test {
- //~^ERROR type mismatch resolving `<() as Super>::Assoc == ()`
()
+ //~^ERROR type mismatch resolving `<() as Super>::Assoc == ()`
}
fn main() {
error[E0271]: type mismatch resolving `<() as Super>::Assoc == ()`
- --> $DIR/projection-mismatch-in-impl-where-clause.rs:13:14
+ --> $DIR/projection-mismatch-in-impl-where-clause.rs:14:5
|
-LL | fn test() -> impl Test {
- | ^^^^^^^^^ type mismatch resolving `<() as Super>::Assoc == ()`
+LL | ()
+ | ^^ type mismatch resolving `<() as Super>::Assoc == ()`
|
-note: expected this to be `()`
+note: expected this to be `u8`
--> $DIR/projection-mismatch-in-impl-where-clause.rs:6:18
|
LL | type Assoc = u8;
--- /dev/null
+// check-pass
+
+fn foo() -> impl MyTrait {
+ panic!();
+ MyStruct
+}
+
+struct MyStruct;
+trait MyTrait {}
+
+impl MyTrait for MyStruct {}
+
+fn main() {}
-// Test that an `impl Trait` type that expands to itself is an error.
+// check-pass
#![allow(unconditional_recursion)]
fn test() -> impl Sized {
- //~^ ERROR E0720
test()
}
+++ /dev/null
-error[E0720]: cannot resolve opaque type
- --> $DIR/recursive-impl-trait-type-direct.rs:5:14
- |
-LL | fn test() -> impl Sized {
- | ^^^^^^^^^^ recursive opaque type
-LL |
-LL | test()
- | ------ returning here with type `impl Sized`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0720`.
#![allow(unconditional_recursion)]
fn option(i: i32) -> impl Sized {
- //~^ ERROR
+ //~^ ERROR cannot resolve opaque type
if i < 0 { None } else { Some((option(i - 1), i)) }
}
--- /dev/null
+#![feature(type_alias_impl_trait)]
+
+mod a {
+ type Foo = impl PartialEq<(Foo, i32)>;
+ //~^ ERROR unconstrained opaque type
+
+ struct Bar;
+
+ impl PartialEq<(Bar, i32)> for Bar {
+ fn eq(&self, _other: &(Foo, i32)) -> bool {
+ true
+ }
+ }
+}
+
+mod b {
+ type Foo = impl PartialEq<(Foo, i32)>;
+ //~^ ERROR unconstrained opaque type
+
+ struct Bar;
+
+ impl PartialEq<(Foo, i32)> for Bar {
+ fn eq(&self, _other: &(Bar, i32)) -> bool {
+ true
+ }
+ }
+}
+
+fn main() {}
--- /dev/null
+error: unconstrained opaque type
+ --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:4:16
+ |
+LL | type Foo = impl PartialEq<(Foo, i32)>;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: `Foo` must be used in combination with a concrete type within the same module
+
+error: unconstrained opaque type
+ --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:17:16
+ |
+LL | type Foo = impl PartialEq<(Foo, i32)>;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: `Foo` must be used in combination with a concrete type within the same module
+
+error: aborting due to 2 previous errors
+
--- /dev/null
+// check-pass
+
+#![feature(type_alias_impl_trait)]
+
+mod direct {
+ type Foo = impl PartialEq<(Foo, i32)>;
+
+ struct Bar;
+
+ impl PartialEq<(Foo, i32)> for Bar {
+ fn eq(&self, _other: &(Foo, i32)) -> bool {
+ true
+ }
+ }
+
+ fn foo() -> Foo {
+ Bar
+ }
+}
+
+mod indirect {
+ type Foo = impl PartialEq<(Foo, i32)>;
+
+ struct Bar;
+
+ impl PartialEq<(Bar, i32)> for Bar {
+ fn eq(&self, _other: &(Bar, i32)) -> bool {
+ true
+ }
+ }
+
+ fn foo() -> Foo {
+ Bar
+ }
+}
+
+fn main() {}
impl Trait<'b> for Cell<&'a u32> { }
fn foo(x: Cell<&'x u32>) -> impl Trait<'y>
- //~^ ERROR hidden type for `impl Trait` captures lifetime that does not appear in bounds [E0700]
where 'x: 'y
{
x
+ //~^ ERROR hidden type for `impl Trait` captures lifetime that does not appear in bounds [E0700]
}
fn main() { }
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
- --> $DIR/region-escape-via-bound.rs:15:29
+ --> $DIR/region-escape-via-bound.rs:18:5
|
-LL | fn foo(x: Cell<&'x u32>) -> impl Trait<'y>
- | ^^^^^^^^^^^^^^
-LL |
LL | where 'x: 'y
| -- hidden type `Cell<&'x u32>` captures the lifetime `'x` as defined here
+LL | {
+LL | x
+ | ^
|
help: to declare that the `impl Trait` captures `'x`, you can add an explicit `'x` lifetime bound
|
impl A {
fn iter_values_anon(&self) -> impl Iterator<Item=u32> {
+ self.x.iter().map(|a| a.0)
//~^ ERROR: captures lifetime that does not appear in bounds
//~| ERROR: captures lifetime that does not appear in bounds
- self.x.iter().map(|a| a.0)
}
fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> {
+ self.x.iter().map(|a| a.0)
//~^ ERROR: captures lifetime that does not appear in bounds
//~| ERROR: captures lifetime that does not appear in bounds
- self.x.iter().map(|a| a.0)
}
}
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
- --> $DIR/static-return-lifetime-infered.rs:6:35
+ --> $DIR/static-return-lifetime-infered.rs:7:9
|
LL | fn iter_values_anon(&self) -> impl Iterator<Item=u32> {
- | ----- ^^^^^^^^^^^^^^^^^^^^^^^
- | |
- | hidden type `Map<std::slice::Iter<'_, (u32, u32)>, [closure@$DIR/static-return-lifetime-infered.rs:9:27: 9:34]>` captures the anonymous lifetime defined here
+ | ----- hidden type `Map<std::slice::Iter<'_, (u32, u32)>, [closure@$DIR/static-return-lifetime-infered.rs:7:27: 7:34]>` captures the anonymous lifetime defined here
+LL | self.x.iter().map(|a| a.0)
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: to declare that the `impl Trait` captures `'_`, you can add an explicit `'_` lifetime bound
|
| ++++
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
- --> $DIR/static-return-lifetime-infered.rs:6:35
+ --> $DIR/static-return-lifetime-infered.rs:7:9
|
LL | fn iter_values_anon(&self) -> impl Iterator<Item=u32> {
- | ----- ^^^^^^^^^^^^^^^^^^^^^^^
- | |
- | hidden type `Map<std::slice::Iter<'_, (u32, u32)>, [closure@$DIR/static-return-lifetime-infered.rs:9:27: 9:34]>` captures the anonymous lifetime defined here
+ | ----- hidden type `Map<std::slice::Iter<'_, (u32, u32)>, [closure@$DIR/static-return-lifetime-infered.rs:7:27: 7:34]>` captures the anonymous lifetime defined here
+LL | self.x.iter().map(|a| a.0)
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: to declare that the `impl Trait` captures `'_`, you can add an explicit `'_` lifetime bound
|
| ++++
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
- --> $DIR/static-return-lifetime-infered.rs:11:37
+ --> $DIR/static-return-lifetime-infered.rs:12:9
|
LL | fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> {
- | -- ^^^^^^^^^^^^^^^^^^^^^^^
- | |
- | hidden type `Map<std::slice::Iter<'a, (u32, u32)>, [closure@$DIR/static-return-lifetime-infered.rs:14:27: 14:34]>` captures the lifetime `'a` as defined here
+ | -- hidden type `Map<std::slice::Iter<'a, (u32, u32)>, [closure@$DIR/static-return-lifetime-infered.rs:12:27: 12:34]>` captures the lifetime `'a` as defined here
+LL | self.x.iter().map(|a| a.0)
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: to declare that the `impl Trait` captures `'a`, you can add an explicit `'a` lifetime bound
|
| ++++
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
- --> $DIR/static-return-lifetime-infered.rs:11:37
+ --> $DIR/static-return-lifetime-infered.rs:12:9
|
LL | fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> {
- | -- ^^^^^^^^^^^^^^^^^^^^^^^
- | |
- | hidden type `Map<std::slice::Iter<'a, (u32, u32)>, [closure@$DIR/static-return-lifetime-infered.rs:14:27: 14:34]>` captures the lifetime `'a` as defined here
+ | -- hidden type `Map<std::slice::Iter<'a, (u32, u32)>, [closure@$DIR/static-return-lifetime-infered.rs:12:27: 12:34]>` captures the lifetime `'a` as defined here
+LL | self.x.iter().map(|a| a.0)
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: to declare that the `impl Trait` captures `'a`, you can add an explicit `'a` lifetime bound
|
--- /dev/null
+#![feature(type_alias_impl_trait)]
+
+type A = impl Foo;
+type B = impl Foo;
+
+trait Foo {}
+
+fn muh(x: A) -> B {
+ if false {
+ return Bar; // B's hidden type is Bar
+ }
+ x // A's hidden type is `Bar`, because all the hidden types of `B` are compared with each other
+ //~^ ERROR opaque type's hidden type cannot be another opaque type
+}
+
+struct Bar;
+impl Foo for Bar {}
+
+fn main() {}
--- /dev/null
+error: opaque type's hidden type cannot be another opaque type from the same scope
+ --> $DIR/two_tait_defining_each_other.rs:12:5
+ |
+LL | x // A's hidden type is `Bar`, because all the hidden types of `B` are compared with each other
+ | ^ one of the two opaque types used here has to be outside its defining scope
+ |
+note: opaque type whose hidden type is being assigned
+ --> $DIR/two_tait_defining_each_other.rs:4:10
+ |
+LL | type B = impl Foo;
+ | ^^^^^^^^
+note: opaque type being used as hidden type
+ --> $DIR/two_tait_defining_each_other.rs:3:10
+ |
+LL | type A = impl Foo;
+ | ^^^^^^^^
+
+error: aborting due to previous error
+
--- /dev/null
+#![feature(type_alias_impl_trait)]
+
+type A = impl Foo;
+type B = impl Foo;
+
+trait Foo {}
+
+fn muh(x: A) -> B {
+ x // B's hidden type is A (opaquely)
+ //~^ ERROR opaque type's hidden type cannot be another opaque type
+}
+
+struct Bar;
+impl Foo for Bar {}
+
+fn main() {}
--- /dev/null
+error: opaque type's hidden type cannot be another opaque type from the same scope
+ --> $DIR/two_tait_defining_each_other2.rs:9:5
+ |
+LL | x // B's hidden type is A (opaquely)
+ | ^ one of the two opaque types used here has to be outside its defining scope
+ |
+note: opaque type whose hidden type is being assigned
+ --> $DIR/two_tait_defining_each_other2.rs:4:10
+ |
+LL | type B = impl Foo;
+ | ^^^^^^^^
+note: opaque type being used as hidden type
+ --> $DIR/two_tait_defining_each_other2.rs:3:10
+ |
+LL | type A = impl Foo;
+ | ^^^^^^^^
+
+error: aborting due to previous error
+
--- /dev/null
+#![feature(type_alias_impl_trait)]
+
+type A = impl Foo;
+type B = impl Foo;
+
+trait Foo {}
+
+fn muh(x: A) -> B {
+ if false {
+ return x; // B's hidden type is A (opaquely)
+ //~^ ERROR opaque type's hidden type cannot be another opaque type
+ }
+ Bar // A's hidden type is `Bar`, because all the return types are compared with each other
+}
+
+struct Bar;
+impl Foo for Bar {}
+
+fn main() {}
--- /dev/null
+error: opaque type's hidden type cannot be another opaque type from the same scope
+ --> $DIR/two_tait_defining_each_other3.rs:10:16
+ |
+LL | return x; // B's hidden type is A (opaquely)
+ | ^ one of the two opaque types used here has to be outside its defining scope
+ |
+note: opaque type whose hidden type is being assigned
+ --> $DIR/two_tait_defining_each_other3.rs:4:10
+ |
+LL | type B = impl Foo;
+ | ^^^^^^^^
+note: opaque type being used as hidden type
+ --> $DIR/two_tait_defining_each_other3.rs:3:10
+ |
+LL | type A = impl Foo;
+ | ^^^^^^^^
+
+error: aborting due to previous error
+
error[E0310]: the parameter type `T` may not live long enough
- --> $DIR/type_parameters_captured.rs:7:20
+ --> $DIR/type_parameters_captured.rs:8:5
|
-LL | fn foo<T>(x: T) -> impl Any + 'static {
- | ^^^^^^^^^^^^^^^^^^
+LL | x
+ | ^
|
= help: consider adding an explicit lifetime bound `T: 'static`...
// Check that type parameters are captured and not considered 'static
fn foo<T>(x: T) -> impl Any + 'static {
- //~^ ERROR the parameter type `T` may not live long enough
x
+ //~^ ERROR the parameter type `T` may not live long enough
}
fn main() {}
error[E0310]: the parameter type `T` may not live long enough
- --> $DIR/type_parameters_captured.rs:7:20
+ --> $DIR/type_parameters_captured.rs:8:5
|
LL | fn foo<T>(x: T) -> impl Any + 'static {
- | - ^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
- | |
- | help: consider adding an explicit lifetime bound...: `T: 'static`
+ | - help: consider adding an explicit lifetime bound...: `T: 'static`
+LL | x
+ | ^ ...so that the type `T` will meet its required lifetime bounds
error: aborting due to previous error
-//! Ideally, these tests would go in `where-allowed.rs`, but we bail out
-//! too early to display them.
use std::fmt::Debug;
-// Disallowed
-fn in_adt_in_return() -> Vec<impl Debug> { panic!() } //~ ERROR cannot resolve opaque type
+// check-pass
+
+fn in_adt_in_return() -> Vec<impl Debug> { panic!() }
fn main() {}
+++ /dev/null
-error[E0720]: cannot resolve opaque type
- --> $DIR/where-allowed-2.rs:6:30
- |
-LL | fn in_adt_in_return() -> Vec<impl Debug> { panic!() }
- | ^^^^^^^^^^ -------- this returned value is of `!` type
- | |
- | cannot resolve opaque type
- |
- = help: this error will resolve once the item's body returns a concrete type
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0720`.
-// When a MULTI-character string literal is used where a char should be,
+// When a MULTI/NO-character string literal is used where a char should be,
// DO NOT suggest changing to single quotes.
fn main() {
let _: char = "foo"; //~ ERROR mismatched types
+ let _: char = ""; //~ ERROR mismatched types
}
| |
| expected due to this
-error: aborting due to previous error
+error[E0308]: mismatched types
+ --> $DIR/char-as-str-multi.rs:6:19
+ |
+LL | let _: char = "";
+ | ---- ^^ expected `char`, found `&str`
+ | |
+ | expected due to this
+
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0308`.
fn test_ref(x: &u32) -> impl std::future::Future<Output = u32> + '_ {
- *x //~^ ERROR `u32` is not a future
+ *x
+ //~^ ERROR `u32` is not a future
}
fn main() {
error[E0425]: cannot find value `u` in this scope
- --> $DIR/issues-71798.rs:6:24
+ --> $DIR/issues-71798.rs:7:24
|
LL | let _ = test_ref & u;
| ^ not found in this scope
error[E0277]: `u32` is not a future
- --> $DIR/issues-71798.rs:1:25
+ --> $DIR/issues-71798.rs:2:5
|
-LL | fn test_ref(x: &u32) -> impl std::future::Future<Output = u32> + '_ {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `u32` is not a future
+LL | *x
+ | ^^ `u32` is not a future
|
= help: the trait `Future` is not implemented for `u32`
= note: u32 must be a future or must implement `IntoFuture` to be awaited
error: requires `generator` lang_item
- --> $DIR/lang-item-missing-generator.rs:15:17
+ --> $DIR/lang-item-missing-generator.rs:15:22
|
LL | pub fn abc() -> impl FnOnce(f32) {
- | ^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^
error: aborting due to previous error
--- /dev/null
+// check-pass
+
+#![feature(gen_future, generator_trait, negative_impls, const_fn_trait_bound, const_impl_trait)]
+
+use std::ops::{Generator, GeneratorState};
+use std::task::{Poll, Context};
+use std::future::{Future};
+use std::ptr::NonNull;
+use std::pin::Pin;
+
+fn main() {}
+
+#[derive(Debug, Copy, Clone)]
+pub struct ResumeTy(NonNull<Context<'static>>);
+
+unsafe impl Send for ResumeTy {}
+
+unsafe impl Sync for ResumeTy {}
+
+pub const fn from_generator<T>(gen: T) -> impl Future<Output = T::Return>
+where
+ T: Generator<ResumeTy, Yield = ()>,
+{
+ struct GenFuture<T: Generator<ResumeTy, Yield = ()>>(T);
+
+ // We rely on the fact that async/await futures are immovable in order to create
+ // self-referential borrows in the underlying generator.
+ impl<T: Generator<ResumeTy, Yield = ()>> !Unpin for GenFuture<T> {}
+
+ impl<T: Generator<ResumeTy, Yield = ()>> Future for GenFuture<T> {
+ type Output = T::Return;
+ fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
+ // SAFETY: Safe because we're !Unpin + !Drop, and this is just a field projection.
+ let gen = unsafe { Pin::map_unchecked_mut(self, |s| &mut s.0) };
+
+ // Resume the generator, turning the `&mut Context` into a `NonNull` raw pointer. The
+ // `.await` lowering will safely cast that back to a `&mut Context`.
+ match gen.resume(ResumeTy(NonNull::from(cx).cast::<Context<'static>>())) {
+ GeneratorState::Yielded(()) => Poll::Pending,
+ GeneratorState::Complete(x) => Poll::Ready(x),
+ }
+ }
+ }
+
+ GenFuture(gen)
+}
--- /dev/null
+// check-pass
+
+fn main() {}
+
+trait Reader {}
+
+struct Unit<R>(R);
+struct ResDwarf<R>(R);
+
+struct Context<R: Reader> {
+ dwarf: ResDwarf<R>,
+}
+
+struct Range;
+
+struct ResUnit<R>(R);
+
+impl<R: Reader + 'static> Context<R> {
+ fn find_dwarf_unit(&self, probe: u64) -> Option<&Unit<R>> {
+ let x = self.find_units(probe);
+ None
+ }
+
+ fn find_units(&self, probe: u64) -> impl Iterator<Item = &ResUnit<R>> {
+ std::iter::empty()
+ }
+}
--- /dev/null
+// check-pass
+
+fn main() {}
+
+fn nth<I: Iterator>(iter: &mut I, step: usize) -> impl FnMut() -> Option<I::Item> + '_ {
+ move || iter.nth(step)
+}
--- /dev/null
+// check-pass
+
+fn main() {}
+
+struct RawTableInner<A> {
+ alloc: A,
+}
+
+impl<A> RawTableInner<A> {
+ fn prepare_resize(
+ self,
+ ) -> ScopeGuard<Self, impl FnMut(&mut Self)> {
+ ScopeGuard { dropfn: move |self_| {}, value: self, }
+ }
+}
+
+pub struct ScopeGuard<T, F>
+where
+ F: FnMut(&mut T),
+{
+ dropfn: F,
+ value: T,
+}
--- /dev/null
+// check-pass
+
+fn main() {}
+
+fn filter_fold<T, Acc, PRED: FnMut(&T) -> bool, FOLD: FnMut(Acc, T) -> Acc>(
+ mut predicate: PRED,
+ mut fold: FOLD,
+) -> impl FnMut(Acc, T) -> Acc {
+ move |acc, item| if predicate(&item) { fold(acc, item) } else { acc }
+}
--- /dev/null
+// check-pass
+
+fn main() {}
+
+pub struct PairSlices<'a, 'b, T> {
+ pub(crate) a0: &'a mut [T],
+ pub(crate) a1: &'a mut [T],
+ pub(crate) b0: &'b [T],
+ pub(crate) b1: &'b [T],
+}
+
+impl<'a, 'b, T> PairSlices<'a, 'b, T> {
+ pub fn remainder(self) -> impl Iterator<Item = &'b [T]> {
+ IntoIterator::into_iter([self.b0, self.b1])
+ }
+}
use std::error::Error;
fn foo() -> impl Future<Item=(), Error=Box<dyn Error>> {
-//~^ ERROR not satisfied
Ok(())
+ //~^ ERROR not satisfied
}
fn main() {}
error[E0277]: the trait bound `Result<(), _>: Future` is not satisfied
- --> $DIR/lifetime-elision-return-type-trait.rs:8:13
+ --> $DIR/lifetime-elision-return-type-trait.rs:9:5
|
-LL | fn foo() -> impl Future<Item=(), Error=Box<dyn Error>> {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Future` is not implemented for `Result<(), _>`
+LL | Ok(())
+ | ^^^^^^ the trait `Future` is not implemented for `Result<(), _>`
error: aborting due to previous error
type T = Self;
#[inline] //~ ERROR attribute should be applied to function or closure
- type U = impl Trait; //~ ERROR could not find defining uses
+ type U = impl Trait; //~ ERROR unconstrained opaque type
}
extern "C" {
LL | type T;
| ------- not a function or closure
-error: could not find defining uses
+error: unconstrained opaque type
--> $DIR/inline-trait-and-foreign-items.rs:26:14
|
LL | type U = impl Trait;
| ^^^^^^^^^^
+ |
+ = note: `U` must be used in combination with a concrete type within the same module
error: aborting due to 6 previous errors; 2 warnings emitted
}
extern "C" {
- pub fn lint_me() -> A<()>; //~ ERROR: uses type `impl Baz`
+ pub fn lint_me() -> A<()>; //~ ERROR: uses type `Qux`
}
fn main() {}
-error: `extern` block uses type `impl Baz`, which is not FFI-safe
+error: `extern` block uses type `Qux`, which is not FFI-safe
--> $DIR/lint-ctypes-73249-2.rs:26:25
|
LL | pub fn lint_me() -> A<()>;
}
extern "C" {
- pub fn lint_me() -> A; //~ ERROR: uses type `impl Baz`
+ pub fn lint_me() -> A; //~ ERROR: uses type `Qux`
}
fn main() {}
-error: `extern` block uses type `impl Baz`, which is not FFI-safe
+error: `extern` block uses type `Qux`, which is not FFI-safe
--> $DIR/lint-ctypes-73249-3.rs:20:25
|
LL | pub fn lint_me() -> A;
}
extern "C" {
- pub fn lint_me() -> A; //~ ERROR: uses type `impl Baz`
+ pub fn lint_me() -> A; //~ ERROR: uses type `Qux`
}
fn main() {}
-error: `extern` block uses type `impl Baz`, which is not FFI-safe
+error: `extern` block uses type `Qux`, which is not FFI-safe
--> $DIR/lint-ctypes-73249-5.rs:20:25
|
LL | pub fn lint_me() -> A;
}
extern "C" {
- pub fn lint_me() -> <u32 as Foo>::Assoc; //~ ERROR: uses type `impl Baz`
+ pub fn lint_me() -> <u32 as Foo>::Assoc; //~ ERROR: uses type `Qux`
}
fn main() {}
-error: `extern` block uses type `impl Baz`, which is not FFI-safe
+error: `extern` block uses type `Qux`, which is not FFI-safe
--> $DIR/lint-ctypes-73251-1.rs:23:25
|
LL | pub fn lint_me() -> <u32 as Foo>::Assoc;
}
extern "C" {
- pub fn lint_me() -> <AliasB as TraitB>::Assoc; //~ ERROR: uses type `impl TraitA<Assoc = u32>`
+ pub fn lint_me() -> <AliasB as TraitB>::Assoc; //~ ERROR: uses type `AliasA`
}
fn main() {}
-error: `extern` block uses type `impl TraitA<Assoc = u32>`, which is not FFI-safe
+error: `extern` block uses type `AliasA`, which is not FFI-safe
--> $DIR/lint-ctypes-73251-2.rs:36:25
|
LL | pub fn lint_me() -> <AliasB as TraitB>::Assoc;
extern "C" {
pub fn a(_: A);
- //~^ ERROR `extern` block uses type `impl Fn()`, which is not FFI-safe [improper_ctypes]
+ //~^ ERROR `extern` block uses type `A`, which is not FFI-safe [improper_ctypes]
}
fn main() {}
-error: `extern` block uses type `impl Fn()`, which is not FFI-safe
+error: `extern` block uses type `A`, which is not FFI-safe
--> $DIR/opaque-ty-ffi-unsafe.rs:11:17
|
LL | pub fn a(_: A);
trait T {}
-fn should_ret_unit() -> impl T {
- //~^ ERROR the trait bound `(): T` is not satisfied
- panic!()
+fn should_ret_unit() {
+ foo(panic!()) //~ ERROR
}
+
+fn foo(_: impl T) {}
error[E0277]: the trait bound `(): T` is not satisfied
- --> $DIR/feature-gate-never_type_fallback.rs:9:25
+ --> $DIR/feature-gate-never_type_fallback.rs:10:5
|
-LL | fn should_ret_unit() -> impl T {
- | ^^^^^^ the trait `T` is not implemented for `()`
+LL | foo(panic!())
+ | ^^^ the trait `T` is not implemented for `()`
+ |
+note: required by a bound in `foo`
+ --> $DIR/feature-gate-never_type_fallback.rs:13:16
+ |
+LL | fn foo(_: impl T) {}
+ | ^ required by this bound in `foo`
error: aborting due to previous error
--- /dev/null
+// check-pass
+
+fn main() {}
+
+trait T {}
+impl T for () {}
+
+fn should_ret_unit() -> impl T {
+ panic!()
+}
--- /dev/null
+#![feature(type_alias_impl_trait)]
+
+fn main() {}
+
+trait T {}
+impl T for i32 {}
+
+fn should_ret_unit() -> impl T {
+ //~^ ERROR `(): T` is not satisfied
+ panic!()
+}
+
+type Foo = impl T;
+
+fn a() -> Foo {
+ panic!()
+}
+
+fn b() -> Foo {
+ 42
+}
--- /dev/null
+error[E0277]: the trait bound `(): T` is not satisfied
+ --> $DIR/impl_trait_fallback2.rs:8:25
+ |
+LL | fn should_ret_unit() -> impl T {
+ | ^^^^^^ the trait `T` is not implemented for `()`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+#![feature(type_alias_impl_trait)]
+
+fn main() {}
+
+trait T {
+ type Assoc;
+}
+
+type Foo = impl T;
+//~^ ERROR unconstrained opaque type
+
+fn a() -> Foo {
+ // This is not a defining use, it doesn't actually constrain the opaque type.
+ panic!()
+}
--- /dev/null
+error: unconstrained opaque type
+ --> $DIR/impl_trait_fallback3.rs:9:12
+ |
+LL | type Foo = impl T;
+ | ^^^^^^
+ |
+ = note: `Foo` must be used in combination with a concrete type within the same module
+
+error: aborting due to previous error
+
--- /dev/null
+#![feature(type_alias_impl_trait)]
+
+trait T {
+ type Assoc: Cake;
+}
+
+trait Cake: std::fmt::Display {
+ fn cake() -> Self;
+}
+
+type Foo = impl T;
+
+fn foo() -> impl T {
+ //~^ ERROR `(): T` is not satisfied
+ panic!()
+}
+
+fn a() -> Foo {
+ foo()
+}
+
+fn main() {
+ println!("{}", <Foo as T>::Assoc::cake());
+}
--- /dev/null
+error[E0277]: the trait bound `(): T` is not satisfied
+ --> $DIR/impl_trait_fallback4.rs:13:13
+ |
+LL | fn foo() -> impl T {
+ | ^^^^^^ the trait `T` is not implemented for `()`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
fn produce_err<'a, 'b: 'a>(data: &'b mut Vec<&'b u32>, value: &'a u32) -> impl Bazinga + 'b {
let x = move || {
let value: &'a u32 = value;
- data.push(value);
+ data.push(value); //~ ERROR lifetime may not live long enough
};
- x //~ ERROR lifetime may not live long enough
+ x
}
fn main() {}
error: lifetime may not live long enough
- --> $DIR/issue-52113.rs:34:5
+ --> $DIR/issue-52113.rs:32:9
|
LL | fn produce_err<'a, 'b: 'a>(data: &'b mut Vec<&'b u32>, value: &'a u32) -> impl Bazinga + 'b {
| -- -- lifetime `'b` defined here
| |
| lifetime `'a` defined here
...
-LL | x
- | ^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
+LL | data.push(value);
+ | ^^^^^^^^^^^^^^^^ argument requires that `'a` must outlive `'b`
|
= help: consider adding the following bound: `'a: 'b`
LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
+ = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
= help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
error: aborting due to previous error
impl<'a> Foo<'a> {
fn make_it(&self) -> impl Iterator<Item = u8> {
- //~^ ERROR: captures lifetime that does not appear in bounds
self.0.iter().copied()
+ //~^ ERROR: captures lifetime that does not appear in bounds
}
}
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
- --> $DIR/issue-73159-rpit-static.rs:9:26
+ --> $DIR/issue-73159-rpit-static.rs:10:9
|
LL | impl<'a> Foo<'a> {
| -- hidden type `Copied<std::slice::Iter<'a, u8>>` captures the lifetime `'a` as defined here
LL | fn make_it(&self) -> impl Iterator<Item = u8> {
- | ^^^^^^^^^^^^^^^^^^^^^^^^
+LL | self.0.iter().copied()
+ | ^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error
impl<'a, T> Foo<'a> for T { }
fn foo<'a, T>(x: &T) -> impl Foo<'a> {
-//~^ ERROR captures lifetime that does not appear in bounds
x
+ //~^ ERROR captures lifetime that does not appear in bounds
}
fn main() {}
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
- --> $DIR/impl-trait-captures.rs:10:25
+ --> $DIR/impl-trait-captures.rs:11:5
|
LL | fn foo<'a, T>(x: &T) -> impl Foo<'a> {
- | -- ^^^^^^^^^^^^
- | |
- | hidden type `&ReFree(DefId(0:8 ~ impl_trait_captures[1afc]::foo), BrAnon(0)) T` captures the anonymous lifetime defined here
+ | -- hidden type `&ReFree(DefId(0:8 ~ impl_trait_captures[1afc]::foo), BrAnon(0)) T` captures the anonymous lifetime defined here
+LL | x
+ | ^
|
help: to declare that the `impl Trait` captures `ReFree(DefId(0:8 ~ impl_trait_captures[1afc]::foo), BrAnon(0))`, you can add an explicit `ReFree(DefId(0:8 ~ impl_trait_captures[1afc]::foo), BrAnon(0))` lifetime bound
|
use std::fmt::Debug;
fn no_region<'a, T>(x: Box<T>) -> impl Debug + 'a
- //~^ ERROR the parameter type `T` may not live long enough [E0309]
where
T: Debug,
{
x
+ //~^ ERROR the parameter type `T` may not live long enough [E0309]
}
fn correct_region<'a, T>(x: Box<T>) -> impl Debug + 'a
}
fn wrong_region<'a, 'b, T>(x: Box<T>) -> impl Debug + 'a
- //~^ ERROR the parameter type `T` may not live long enough [E0309]
where
T: 'b + Debug,
{
x
+ //~^ ERROR the parameter type `T` may not live long enough [E0309]
}
fn outlives_region<'a, 'b, T>(x: Box<T>) -> impl Debug + 'a
error[E0309]: the parameter type `T` may not live long enough
- --> $DIR/impl-trait-outlives.rs:7:35
+ --> $DIR/impl-trait-outlives.rs:11:5
|
-LL | fn no_region<'a, T>(x: Box<T>) -> impl Debug + 'a
- | ^^^^^^^^^^^^^^^
+LL | x
+ | ^
|
= help: consider adding an explicit lifetime bound `T: 'a`...
error[E0309]: the parameter type `T` may not live long enough
- --> $DIR/impl-trait-outlives.rs:22:42
+ --> $DIR/impl-trait-outlives.rs:26:5
|
-LL | fn wrong_region<'a, 'b, T>(x: Box<T>) -> impl Debug + 'a
- | ^^^^^^^^^^^^^^^
+LL | x
+ | ^
|
= help: consider adding an explicit lifetime bound `T: 'a`...
unsafe fn ff2() {} // OK.
const fn ff3() {} // OK.
extern "C" fn ff4() {} // OK.
- const async unsafe extern "C" fn ff5() {} // OK.
+ const async unsafe extern "C" fn ff5() {}
//~^ ERROR functions cannot be both `const` and `async`
+ //~| ERROR cycle detected
trait X {
async fn ft1(); //~ ERROR functions in traits cannot be declared `async`
struct Y;
impl X for Y {
async fn ft1() {} //~ ERROR functions in traits cannot be declared `async`
- //~^ ERROR method `ft1` has an incompatible type for trait
unsafe fn ft2() {} // OK.
const fn ft3() {} //~ ERROR functions in traits cannot be declared const
extern "C" fn ft4() {}
const async unsafe extern "C" fn ft5() {}
//~^ ERROR functions in traits cannot be declared `async`
//~| ERROR functions in traits cannot be declared const
- //~| ERROR method `ft5` has an incompatible type for trait
//~| ERROR functions cannot be both `const` and `async`
+ //~| ERROR cycle detected
}
impl Y {
extern "C" fn fi4() {} // OK.
const async unsafe extern "C" fn fi5() {}
//~^ ERROR functions cannot be both `const` and `async`
+ //~| ERROR cycle detected
}
extern "C" {
error: functions cannot be both `const` and `async`
--> $DIR/fn-header-semantic-fail.rs:12:5
|
-LL | const async unsafe extern "C" fn ff5() {} // OK.
+LL | const async unsafe extern "C" fn ff5() {}
| ^^^^^-^^^^^------------------------------
| | |
| | `async` because of this
| `const` because of this
error[E0706]: functions in traits cannot be declared `async`
- --> $DIR/fn-header-semantic-fail.rs:16:9
+ --> $DIR/fn-header-semantic-fail.rs:17:9
|
LL | async fn ft1();
| -----^^^^^^^^^^
= note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
error[E0379]: functions in traits cannot be declared const
- --> $DIR/fn-header-semantic-fail.rs:18:9
+ --> $DIR/fn-header-semantic-fail.rs:19:9
|
LL | const fn ft3();
| ^^^^^ functions in traits cannot be const
error[E0379]: functions in traits cannot be declared const
- --> $DIR/fn-header-semantic-fail.rs:20:9
+ --> $DIR/fn-header-semantic-fail.rs:21:9
|
LL | const async unsafe extern "C" fn ft5();
| ^^^^^ functions in traits cannot be const
error[E0706]: functions in traits cannot be declared `async`
- --> $DIR/fn-header-semantic-fail.rs:20:9
+ --> $DIR/fn-header-semantic-fail.rs:21:9
|
LL | const async unsafe extern "C" fn ft5();
| ^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
error: functions cannot be both `const` and `async`
- --> $DIR/fn-header-semantic-fail.rs:20:9
+ --> $DIR/fn-header-semantic-fail.rs:21:9
|
LL | const async unsafe extern "C" fn ft5();
| ^^^^^-^^^^^----------------------------
| `const` because of this
error[E0706]: functions in traits cannot be declared `async`
- --> $DIR/fn-header-semantic-fail.rs:28:9
+ --> $DIR/fn-header-semantic-fail.rs:29:9
|
LL | async fn ft1() {}
| -----^^^^^^^^^^^^
| `const` because of this
error: functions in `extern` blocks cannot have qualifiers
- --> $DIR/fn-header-semantic-fail.rs:50:18
+ --> $DIR/fn-header-semantic-fail.rs:51:18
|
LL | extern "C" {
| ---------- in this `extern` block
| ~~
error: functions in `extern` blocks cannot have qualifiers
- --> $DIR/fn-header-semantic-fail.rs:51:19
+ --> $DIR/fn-header-semantic-fail.rs:52:19
|
LL | extern "C" {
| ---------- in this `extern` block
| ~~
error: functions in `extern` blocks cannot have qualifiers
- --> $DIR/fn-header-semantic-fail.rs:52:18
+ --> $DIR/fn-header-semantic-fail.rs:53:18
|
LL | extern "C" {
| ---------- in this `extern` block
| ~~
error: functions in `extern` blocks cannot have qualifiers
- --> $DIR/fn-header-semantic-fail.rs:53:23
+ --> $DIR/fn-header-semantic-fail.rs:54:23
|
LL | extern "C" {
| ---------- in this `extern` block
| ~~
error: functions in `extern` blocks cannot have qualifiers
- --> $DIR/fn-header-semantic-fail.rs:54:42
+ --> $DIR/fn-header-semantic-fail.rs:55:42
|
LL | extern "C" {
| ---------- in this `extern` block
| ~~
error: functions cannot be both `const` and `async`
- --> $DIR/fn-header-semantic-fail.rs:54:9
+ --> $DIR/fn-header-semantic-fail.rs:55:9
|
LL | const async unsafe extern "C" fn fe5();
| ^^^^^-^^^^^----------------------------
| | `async` because of this
| `const` because of this
-error[E0053]: method `ft1` has an incompatible type for trait
- --> $DIR/fn-header-semantic-fail.rs:28:24
+error[E0391]: cycle detected when computing type of `main::ff5::{opaque#0}`
+ --> $DIR/fn-header-semantic-fail.rs:12:44
|
-LL | async fn ft1() {}
- | ^
- | |
- | checked the `Output` of this `async fn`, found opaque type
- | expected `()`, found opaque type
+LL | const async unsafe extern "C" fn ff5() {}
+ | ^
|
- = note: while checking the return type of the `async fn`
-note: type in trait
- --> $DIR/fn-header-semantic-fail.rs:16:23
+note: ...which requires borrow-checking `main::ff5`...
+ --> $DIR/fn-header-semantic-fail.rs:12:5
|
-LL | async fn ft1();
- | ^
- = note: expected fn pointer `fn()`
- found fn pointer `fn() -> impl Future<Output = ()>`
+LL | const async unsafe extern "C" fn ff5() {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires processing `main::ff5`...
+ --> $DIR/fn-header-semantic-fail.rs:12:5
+ |
+LL | const async unsafe extern "C" fn ff5() {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires const checking `main::ff5`...
+ --> $DIR/fn-header-semantic-fail.rs:12:5
+ |
+LL | const async unsafe extern "C" fn ff5() {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = note: ...which requires computing whether `impl core::future::future::Future<Output = ()>` is freeze...
+ = note: ...which requires evaluating trait selection obligation `impl core::future::future::Future<Output = ()>: core::marker::Freeze`...
+ = note: ...which again requires computing type of `main::ff5::{opaque#0}`, completing the cycle
+note: cycle used when checking item types in top-level module
+ --> $DIR/fn-header-semantic-fail.rs:5:1
+ |
+LL | / #![feature(const_extern_fn)]
+LL | |
+LL | | fn main() {
+LL | | async fn ff1() {} // OK.
+... |
+LL | | }
+LL | | }
+ | |_^
-error[E0053]: method `ft5` has an incompatible type for trait
+error[E0391]: cycle detected when computing type of `main::<impl at $DIR/fn-header-semantic-fail.rs:28:5: 38:6>::ft5::{opaque#0}`
--> $DIR/fn-header-semantic-fail.rs:33:48
|
LL | const async unsafe extern "C" fn ft5() {}
| ^
- | |
- | checked the `Output` of this `async fn`, found opaque type
- | expected `()`, found opaque type
|
- = note: while checking the return type of the `async fn`
-note: type in trait
- --> $DIR/fn-header-semantic-fail.rs:20:47
+note: ...which requires borrow-checking `main::<impl at $DIR/fn-header-semantic-fail.rs:28:5: 38:6>::ft5`...
+ --> $DIR/fn-header-semantic-fail.rs:33:9
|
-LL | const async unsafe extern "C" fn ft5();
- | ^
- = note: expected fn pointer `unsafe extern "C" fn()`
- found fn pointer `unsafe extern "C" fn() -> impl Future<Output = ()>`
+LL | const async unsafe extern "C" fn ft5() {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires processing `main::<impl at $DIR/fn-header-semantic-fail.rs:28:5: 38:6>::ft5`...
+ --> $DIR/fn-header-semantic-fail.rs:33:9
+ |
+LL | const async unsafe extern "C" fn ft5() {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires const checking `main::<impl at $DIR/fn-header-semantic-fail.rs:28:5: 38:6>::ft5`...
+ --> $DIR/fn-header-semantic-fail.rs:33:9
+ |
+LL | const async unsafe extern "C" fn ft5() {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = note: ...which requires computing whether `impl core::future::future::Future<Output = ()>` is freeze...
+ = note: ...which requires evaluating trait selection obligation `impl core::future::future::Future<Output = ()>: core::marker::Freeze`...
+ = note: ...which again requires computing type of `main::<impl at $DIR/fn-header-semantic-fail.rs:28:5: 38:6>::ft5::{opaque#0}`, completing the cycle
+note: cycle used when checking item types in top-level module
+ --> $DIR/fn-header-semantic-fail.rs:5:1
+ |
+LL | / #![feature(const_extern_fn)]
+LL | |
+LL | | fn main() {
+LL | | async fn ff1() {} // OK.
+... |
+LL | | }
+LL | | }
+ | |_^
+
+error[E0391]: cycle detected when computing type of `main::<impl at $DIR/fn-header-semantic-fail.rs:40:5: 48:6>::fi5::{opaque#0}`
+ --> $DIR/fn-header-semantic-fail.rs:45:48
+ |
+LL | const async unsafe extern "C" fn fi5() {}
+ | ^
+ |
+note: ...which requires borrow-checking `main::<impl at $DIR/fn-header-semantic-fail.rs:40:5: 48:6>::fi5`...
+ --> $DIR/fn-header-semantic-fail.rs:45:9
+ |
+LL | const async unsafe extern "C" fn fi5() {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires processing `main::<impl at $DIR/fn-header-semantic-fail.rs:40:5: 48:6>::fi5`...
+ --> $DIR/fn-header-semantic-fail.rs:45:9
+ |
+LL | const async unsafe extern "C" fn fi5() {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires const checking `main::<impl at $DIR/fn-header-semantic-fail.rs:40:5: 48:6>::fi5`...
+ --> $DIR/fn-header-semantic-fail.rs:45:9
+ |
+LL | const async unsafe extern "C" fn fi5() {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = note: ...which requires computing whether `impl core::future::future::Future<Output = ()>` is freeze...
+ = note: ...which requires evaluating trait selection obligation `impl core::future::future::Future<Output = ()>: core::marker::Freeze`...
+ = note: ...which again requires computing type of `main::<impl at $DIR/fn-header-semantic-fail.rs:40:5: 48:6>::fi5::{opaque#0}`, completing the cycle
+note: cycle used when checking item types in top-level module
+ --> $DIR/fn-header-semantic-fail.rs:5:1
+ |
+LL | / #![feature(const_extern_fn)]
+LL | |
+LL | | fn main() {
+LL | | async fn ff1() {} // OK.
+... |
+LL | | }
+LL | | }
+ | |_^
-error: aborting due to 20 previous errors
+error: aborting due to 21 previous errors
-Some errors have detailed explanations: E0053, E0379, E0706.
-For more information about an error, try `rustc --explain E0053`.
+Some errors have detailed explanations: E0379, E0391, E0706.
+For more information about an error, try `rustc --explain E0379`.
LL | "invalid-ab_isize"
| ^^^^^^^^^^^^^^^^^^ invalid ABI
|
- = help: valid ABIs: Rust, C, C-unwind, cdecl, stdcall, stdcall-unwind, fastcall, vectorcall, thiscall, thiscall-unwind, aapcs, win64, sysv64, ptx-kernel, msp430-interrupt, x86-interrupt, amdgpu-kernel, efiapi, avr-interrupt, avr-non-blocking-interrupt, C-cmse-nonsecure-call, wasm, system, system-unwind, rust-intrinsic, rust-call, platform-intrinsic, unadjusted
+ = help: valid ABIs: Rust, C, C-unwind, cdecl, cdecl-unwind, stdcall, stdcall-unwind, fastcall, fastcall-unwind, vectorcall, vectorcall-unwind, thiscall, thiscall-unwind, aapcs, aapcs-unwind, win64, win64-unwind, sysv64, sysv64-unwind, ptx-kernel, msp430-interrupt, x86-interrupt, amdgpu-kernel, efiapi, avr-interrupt, avr-non-blocking-interrupt, C-cmse-nonsecure-call, wasm, system, system-unwind, rust-intrinsic, rust-call, platform-intrinsic, unadjusted
error: aborting due to previous error
#[rustc_polymorphize_error]
pub fn unused_type<T>() -> impl Generator<(), Yield = u32, Return = u32> + Unpin {
- //~^ ERROR item has unused generic parameters
|| {
//~^ ERROR item has unused generic parameters
yield 1;
#[rustc_polymorphize_error]
pub fn unused_const<const T: u32>() -> impl Generator<(), Yield = u32, Return = u32> + Unpin {
- //~^ ERROR item has unused generic parameters
|| {
//~^ ERROR item has unused generic parameters
yield 1;
= note: see issue #76560 <https://github.com/rust-lang/rust/issues/76560> for more information
error: item has unused generic parameters
- --> $DIR/generators.rs:36:5
+ --> $DIR/generators.rs:35:5
|
LL | pub fn unused_type<T>() -> impl Generator<(), Yield = u32, Return = u32> + Unpin {
| - generic parameter `T` is unused
-LL |
LL | / || {
LL | |
LL | | yield 1;
| |_____^
error: item has unused generic parameters
- --> $DIR/generators.rs:34:8
- |
-LL | pub fn unused_type<T>() -> impl Generator<(), Yield = u32, Return = u32> + Unpin {
- | ^^^^^^^^^^^ - generic parameter `T` is unused
-
-error: item has unused generic parameters
- --> $DIR/generators.rs:62:5
+ --> $DIR/generators.rs:60:5
|
LL | pub fn unused_const<const T: u32>() -> impl Generator<(), Yield = u32, Return = u32> + Unpin {
| - generic parameter `T` is unused
-LL |
LL | / || {
LL | |
LL | | yield 1;
LL | | }
| |_____^
-error: item has unused generic parameters
- --> $DIR/generators.rs:60:8
- |
-LL | pub fn unused_const<const T: u32>() -> impl Generator<(), Yield = u32, Return = u32> + Unpin {
- | ^^^^^^^^^^^^ - generic parameter `T` is unused
-
-error: aborting due to 4 previous errors; 1 warning emitted
+error: aborting due to 2 previous errors; 1 warning emitted
impl B for A {
async fn associated(); //~ ERROR without body
//~^ ERROR cannot be declared `async`
- //~| ERROR incompatible type for trait
}
fn main() {}
= note: `async` trait functions are not currently supported
= note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
-error[E0053]: method `associated` has an incompatible type for trait
- --> $DIR/issue-70736-async-fn-no-body-def-collector.rs:15:26
- |
-LL | async fn associated();
- | ^
- | |
- | checked the `Output` of this `async fn`, found opaque type
- | expected `()`, found opaque type
- |
- = note: while checking the return type of the `async fn`
-note: type in trait
- --> $DIR/issue-70736-async-fn-no-body-def-collector.rs:11:26
- |
-LL | async fn associated();
- | ^
- = note: expected fn pointer `fn()`
- found fn pointer `fn() -> impl Future<Output = ()>`
-
-error: aborting due to 6 previous errors
+error: aborting due to 5 previous errors
-Some errors have detailed explanations: E0053, E0706.
-For more information about an error, try `rustc --explain E0053`.
+For more information about this error, try `rustc --explain E0706`.
struct Struct;
impl Service for Struct {
- type Future = impl Trait; //~ ERROR: could not find defining uses
+ type Future = impl Trait; //~ ERROR: unconstrained opaque type
}
fn main() {}
-error: could not find defining uses
+error: unconstrained opaque type
--> $DIR/issue-68621.rs:14:19
|
LL | type Future = impl Trait;
| ^^^^^^^^^^
+ |
+ = note: `Future` must be used in combination with a concrete type within the same module
error: aborting due to previous error
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
- --> $DIR/arbitrary_self_types_pin_lifetime_impl_trait-async.rs:8:37
+ --> $DIR/arbitrary_self_types_pin_lifetime_impl_trait-async.rs:8:48
|
LL | async fn f(self: Pin<&Self>) -> impl Clone { self }
- | - ^^^^^^^^^^
+ | - ^^^^^^^^
| |
| hidden type `Pin<&Foo>` captures the lifetime `'_` as defined here
|
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
- --> $DIR/arbitrary_self_types_pin_lifetime_impl_trait.rs:6:31
+ --> $DIR/arbitrary_self_types_pin_lifetime_impl_trait.rs:6:44
|
LL | fn f(self: Pin<&Self>) -> impl Clone { self }
- | ----- ^^^^^^^^^^
+ | ----- ^^^^
| |
| hidden type `Pin<&Foo>` captures the anonymous lifetime defined here
|
let _: Option<(i8,)> = Some();
//~^ ERROR this enum variant takes 1 argument but 0 arguments were supplied
+
+ let _: Option<(i32,)> = Some(5_usize);
+ //~^ ERROR mismatched types
+
+ let _: Option<(i32,)> = Some((5_usize));
+ //~^ ERROR mismatched types
}
fn int_bool(_: (i32, bool)) {
| expected 1 argument
|
note: function defined here
- --> $DIR/args-instead-of-tuple-errors.rs:15:4
+ --> $DIR/args-instead-of-tuple-errors.rs:21:4
|
LL | fn int_bool(_: (i32, bool)) {
| ^^^^^^^^ --------------
| |
| expected 1 argument
-error: aborting due to 3 previous errors
+error[E0308]: mismatched types
+ --> $DIR/args-instead-of-tuple-errors.rs:14:34
+ |
+LL | let _: Option<(i32,)> = Some(5_usize);
+ | ^^^^^^^ expected tuple, found `usize`
+ |
+ = note: expected tuple `(i32,)`
+ found type `usize`
+
+error[E0308]: mismatched types
+ --> $DIR/args-instead-of-tuple-errors.rs:17:34
+ |
+LL | let _: Option<(i32,)> = Some((5_usize));
+ | ^^^^^^^^^ expected tuple, found `usize`
+ |
+ = note: expected tuple `(i32,)`
+ found type `usize`
+
+error: aborting due to 5 previous errors
-For more information about this error, try `rustc --explain E0061`.
+Some errors have detailed explanations: E0061, E0308.
+For more information about an error, try `rustc --explain E0061`.
let _: Option<()> = Some(());
//~^ ERROR this enum variant takes 1 argument but 0 arguments were supplied
+ let _: Option<(i32,)> = Some((3,));
+ //~^ ERROR mismatched types
+
+ let _: Option<(i32,)> = Some((3,));
+ //~^ ERROR mismatched types
+
two_ints((1, 2)); //~ ERROR this function takes 1 argument
with_generic((3, 4)); //~ ERROR this function takes 1 argument
let _: Option<()> = Some();
//~^ ERROR this enum variant takes 1 argument but 0 arguments were supplied
+ let _: Option<(i32,)> = Some(3);
+ //~^ ERROR mismatched types
+
+ let _: Option<(i32,)> = Some((3));
+ //~^ ERROR mismatched types
+
two_ints(1, 2); //~ ERROR this function takes 1 argument
with_generic(3, 4); //~ ERROR this function takes 1 argument
LL | let _: Option<()> = Some(());
| ++
+error[E0308]: mismatched types
+ --> $DIR/args-instead-of-tuple.rs:14:34
+ |
+LL | let _: Option<(i32,)> = Some(3);
+ | ^ expected tuple, found integer
+ |
+ = note: expected tuple `(i32,)`
+ found type `{integer}`
+help: use a trailing comma to create a tuple with one element
+ |
+LL | let _: Option<(i32,)> = Some((3,));
+ | + ++
+
+error[E0308]: mismatched types
+ --> $DIR/args-instead-of-tuple.rs:17:34
+ |
+LL | let _: Option<(i32,)> = Some((3));
+ | ^^^ expected tuple, found integer
+ |
+ = note: expected tuple `(i32,)`
+ found type `{integer}`
+help: use a trailing comma to create a tuple with one element
+ |
+LL | let _: Option<(i32,)> = Some((3,));
+ | +
+
error[E0061]: this function takes 1 argument but 2 arguments were supplied
- --> $DIR/args-instead-of-tuple.rs:14:5
+ --> $DIR/args-instead-of-tuple.rs:20:5
|
LL | two_ints(1, 2);
| ^^^^^^^^ - - supplied 2 arguments
|
note: function defined here
- --> $DIR/args-instead-of-tuple.rs:19:4
+ --> $DIR/args-instead-of-tuple.rs:25:4
|
LL | fn two_ints(_: (i32, i32)) {
| ^^^^^^^^ -------------
| + +
error[E0061]: this function takes 1 argument but 2 arguments were supplied
- --> $DIR/args-instead-of-tuple.rs:16:5
+ --> $DIR/args-instead-of-tuple.rs:22:5
|
LL | with_generic(3, 4);
| ^^^^^^^^^^^^ - - supplied 2 arguments
|
note: function defined here
- --> $DIR/args-instead-of-tuple.rs:22:4
+ --> $DIR/args-instead-of-tuple.rs:28:4
|
LL | fn with_generic<T: Copy + Send>((a, b): (i32, T)) {
| ^^^^^^^^^^^^ ----------------
| + +
error[E0061]: this function takes 1 argument but 2 arguments were supplied
- --> $DIR/args-instead-of-tuple.rs:25:9
+ --> $DIR/args-instead-of-tuple.rs:31:9
|
LL | with_generic(a, b);
| ^^^^^^^^^^^^ - - supplied 2 arguments
|
note: function defined here
- --> $DIR/args-instead-of-tuple.rs:22:4
+ --> $DIR/args-instead-of-tuple.rs:28:4
|
LL | fn with_generic<T: Copy + Send>((a, b): (i32, T)) {
| ^^^^^^^^^^^^ ----------------
LL | with_generic((a, b));
| + +
-error: aborting due to 6 previous errors
+error: aborting due to 8 previous errors
-For more information about this error, try `rustc --explain E0061`.
+Some errors have detailed explanations: E0061, E0308.
+For more information about an error, try `rustc --explain E0061`.
error[E0277]: the trait bound `(): Bar` is not satisfied
- --> $DIR/impl-trait-return-trailing-semicolon.rs:3:13
+ --> $DIR/impl-trait-return-trailing-semicolon.rs:3:22
|
-LL | fn foo() -> impl Bar {
- | ^^^^^^^^ the trait `Bar` is not implemented for `()`
-LL | 5;
- | - consider removing this semicolon
+LL | fn foo() -> impl Bar {
+ | ______________________^
+LL | | 5;
+LL | | }
+ | |_^ the trait `Bar` is not implemented for `()`
error: aborting due to previous error
error[E0277]: `()` doesn't implement `std::fmt::Display`
- --> $DIR/issue-81098.rs:3:13
+ --> $DIR/issue-81098.rs:3:37
|
-LL | fn wat() -> impl core::fmt::Display {
- | ^^^^^^^^^^^^^^^^^^^^^^^ `()` cannot be formatted with the default formatter
+LL | fn wat() -> impl core::fmt::Display {
+ | _____________________________________^
+LL | | fn why() {}
+LL | | }
+ | |_^ `()` cannot be formatted with the default formatter
|
= help: the trait `std::fmt::Display` is not implemented for `()`
= note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
error[E0277]: `()` doesn't implement `std::fmt::Display`
- --> $DIR/issue-81098.rs:9:12
+ --> $DIR/issue-81098.rs:9:36
|
-LL | fn ok() -> impl core::fmt::Display {
- | ^^^^^^^^^^^^^^^^^^^^^^^ `()` cannot be formatted with the default formatter
-LL | 1;
- | - consider removing this semicolon
+LL | fn ok() -> impl core::fmt::Display {
+ | ____________________________________^
+LL | | 1;
+LL | | }
+ | |_^ `()` cannot be formatted with the default formatter
|
= help: the trait `std::fmt::Display` is not implemented for `()`
= note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
help: use a trailing comma to create a tuple with one element
|
LL | let _x: (i32,) = (5,);
- | ~~~~
+ | +
error[E0308]: mismatched types
--> $DIR/issue-86100-tuple-paren-comma.rs:13:9
help: use a trailing comma to create a tuple with one element
|
LL | foo((Some(3),));
- | ~~~~~~~~~~
+ | +
error[E0308]: mismatched types
--> $DIR/issue-86100-tuple-paren-comma.rs:17:22
help: use a trailing comma to create a tuple with one element
|
LL | let _s = S { _s: ("abc".to_string(),) };
- | ~~~~~~~~~~~~~~~~~~~~
+ | +
error[E0308]: mismatched types
--> $DIR/issue-86100-tuple-paren-comma.rs:23:22
LL | remaining: self.0.iter(),
| ------ ^^^^
| |
- | ...is used here...
+ | ...is used and required to live as long as `'static` here
|
-note: ...and is required to live as long as `'static` here
+note: `'static` lifetime requirement introduced by the return type
--> $DIR/trait-object-nested-in-impl-trait.rs:27:23
|
-LL | fn iter(&self) -> impl Iterator<Item = Box<dyn Foo>> {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | fn iter(&self) -> impl Iterator<Item = Box<dyn Foo>> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requirement introduced by this return type
+LL | / Iter {
+LL | | current: None,
+LL | | remaining: self.0.iter(),
+LL | | }
+ | |_________- because of this returned expression
help: to declare that the `impl Trait` captures data from argument `self`, you can add an explicit `'_` lifetime bound
|
LL | fn iter(&self) -> impl Iterator<Item = Box<dyn Foo>> + '_ {
LL | remaining: self.0.iter(),
| ------ ^^^^
| |
- | ...is used here...
+ | ...is used and required to live as long as `'static` here
|
-note: ...and is required to live as long as `'static` here
+note: `'static` lifetime requirement introduced by the return type
--> $DIR/trait-object-nested-in-impl-trait.rs:38:23
|
-LL | fn iter(&self) -> impl Iterator<Item = Box<dyn Foo>> + '_ {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | fn iter(&self) -> impl Iterator<Item = Box<dyn Foo>> + '_ {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requirement introduced by this return type
+LL | / Iter {
+LL | | current: None,
+LL | | remaining: self.0.iter(),
+LL | | }
+ | |_________- because of this returned expression
help: to declare that the trait object captures data from argument `self`, you can add an explicit `'_` lifetime bound
|
LL | fn iter(&self) -> impl Iterator<Item = Box<dyn Foo + '_>> + '_ {
LL | remaining: self.0.iter(),
| ------ ^^^^
| |
- | ...is used here...
+ | ...is used and required to live as long as `'static` here
|
-note: ...and is required to live as long as `'static` here
+note: `'static` lifetime requirement introduced by the return type
--> $DIR/trait-object-nested-in-impl-trait.rs:49:30
|
-LL | fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo>> + 'a {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo>> + 'a {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requirement introduced by this return type
+LL | / Iter {
+LL | | current: None,
+LL | | remaining: self.0.iter(),
+LL | | }
+ | |_________- because of this returned expression
help: to declare that the trait object captures data from argument `self`, you can add an explicit `'a` lifetime bound
|
LL | fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo + 'a>> + 'a {
LL | remaining: self.0.iter(),
| ------ ^^^^
| |
- | ...is used here...
+ | ...is used and required to live as long as `'static` here
|
-note: ...and is required to live as long as `'static` here
+note: `'static` lifetime requirement introduced by the return type
--> $DIR/trait-object-nested-in-impl-trait.rs:60:30
|
-LL | fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo>> {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo>> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requirement introduced by this return type
+LL | / Iter {
+LL | | current: None,
+LL | | remaining: self.0.iter(),
+LL | | }
+ | |_________- because of this returned expression
help: to declare that the `impl Trait` captures data from argument `self`, you can add an explicit `'a` lifetime bound
|
LL | fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo>> + 'a {
async fn async_dummy() {} //~ NOTE checked the `Output` of this `async fn`, found opaque type
//~| NOTE while checking the return type of the `async fn`
//~| NOTE in this expansion of desugaring of `async` block or function
+//~| NOTE while checking the return type of the `async fn`
+//~| NOTE in this expansion of desugaring of `async` block or function
+//~| NOTE checked the `Output` of this `async fn`, expected opaque type
async fn async_dummy2() {} //~ NOTE checked the `Output` of this `async fn`, found opaque type
//~| NOTE checked the `Output` of this `async fn`, found opaque type
//~| NOTE while checking the return type of the `async fn`
}
false => async_dummy(), //~ ERROR `match` arms have incompatible types
//~^ NOTE expected `()`, found opaque type
- //~| NOTE expected type `()`
+ //~| NOTE expected unit type `()`
//~| HELP consider `await`ing on the `Future`
};
}
}
false => async_dummy2(), //~ ERROR `match` arms have incompatible types
//~^ NOTE expected `()`, found opaque type
- //~| NOTE expected type `()`
+ //~| NOTE expected unit type `()`
//~| HELP consider `await`ing on the `Future`
};
}
//~| HELP consider `await`ing on both `Future`s
false => async_dummy2(), //~ ERROR `match` arms have incompatible types
//~^ NOTE expected opaque type, found a different opaque type
- //~| NOTE expected type `impl Future<Output = ()>`
+ //~| NOTE expected opaque type `impl Future<Output = ()>`
//~| NOTE distinct uses of `impl Trait` result in different opaque types
};
}
error[E0308]: `match` arms have incompatible types
- --> $DIR/match-prev-arm-needing-semi.rs:32:18
+ --> $DIR/match-prev-arm-needing-semi.rs:35:18
|
LL | let _ = match true {
| _____________-
|
LL | async fn async_dummy() {}
| ^ checked the `Output` of this `async fn`, found opaque type
- = note: expected type `()`
- found opaque type `impl Future<Output = ()>`
+ = note: expected unit type `()`
+ found opaque type `impl Future<Output = ()>`
help: consider `await`ing on the `Future`
|
LL | false => async_dummy().await,
|
error[E0308]: `match` arms have incompatible types
- --> $DIR/match-prev-arm-needing-semi.rs:45:18
+ --> $DIR/match-prev-arm-needing-semi.rs:48:18
|
LL | let _ = match true {
| _____________-
| |_____- `match` arms have incompatible types
|
note: while checking the return type of the `async fn`
- --> $DIR/match-prev-arm-needing-semi.rs:19:25
+ --> $DIR/match-prev-arm-needing-semi.rs:22:25
|
LL | async fn async_dummy2() {}
| ^ checked the `Output` of this `async fn`, found opaque type
- = note: expected type `()`
- found opaque type `impl Future<Output = ()>`
+ = note: expected unit type `()`
+ found opaque type `impl Future<Output = ()>`
help: consider `await`ing on the `Future`
|
LL | false => async_dummy2().await,
|
error[E0308]: `match` arms have incompatible types
- --> $DIR/match-prev-arm-needing-semi.rs:56:18
+ --> $DIR/match-prev-arm-needing-semi.rs:59:18
|
LL | let _ = match true {
| _____________-
| |_____- `match` arms have incompatible types
|
note: while checking the return type of the `async fn`
- --> $DIR/match-prev-arm-needing-semi.rs:19:25
+ --> $DIR/match-prev-arm-needing-semi.rs:16:24
+ |
+LL | async fn async_dummy() {}
+ | ^ checked the `Output` of this `async fn`, expected opaque type
+note: while checking the return type of the `async fn`
+ --> $DIR/match-prev-arm-needing-semi.rs:22:25
|
LL | async fn async_dummy2() {}
| ^ checked the `Output` of this `async fn`, found opaque type
- = note: expected type `impl Future<Output = ()>` (opaque type at <$DIR/match-prev-arm-needing-semi.rs:16:24>)
- found opaque type `impl Future<Output = ()>` (opaque type at <$DIR/match-prev-arm-needing-semi.rs:19:25>)
+ = note: expected opaque type `impl Future<Output = ()>` (opaque type at <$DIR/match-prev-arm-needing-semi.rs:16:24>)
+ found opaque type `impl Future<Output = ()>` (opaque type at <$DIR/match-prev-arm-needing-semi.rs:22:25>)
= note: distinct uses of `impl Trait` result in different opaque types
help: consider `await`ing on both `Future`s
|
error[E0308]: `if` and `else` have incompatible types
--> $DIR/opaque-type-error.rs:20:9
|
+LL | fn thing_one() -> impl Future<Output = Result<(), ()>> {
+ | ------------------------------------ the expected opaque type
+...
LL | fn thing_two() -> impl Future<Output = Result<(), ()>> {
| ------------------------------------ the found opaque type
...
LL | | }.await
| |_____- `if` and `else` have incompatible types
|
- = note: expected type `impl Future<Output = Result<(), ()>>` (opaque type at <$DIR/opaque-type-error.rs:8:19>)
- found opaque type `impl Future<Output = Result<(), ()>>` (opaque type at <$DIR/opaque-type-error.rs:12:19>)
+ = note: expected opaque type `impl Future<Output = Result<(), ()>>` (opaque type at <$DIR/opaque-type-error.rs:8:19>)
+ found opaque type `impl Future<Output = Result<(), ()>>` (opaque type at <$DIR/opaque-type-error.rs:12:19>)
= note: distinct uses of `impl Trait` result in different opaque types
help: consider `await`ing on both `Future`s
|
+++ /dev/null
-// run-pass
-// compile-flags: --test
-#![feature(allow_fail)]
-#![feature(cfg_panic)]
-
-#[test]
-#[allow_fail]
-fn test1() {
- #[cfg(not(panic = "abort"))]
- panic!();
-}
-
-#[test]
-#[allow_fail]
-fn test2() {
- assert!(true);
-}
trait AnotherTrait {}
impl<T: Send> AnotherTrait for T {}
impl AnotherTrait for OpaqueType {}
-//~^ ERROR conflicting implementations of trait `AnotherTrait` for type `impl OpaqueTrait`
+//~^ ERROR conflicting implementations of trait `AnotherTrait` for type `OpaqueType`
//~| ERROR cannot implement trait on type alias impl trait
fn main() {}
LL | type OpaqueType = impl OpaqueTrait;
| ^^^^^^^^^^^^^^^^
-error[E0119]: conflicting implementations of trait `AnotherTrait` for type `impl OpaqueTrait`
+error[E0119]: conflicting implementations of trait `AnotherTrait` for type `OpaqueType`
--> $DIR/issue-83613.rs:10:1
|
LL | impl<T: Send> AnotherTrait for T {}
| -------------------------------- first implementation here
LL | impl AnotherTrait for OpaqueType {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `impl OpaqueTrait`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `OpaqueType`
error: aborting due to 2 previous errors
#![feature(type_alias_impl_trait)]
#![allow(dead_code)]
-
+// check-pass
use std::fmt::Debug;
type Foo = impl Debug;
-// FIXME: This should compile, but it currently doesn't
fn foo1(mut x: Foo) {
x = 22_u32;
- //~^ ERROR: mismatched types [E0308]
}
fn foo2(mut x: Foo) {
+++ /dev/null
-error[E0308]: mismatched types
- --> $DIR/argument-types.rs:10:9
- |
-LL | type Foo = impl Debug;
- | ---------- the expected opaque type
-...
-LL | fn foo1(mut x: Foo) {
- | --- expected due to this parameter type
-LL | x = 22_u32;
- | ^^^^^^ expected opaque type, found `u32`
- |
- = note: expected opaque type `impl Debug`
- found type `u32`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0308`.
--> $DIR/auto-trait-leakage2.rs:17:13
|
LL | type Foo = impl std::fmt::Debug;
- | -------------------- within this `impl Debug`
+ | -------------------- within this `Foo`
...
LL | is_send(m::foo());
| ------- ^^^^^^^^ `Rc<u32>` cannot be sent between threads safely
| |
| required by a bound introduced by this call
|
- = help: within `impl Debug`, the trait `Send` is not implemented for `Rc<u32>`
- = note: required because it appears within the type `impl Debug`
+ = help: within `Foo`, the trait `Send` is not implemented for `Rc<u32>`
+ = note: required because it appears within the type `Foo`
note: required by a bound in `is_send`
--> $DIR/auto-trait-leakage2.rs:14:15
|
mod m {
type Foo = impl std::fmt::Debug;
//~^ ERROR: cycle detected when computing type of `m::Foo::{opaque#0}` [E0391]
+ //~| ERROR: cycle detected when computing type of `m::Foo::{opaque#0}` [E0391]
pub fn foo() -> Foo {
22_u32
| ^^^^^^^^^^^^^^^^^^^^
|
note: ...which requires type-checking `m::bar`...
- --> $DIR/auto-trait-leakage3.rs:15:9
+ --> $DIR/auto-trait-leakage3.rs:15:5
|
-LL | is_send(foo());
- | ^^^^^^^
- = note: ...which requires evaluating trait selection obligation `impl core::fmt::Debug: core::marker::Send`...
+LL | pub fn bar() {
+ | ^^^^^^^^^^^^
= note: ...which again requires computing type of `m::Foo::{opaque#0}`, completing the cycle
note: cycle used when checking item types in module `m`
--> $DIR/auto-trait-leakage3.rs:6:1
LL | mod m {
| ^^^^^
-error: aborting due to previous error
+error[E0391]: cycle detected when computing type of `m::Foo::{opaque#0}`
+ --> $DIR/auto-trait-leakage3.rs:7:16
+ |
+LL | type Foo = impl std::fmt::Debug;
+ | ^^^^^^^^^^^^^^^^^^^^
+ |
+note: ...which requires type-checking `m::bar`...
+ --> $DIR/auto-trait-leakage3.rs:15:5
+ |
+LL | pub fn bar() {
+ | ^^^^^^^^^^^^
+ = note: ...which again requires computing type of `m::Foo::{opaque#0}`, completing the cycle
+note: cycle used when checking item types in module `m`
+ --> $DIR/auto-trait-leakage3.rs:6:1
+ |
+LL | mod m {
+ | ^^^^^
+
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0391`.
}
type Foo<V> = impl Trait<V>;
-//~^ ERROR could not find defining uses
trait Trait<U> {}
impl<W> Trait<W> for () {}
fn foo_desugared<T: TraitWithAssoc>(_: T) -> Foo<T::Assoc> {
- //~^ ERROR non-defining opaque type use in defining scope
()
+ //~^ ERROR non-defining opaque type use
}
error: non-defining opaque type use in defining scope
- --> $DIR/bound_reduction2.rs:16:46
+ --> $DIR/bound_reduction2.rs:16:5
|
-LL | fn foo_desugared<T: TraitWithAssoc>(_: T) -> Foo<T::Assoc> {
- | ^^^^^^^^^^^^^
+LL | ()
+ | ^^
|
note: used non-generic type `<T as TraitWithAssoc>::Assoc` for generic parameter
--> $DIR/bound_reduction2.rs:9:10
LL | type Foo<V> = impl Trait<V>;
| ^
-error: could not find defining uses
- --> $DIR/bound_reduction2.rs:9:15
- |
-LL | type Foo<V> = impl Trait<V>;
- | ^^^^^^^^^^^^^
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
#![feature(type_alias_impl_trait)]
type X<'a> = impl Into<&'static str> + From<&'a str>;
-//~^ ERROR mismatched types
fn f<'a: 'static>(t: &'a str) -> X<'a> {
//~^ WARNING unnecessary lifetime parameter
t
+ //~^ ERROR non-defining opaque type use
}
fn extend_lt<'a>(o: &'a str) -> &'static str {
warning: unnecessary lifetime parameter `'a`
- --> $DIR/bounds-are-checked.rs:9:6
+ --> $DIR/bounds-are-checked.rs:8:6
|
LL | fn f<'a: 'static>(t: &'a str) -> X<'a> {
| ^^^^^^^^^^^
|
= help: you can use the `'static` lifetime directly, in place of `'a`
-error[E0308]: mismatched types
- --> $DIR/bounds-are-checked.rs:6:14
+error: non-defining opaque type use in defining scope
+ --> $DIR/bounds-are-checked.rs:10:5
|
LL | type X<'a> = impl Into<&'static str> + From<&'a str>;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch
- |
- = note: expected trait `From<&'a str>`
- found trait `From<&'static str>`
-note: the lifetime `'a` as defined here...
- --> $DIR/bounds-are-checked.rs:6:8
- |
-LL | type X<'a> = impl Into<&'static str> + From<&'a str>;
- | ^^
- = note: ...does not necessarily outlive the static lifetime
+ | -- cannot use static lifetime; use a bound lifetime instead or remove the lifetime parameter from the opaque type
+...
+LL | t
+ | ^
error: aborting due to previous error; 1 warning emitted
-For more information about this error, try `rustc --explain E0308`.
fn main() {}
// declared but never defined
-type Bar = impl std::fmt::Debug; //~ ERROR could not find defining uses
+type Bar = impl std::fmt::Debug; //~ ERROR unconstrained opaque type
-error: could not find defining uses
+error: unconstrained opaque type
--> $DIR/declared_but_never_defined.rs:6:12
|
LL | type Bar = impl std::fmt::Debug;
| ^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: `Bar` must be used in combination with a concrete type within the same module
error: aborting due to previous error
mod boo {
// declared in module but not defined inside of it
- pub type Boo = impl ::std::fmt::Debug; //~ ERROR could not find defining uses
+ pub type Boo = impl ::std::fmt::Debug; //~ ERROR unconstrained opaque type
}
fn bomp() -> boo::Boo {
-error: could not find defining uses
+error: unconstrained opaque type
--> $DIR/declared_but_not_defined_in_scope.rs:7:20
|
LL | pub type Boo = impl ::std::fmt::Debug;
| ^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: `Boo` must be used in combination with a concrete type within the same module
error[E0308]: mismatched types
--> $DIR/declared_but_not_defined_in_scope.rs:11:5
LL | pub type Boo = impl ::std::fmt::Debug;
| ---------------------- the expected opaque type
...
-LL | fn bomp() -> boo::Boo {
- | -------- expected `impl Debug` because of return type
LL | ""
| ^^ expected opaque type, found `&str`
|
- = note: expected opaque type `impl Debug`
- found reference `&'static str`
+ = note: expected opaque type `Boo`
+ found reference `&str`
error: aborting due to 2 previous errors
#![feature(type_alias_impl_trait)]
-
+// check-pass
fn main() {}
// two definitions with different types
}
fn bar() -> Foo {
- //~^ ERROR concrete type differs from previous
panic!()
}
fn boo() -> Foo {
- //~^ ERROR concrete type differs from previous
loop {}
}
+++ /dev/null
-error: concrete type differs from previous defining opaque type use
- --> $DIR/different_defining_uses_never_type.rs:12:1
- |
-LL | fn bar() -> Foo {
- | ^^^^^^^^^^^^^^^ expected `&'static str`, got `()`
- |
-note: previous use here
- --> $DIR/different_defining_uses_never_type.rs:8:1
- |
-LL | fn foo() -> Foo {
- | ^^^^^^^^^^^^^^^
-
-error: concrete type differs from previous defining opaque type use
- --> $DIR/different_defining_uses_never_type.rs:17:1
- |
-LL | fn boo() -> Foo {
- | ^^^^^^^^^^^^^^^ expected `&'static str`, got `()`
- |
-note: previous use here
- --> $DIR/different_defining_uses_never_type.rs:8:1
- |
-LL | fn foo() -> Foo {
- | ^^^^^^^^^^^^^^^
-
-error: aborting due to 2 previous errors
-
-// Tests that we correctly handle the instantiated
-// inference variable being completely unconstrained.
+// Tests that we correctly handle opaque types being used opaquely,
+// even within their defining scope.
//
// check-pass
#![feature(type_alias_impl_trait)]
#![feature(type_alias_impl_trait)]
#![allow(dead_code)]
-// FIXME This should compile, but it currently doesn't
+// check-pass
use std::fmt::Debug;
type Foo = impl Debug;
-//~^ ERROR: could not find defining uses
struct Bar {
foo: Foo,
fn bar() -> Bar {
Bar { foo: "foo" }
- //~^ ERROR: mismatched types [E0308]
}
fn main() {}
+++ /dev/null
-error[E0308]: mismatched types
- --> $DIR/field-types.rs:16:16
- |
-LL | type Foo = impl Debug;
- | ---------- the expected opaque type
-...
-LL | Bar { foo: "foo" }
- | ^^^^^ expected opaque type, found `&str`
- |
- = note: expected opaque type `impl Debug`
- found reference `&'static str`
-
-error: could not find defining uses
- --> $DIR/field-types.rs:8:12
- |
-LL | type Foo = impl Debug;
- | ^^^^^^^^^^
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0308`.
fn main() {}
type Two<'a, 'b> = impl std::fmt::Debug;
-//~^ ERROR could not find defining uses
+
fn one<'a>(t: &'a ()) -> Two<'a, 'a> {
- //~^ ERROR non-defining opaque type use
t
+ //~^ ERROR non-defining opaque type use
}
error: non-defining opaque type use in defining scope
- --> $DIR/generic_duplicate_lifetime_param.rs:8:26
+ --> $DIR/generic_duplicate_lifetime_param.rs:9:5
|
-LL | fn one<'a>(t: &'a ()) -> Two<'a, 'a> {
- | ^^^^^^^^^^^
+LL | t
+ | ^
|
note: lifetime used multiple times
--> $DIR/generic_duplicate_lifetime_param.rs:5:10
LL | type Two<'a, 'b> = impl std::fmt::Debug;
| ^^ ^^
-error: could not find defining uses
- --> $DIR/generic_duplicate_lifetime_param.rs:5:20
- |
-LL | type Two<'a, 'b> = impl std::fmt::Debug;
- | ^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
// test that unused generic parameters are ok
type TwoTys<T, U> = impl Debug;
-//~^ ERROR could not find defining uses
+
type TwoLifetimes<'a, 'b> = impl Debug;
-//~^ ERROR could not find defining uses
+
type TwoConsts<const X: usize, const Y: usize> = impl Debug;
-//~^ ERROR could not find defining uses
+
fn one_ty<T: Debug>(t: T) -> TwoTys<T, T> {
- //~^ ERROR non-defining opaque type use in defining scope
t
+ //~^ ERROR non-defining opaque type use in defining scope
}
fn one_lifetime<'a>(t: &'a u32) -> TwoLifetimes<'a, 'a> {
- //~^ ERROR non-defining opaque type use in defining scope
t
+ //~^ ERROR non-defining opaque type use in defining scope
}
fn one_const<const N: usize>(t: *mut [u8; N]) -> TwoConsts<N, N> {
- //~^ ERROR non-defining opaque type use in defining scope
t
+ //~^ ERROR non-defining opaque type use in defining scope
}
error: non-defining opaque type use in defining scope
- --> $DIR/generic_duplicate_param_use.rs:15:30
+ --> $DIR/generic_duplicate_param_use.rs:16:5
|
-LL | fn one_ty<T: Debug>(t: T) -> TwoTys<T, T> {
- | ^^^^^^^^^^^^
+LL | t
+ | ^
|
note: type used multiple times
--> $DIR/generic_duplicate_param_use.rs:8:13
LL | type TwoTys<T, U> = impl Debug;
| ^ ^
-error: could not find defining uses
- --> $DIR/generic_duplicate_param_use.rs:8:21
- |
-LL | type TwoTys<T, U> = impl Debug;
- | ^^^^^^^^^^
-
error: non-defining opaque type use in defining scope
- --> $DIR/generic_duplicate_param_use.rs:20:36
+ --> $DIR/generic_duplicate_param_use.rs:21:5
|
-LL | fn one_lifetime<'a>(t: &'a u32) -> TwoLifetimes<'a, 'a> {
- | ^^^^^^^^^^^^^^^^^^^^
+LL | t
+ | ^
|
note: lifetime used multiple times
--> $DIR/generic_duplicate_param_use.rs:10:19
LL | type TwoLifetimes<'a, 'b> = impl Debug;
| ^^ ^^
-error: could not find defining uses
- --> $DIR/generic_duplicate_param_use.rs:10:29
- |
-LL | type TwoLifetimes<'a, 'b> = impl Debug;
- | ^^^^^^^^^^
-
error: non-defining opaque type use in defining scope
- --> $DIR/generic_duplicate_param_use.rs:25:50
+ --> $DIR/generic_duplicate_param_use.rs:26:5
|
-LL | fn one_const<const N: usize>(t: *mut [u8; N]) -> TwoConsts<N, N> {
- | ^^^^^^^^^^^^^^^
+LL | t
+ | ^
|
note: constant used multiple times
--> $DIR/generic_duplicate_param_use.rs:12:22
LL | type TwoConsts<const X: usize, const Y: usize> = impl Debug;
| ^ ^
-error: could not find defining uses
- --> $DIR/generic_duplicate_param_use.rs:12:50
- |
-LL | type TwoConsts<const X: usize, const Y: usize> = impl Debug;
- | ^^^^^^^^^^
-
-error: aborting due to 6 previous errors
+error: aborting due to 3 previous errors
type Two<T, U> = impl Debug;
//~^ ERROR `T` doesn't implement `Debug`
-fn one<T: Debug>(t: T) -> Two<T, T> {
- //~^ ERROR non-defining opaque type use in defining scope
- t
-}
-
fn two<T: Debug, U>(t: T, _: U) -> Two<T, U> {
t
}
-error: non-defining opaque type use in defining scope
- --> $DIR/generic_duplicate_param_use2.rs:11:27
- |
-LL | fn one<T: Debug>(t: T) -> Two<T, T> {
- | ^^^^^^^^^
- |
-note: type used multiple times
- --> $DIR/generic_duplicate_param_use2.rs:8:10
- |
-LL | type Two<T, U> = impl Debug;
- | ^ ^
-
error[E0277]: `T` doesn't implement `Debug`
--> $DIR/generic_duplicate_param_use2.rs:8:18
|
LL | type Two<T: std::fmt::Debug, U> = impl Debug;
| +++++++++++++++++
-error: aborting due to 2 previous errors
+error: aborting due to previous error
For more information about this error, try `rustc --explain E0277`.
type Two<T, U> = impl Debug;
//~^ ERROR `T` doesn't implement `Debug`
-fn one<T: Debug>(t: T) -> Two<T, T> {
- //~^ ERROR non-defining opaque type use in defining scope
- t
-}
-
fn two<T: Debug, U>(t: T, _: U) -> Two<T, U> {
t
}
-error: non-defining opaque type use in defining scope
- --> $DIR/generic_duplicate_param_use3.rs:11:27
- |
-LL | fn one<T: Debug>(t: T) -> Two<T, T> {
- | ^^^^^^^^^
- |
-note: type used multiple times
- --> $DIR/generic_duplicate_param_use3.rs:8:10
- |
-LL | type Two<T, U> = impl Debug;
- | ^ ^
-
error: concrete type differs from previous defining opaque type use
- --> $DIR/generic_duplicate_param_use3.rs:20:1
+ --> $DIR/generic_duplicate_param_use3.rs:15:1
|
LL | fn three<T, U: Debug>(_: T, u: U) -> Two<T, U> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `T`, got `U`
|
note: previous use here
- --> $DIR/generic_duplicate_param_use3.rs:16:1
+ --> $DIR/generic_duplicate_param_use3.rs:11:1
|
LL | fn two<T: Debug, U>(t: T, _: U) -> Two<T, U> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | type Two<T: std::fmt::Debug, U> = impl Debug;
| +++++++++++++++++
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0277`.
type Two<T, U> = impl Debug;
//~^ ERROR `U` doesn't implement `Debug`
-fn one<T: Debug>(t: T) -> Two<T, T> {
- //~^ ERROR non-defining opaque type use in defining scope
- t
-}
-
fn three<T, U: Debug>(_: T, u: U) -> Two<T, U> {
u
}
-error: non-defining opaque type use in defining scope
- --> $DIR/generic_duplicate_param_use4.rs:11:27
- |
-LL | fn one<T: Debug>(t: T) -> Two<T, T> {
- | ^^^^^^^^^
- |
-note: type used multiple times
- --> $DIR/generic_duplicate_param_use4.rs:8:10
- |
-LL | type Two<T, U> = impl Debug;
- | ^ ^
-
error[E0277]: `U` doesn't implement `Debug`
--> $DIR/generic_duplicate_param_use4.rs:8:18
|
LL | type Two<T, U: std::fmt::Debug> = impl Debug;
| +++++++++++++++++
-error: aborting due to 2 previous errors
+error: aborting due to previous error
For more information about this error, try `rustc --explain E0277`.
fn main() {}
type OneTy<T> = impl Debug;
-//~^ ERROR could not find defining uses
+
type OneLifetime<'a> = impl Debug;
-//~^ ERROR could not find defining uses
+
type OneConst<const X: usize> = impl Debug;
-//~^ ERROR could not find defining uses
+
// Not defining uses, because they doesn't define *all* possible generics.
fn concrete_ty() -> OneTy<u32> {
- //~^ ERROR non-defining opaque type use in defining scope
5u32
+ //~^ ERROR non-defining opaque type use in defining scope
}
fn concrete_lifetime() -> OneLifetime<'static> {
- //~^ ERROR non-defining opaque type use in defining scope
6u32
+ //~^ ERROR non-defining opaque type use in defining scope
}
fn concrete_const() -> OneConst<{ 123 }> {
- //~^ ERROR non-defining opaque type use in defining scope
7u32
+ //~^ ERROR non-defining opaque type use in defining scope
}
error: non-defining opaque type use in defining scope
- --> $DIR/generic_nondefining_use.rs:16:21
+ --> $DIR/generic_nondefining_use.rs:17:5
|
-LL | fn concrete_ty() -> OneTy<u32> {
- | ^^^^^^^^^^
+LL | 5u32
+ | ^^^^
|
note: used non-generic type `u32` for generic parameter
--> $DIR/generic_nondefining_use.rs:7:12
LL | type OneTy<T> = impl Debug;
| ^
-error: could not find defining uses
- --> $DIR/generic_nondefining_use.rs:7:17
- |
-LL | type OneTy<T> = impl Debug;
- | ^^^^^^^^^^
-
error: non-defining opaque type use in defining scope
- --> $DIR/generic_nondefining_use.rs:21:27
+ --> $DIR/generic_nondefining_use.rs:22:5
|
LL | type OneLifetime<'a> = impl Debug;
| -- cannot use static lifetime; use a bound lifetime instead or remove the lifetime parameter from the opaque type
...
-LL | fn concrete_lifetime() -> OneLifetime<'static> {
- | ^^^^^^^^^^^^^^^^^^^^
-
-error: could not find defining uses
- --> $DIR/generic_nondefining_use.rs:9:24
- |
-LL | type OneLifetime<'a> = impl Debug;
- | ^^^^^^^^^^
+LL | 6u32
+ | ^^^^
error: non-defining opaque type use in defining scope
- --> $DIR/generic_nondefining_use.rs:26:24
+ --> $DIR/generic_nondefining_use.rs:27:5
|
-LL | fn concrete_const() -> OneConst<{ 123 }> {
- | ^^^^^^^^^^^^^^^^^
+LL | 7u32
+ | ^^^^
|
note: used non-generic constant `123_usize` for generic parameter
--> $DIR/generic_nondefining_use.rs:11:21
LL | type OneConst<const X: usize> = impl Debug;
| ^
-error: could not find defining uses
- --> $DIR/generic_nondefining_use.rs:11:33
- |
-LL | type OneConst<const X: usize> = impl Debug;
- | ^^^^^^^^^^
-
-error: aborting due to 6 previous errors
+error: aborting due to 3 previous errors
//~^ ERROR: at least one trait must be specified
fn wrong_generic<U: 'static, V: 'static>(_: U, v: V) -> WrongGeneric<U> {
- //~^ ERROR type parameter `V` is part of concrete type but not used in parameter list
v
+ //~^ ERROR type parameter `V` is part of concrete type but not used in parameter list
}
| ^^^^^^^^^^^^
error: type parameter `V` is part of concrete type but not used in parameter list for the `impl Trait` type alias
- --> $DIR/generic_not_used.rs:8:73
+ --> $DIR/generic_not_used.rs:9:5
|
-LL | fn wrong_generic<U: 'static, V: 'static>(_: U, v: V) -> WrongGeneric<U> {
- | _________________________________________________________________________^
-LL | |
-LL | | v
-LL | | }
- | |_^
+LL | v
+ | ^
error: aborting due to 2 previous errors
error: at least one trait must be specified
- --> $DIR/generic_type_does_not_live_long_enough.rs:9:24
+ --> $DIR/generic_type_does_not_live_long_enough.rs:10:24
|
LL | type WrongGeneric<T> = impl 'static;
| ^^^^^^^^^^^^
-error[E0308]: mismatched types
+error: non-defining opaque type use in defining scope
--> $DIR/generic_type_does_not_live_long_enough.rs:6:18
|
LL | let z: i32 = x;
- | --- ^ expected `i32`, found opaque type
- | |
- | expected due to this
-...
-LL | type WrongGeneric<T> = impl 'static;
- | ------------ the found opaque type
- |
- = note: expected type `i32`
- found opaque type `impl Sized`
-
-error[E0310]: the parameter type `T` may not live long enough
- --> $DIR/generic_type_does_not_live_long_enough.rs:12:30
+ | ^
|
-LL | fn wrong_generic<T>(t: T) -> WrongGeneric<T> {
- | ^^^^^^^^^^^^^^^
+note: used non-generic type `&'static i32` for generic parameter
+ --> $DIR/generic_type_does_not_live_long_enough.rs:10:19
|
- = help: consider adding an explicit lifetime bound `T: 'static`...
+LL | type WrongGeneric<T> = impl 'static;
+ | ^
error[E0310]: the parameter type `T` may not live long enough
- --> $DIR/generic_type_does_not_live_long_enough.rs:9:24
+ --> $DIR/generic_type_does_not_live_long_enough.rs:14:5
|
-LL | type WrongGeneric<T> = impl 'static;
- | ^^^^^^^^^^^^
+LL | t
+ | ^
|
= help: consider adding an explicit lifetime bound `T: 'static`...
- = note: ...so that the type `T` will meet its required lifetime bounds
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
-Some errors have detailed explanations: E0308, E0310.
-For more information about an error, try `rustc --explain E0308`.
+For more information about this error, try `rustc --explain E0310`.
fn main() {
let y = 42;
let x = wrong_generic(&y);
- let z: i32 = x; //~ ERROR mismatched types
+ let z: i32 = x;
+ //~^ ERROR non-defining opaque type use
}
type WrongGeneric<T> = impl 'static;
//~^ ERROR: at least one trait must be specified
fn wrong_generic<T>(t: T) -> WrongGeneric<T> {
- //~^ ERROR the parameter type `T` may not live long enough
t
+ //~^ ERROR the parameter type `T` may not live long enough
}
error: at least one trait must be specified
- --> $DIR/generic_type_does_not_live_long_enough.rs:9:24
+ --> $DIR/generic_type_does_not_live_long_enough.rs:10:24
|
LL | type WrongGeneric<T> = impl 'static;
| ^^^^^^^^^^^^
-error[E0308]: mismatched types
+error: non-defining opaque type use in defining scope
--> $DIR/generic_type_does_not_live_long_enough.rs:6:18
|
LL | let z: i32 = x;
- | --- ^ expected `i32`, found opaque type
- | |
- | expected due to this
-...
-LL | type WrongGeneric<T> = impl 'static;
- | ------------ the found opaque type
+ | ^
+ |
+note: used non-generic type `&'static i32` for generic parameter
+ --> $DIR/generic_type_does_not_live_long_enough.rs:10:19
|
- = note: expected type `i32`
- found opaque type `impl Sized`
+LL | type WrongGeneric<T> = impl 'static;
+ | ^
error[E0310]: the parameter type `T` may not live long enough
- --> $DIR/generic_type_does_not_live_long_enough.rs:12:30
+ --> $DIR/generic_type_does_not_live_long_enough.rs:14:5
|
LL | fn wrong_generic<T>(t: T) -> WrongGeneric<T> {
- | - ^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
- | |
- | help: consider adding an explicit lifetime bound...: `T: 'static`
+ | - help: consider adding an explicit lifetime bound...: `T: 'static`
+LL | t
+ | ^ ...so that the type `T` will meet its required lifetime bounds
error: aborting due to 3 previous errors
-Some errors have detailed explanations: E0308, E0310.
-For more information about an error, try `rustc --explain E0308`.
+For more information about this error, try `rustc --explain E0310`.
mod m {
type Foo = impl std::fmt::Debug;
- //~^ ERROR: cycle detected when computing type of `m::Foo::{opaque#0}` [E0391]
+ //~^ ERROR cycle detected
+ //~| ERROR cycle detected
// Cycle: error today, but it'd be nice if it eventually worked
fn baz() {
let f: Foo = 22_u32;
- //~^ ERROR: mismatched types [E0308]
}
fn is_send<T: Send>(_: T) {}
| ^^^^^^^^^^^^^^^^^^^^
|
note: ...which requires type-checking `m::bar`...
- --> $DIR/inference-cycle.rs:15:9
+ --> $DIR/inference-cycle.rs:15:5
|
-LL | is_send(foo()); // Today: error
- | ^^^^^^^
- = note: ...which requires evaluating trait selection obligation `impl core::fmt::Debug: core::marker::Send`...
+LL | pub fn bar() {
+ | ^^^^^^^^^^^^
= note: ...which again requires computing type of `m::Foo::{opaque#0}`, completing the cycle
note: cycle used when checking item types in module `m`
--> $DIR/inference-cycle.rs:4:1
LL | mod m {
| ^^^^^
-error[E0308]: mismatched types
- --> $DIR/inference-cycle.rs:19:22
+error[E0391]: cycle detected when computing type of `m::Foo::{opaque#0}`
+ --> $DIR/inference-cycle.rs:5:16
|
LL | type Foo = impl std::fmt::Debug;
- | -------------------- the expected opaque type
-...
-LL | let f: Foo = 22_u32;
- | --- ^^^^^^ expected opaque type, found `u32`
- | |
- | expected due to this
- |
- = note: expected opaque type `impl Debug`
- found type `u32`
+ | ^^^^^^^^^^^^^^^^^^^^
+ |
+note: ...which requires type-checking `m::bar`...
+ --> $DIR/inference-cycle.rs:15:5
+ |
+LL | pub fn bar() {
+ | ^^^^^^^^^^^^
+ = note: ...which again requires computing type of `m::Foo::{opaque#0}`, completing the cycle
+note: cycle used when checking item types in module `m`
+ --> $DIR/inference-cycle.rs:4:1
+ |
+LL | mod m {
+ | ^^^^^
error: aborting due to 2 previous errors
-Some errors have detailed explanations: E0308, E0391.
-For more information about an error, try `rustc --explain E0308`.
+For more information about this error, try `rustc --explain E0391`.
type Item = impl Debug;
fn foo<T: Debug>(_: T) -> Self::Item {
- //~^ Error type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias
S::<T>(Default::default())
+ //~^ Error type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias
}
}
error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias
- --> $DIR/issue-53598.rs:20:42
+ --> $DIR/issue-53598.rs:21:9
|
-LL | fn foo<T: Debug>(_: T) -> Self::Item {
- | __________________________________________^
-LL | |
-LL | | S::<T>(Default::default())
-LL | | }
- | |_____^
+LL | S::<T>(Default::default())
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error
error: higher-ranked subtype error
- --> $DIR/issue-57611-trait-alias.rs:21:9
+ --> $DIR/issue-57611-trait-alias.rs:20:9
|
LL | |x| x
| ^^^^^
error: higher-ranked subtype error
- --> $DIR/issue-57611-trait-alias.rs:21:9
+ --> $DIR/issue-57611-trait-alias.rs:20:9
|
LL | |x| x
| ^^^^^
-error[E0308]: mismatched types
- --> $DIR/issue-57611-trait-alias.rs:17:16
- |
-LL | type Bar = impl Baz<Self, Self>;
- | ^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
- |
- = note: expected type `for<'r> Fn<(&'r X,)>`
- found type `Fn<(&'static X,)>`
-note: this closure does not fulfill the lifetime requirements
- --> $DIR/issue-57611-trait-alias.rs:21:9
- |
-LL | |x| x
- | ^^^^^
-
-error: implementation of `FnOnce` is not general enough
- --> $DIR/issue-57611-trait-alias.rs:17:16
- |
-LL | type Bar = impl Baz<Self, Self>;
- | ^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough
- |
- = note: closure with signature `fn(&'static X) -> &'static X` must implement `FnOnce<(&'0 X,)>`, for any lifetime `'0`...
- = note: ...but it actually implements `FnOnce<(&'static X,)>`
-
-error: aborting due to 4 previous errors
+error: aborting due to 2 previous errors
-For more information about this error, try `rustc --explain E0308`.
type Bar = impl Baz<Self, Self>;
fn bar(&self) -> Self::Bar {
- //~^ ERROR implementation of `FnOnce` is not general enough
|x| x
+ //~^ ERROR implementation of `FnOnce` is not general enough
}
}
error: implementation of `FnOnce` is not general enough
- --> $DIR/issue-57611-trait-alias.rs:19:22
+ --> $DIR/issue-57611-trait-alias.rs:20:9
|
-LL | fn bar(&self) -> Self::Bar {
- | ^^^^^^^^^ implementation of `FnOnce` is not general enough
+LL | |x| x
+ | ^^^^^ implementation of `FnOnce` is not general enough
|
= note: closure with signature `fn(&'2 X) -> &X` must implement `FnOnce<(&'1 X,)>`, for any lifetime `'1`...
= note: ...but it actually implements `FnOnce<(&'2 X,)>`, for some specific lifetime `'2`
type Bar = impl Foo;
fn foo(self: impl Deref<Target = Self>) -> Self::Bar {
- //~^ Error type parameter `impl Deref<Target = Self>` is part of concrete type but not used in parameter list for the `impl Trait` type alias
self
+ //~^ Error type parameter `impl Deref<Target = Self>` is part of concrete type but not used in parameter list for the `impl Trait` type alias
}
}
error: type parameter `impl Deref<Target = Self>` is part of concrete type but not used in parameter list for the `impl Trait` type alias
- --> $DIR/issue-57700.rs:16:58
+ --> $DIR/issue-57700.rs:17:9
|
-LL | fn foo(self: impl Deref<Target = Self>) -> Self::Bar {
- | __________________________________________________________^
-LL | |
-LL | | self
-LL | | }
- | |_____^
+LL | self
+ | ^^^^
error: aborting due to previous error
--- /dev/null
+// check-pass
+
+#![feature(type_alias_impl_trait)]
+
+mod defining_use_scope {
+ pub type A = impl Iterator;
+
+ pub fn def_a() -> A {
+ 0..1
+ }
+}
+use defining_use_scope::*;
+
+pub fn use_a() {
+ def_a().map(|x| x);
+}
+
+fn main() {}
const FUN: fn() -> Self::Item = || ();
//~^ ERROR the trait bound `(): Bug` is not satisfied
- //~| ERROR non-defining opaque type use in defining scope
}
fn main() {}
--> $DIR/issue-60371.rs:12:40
|
LL | const FUN: fn() -> Self::Item = || ();
- | ^ the trait `Bug` is not implemented for `()`
+ | ^^ the trait `Bug` is not implemented for `()`
|
= help: the following implementations were found:
<&() as Bug>
-error: non-defining opaque type use in defining scope
- --> $DIR/issue-60371.rs:12:37
- |
-LL | impl Bug for &() {
- | - cannot use static lifetime; use a bound lifetime instead or remove the lifetime parameter from the opaque type
-...
-LL | const FUN: fn() -> Self::Item = || ();
- | ^^^^^
-
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
Some errors have detailed explanations: E0277, E0658.
For more information about an error, try `rustc --explain E0277`.
}
type IterBitsIter<T, E, I> = impl std::iter::Iterator<Item = I>;
-//~^ ERROR could not find defining uses
impl<T: Copy, E> IterBits for T
where
{
type BitsIter = IterBitsIter<T, E, u8>;
fn iter_bits(self, n: u8) -> Self::BitsIter {
- //~^ ERROR non-defining opaque type use in defining scope
(0u8..n).rev().map(move |shift| ((self >> T::from(shift)) & T::from(1)).try_into().unwrap())
+ //~^ ERROR non-defining opaque type use in defining scope
}
}
error: non-defining opaque type use in defining scope
- --> $DIR/issue-60564.rs:20:34
+ --> $DIR/issue-60564.rs:20:9
|
-LL | fn iter_bits(self, n: u8) -> Self::BitsIter {
- | ^^^^^^^^^^^^^^
+LL | (0u8..n).rev().map(move |shift| ((self >> T::from(shift)) & T::from(1)).try_into().unwrap())
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: used non-generic type `u8` for generic parameter
--> $DIR/issue-60564.rs:8:25
LL | type IterBitsIter<T, E, I> = impl std::iter::Iterator<Item = I>;
| ^
-error: could not find defining uses
- --> $DIR/issue-60564.rs:8:30
- |
-LL | type IterBitsIter<T, E, I> = impl std::iter::Iterator<Item = I>;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
type Closure = impl FnOnce();
fn c() -> Closure {
- || -> Closure { || () } //~ ERROR: mismatched types
+ || -> Closure { || () }
+ //~^ ERROR: mismatched types
+ //~| ERROR: mismatched types
+ //~| ERROR: expected a `FnOnce<()>` closure, found `()`
}
fn main() {}
+error[E0277]: expected a `FnOnce<()>` closure, found `()`
+ --> $DIR/issue-63279.rs:8:11
+ |
+LL | || -> Closure { || () }
+ | ^^^^^^^ expected an `FnOnce<()>` closure, found `()`
+ |
+ = help: the trait `FnOnce<()>` is not implemented for `()`
+ = note: wrap the `()` in a closure with no arguments: `|| { /* code */ }`
+
+error[E0308]: mismatched types
+ --> $DIR/issue-63279.rs:8:21
+ |
+LL | || -> Closure { || () }
+ | ^^^^^ expected `()`, found closure
+ |
+ = note: expected unit type `()`
+ found closure `[closure@$DIR/issue-63279.rs:8:21: 8:26]`
+
error[E0308]: mismatched types
--> $DIR/issue-63279.rs:8:5
|
LL | type Closure = impl FnOnce();
- | ------------- the found opaque type
+ | ------------- the expected opaque type
...
LL | || -> Closure { || () }
- | ^^^^^^^^^^^^^^^^^^^^^^^ expected closure, found a different closure
+ | ^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found closure
|
- = note: expected type `[closure@$DIR/issue-63279.rs:8:21: 8:26]`
- found closure `[closure@$DIR/issue-63279.rs:8:5: 8:28]`
- = note: no two closures, even if identical, have the same type
- = help: consider boxing your closure and/or using it as a trait object
+ = note: expected opaque type `Closure`
+ found closure `[closure@$DIR/issue-63279.rs:8:5: 8:28]`
-error: aborting due to previous error
+error: aborting due to 3 previous errors
-For more information about this error, try `rustc --explain E0308`.
+Some errors have detailed explanations: E0277, E0308.
+For more information about an error, try `rustc --explain E0277`.
#![feature(type_alias_impl_trait)]
-#![feature(type_alias_impl_trait)]
-#![allow(incomplete_features)]
+// check-pass
pub trait Foo {}
}
}
-// FIXME(#86731): The below is illegal use of `type_alias_impl_trait`
-// but the compiler doesn't report it, we should fix it.
pub type FooImpl = impl Foo;
pub type BarImpl = impl Bar<Foo = FooImpl>;
-//~^ ERROR: type mismatch resolving `<() as Bar>::Foo == ()`
impl Baz for () {
type Foo = FooImpl;
+++ /dev/null
-error[E0271]: type mismatch resolving `<() as Bar>::Foo == ()`
- --> $DIR/issue-63355.rs:34:20
- |
-LL | pub type FooImpl = impl Foo;
- | -------- the found opaque type
-LL | pub type BarImpl = impl Bar<Foo = FooImpl>;
- | ^^^^^^^^^^^^^^^^^^^^^^^ type mismatch resolving `<() as Bar>::Foo == ()`
- |
-note: expected this to be `()`
- --> $DIR/issue-63355.rs:24:16
- |
-LL | type Foo = FooImpl;
- | ^^^^^^^
- = note: expected unit type `()`
- found opaque type `impl Foo`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0271`.
#![feature(type_alias_impl_trait)]
trait Trait<T> {}
type Alias<'a, U> = impl Trait<U>;
-//~^ ERROR could not find defining uses
+
fn f<'a>() -> Alias<'a, ()> {}
//~^ ERROR non-defining opaque type use in defining scope
error: non-defining opaque type use in defining scope
- --> $DIR/issue-68368-non-defining-use-2.rs:9:15
+ --> $DIR/issue-68368-non-defining-use-2.rs:9:29
|
LL | fn f<'a>() -> Alias<'a, ()> {}
- | ^^^^^^^^^^^^^
+ | ^^
|
note: used non-generic type `()` for generic parameter
--> $DIR/issue-68368-non-defining-use-2.rs:7:16
LL | type Alias<'a, U> = impl Trait<U>;
| ^
-error: could not find defining uses
- --> $DIR/issue-68368-non-defining-use-2.rs:7:21
- |
-LL | type Alias<'a, U> = impl Trait<U>;
- | ^^^^^^^^^^^^^
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
#![feature(type_alias_impl_trait)]
trait Trait<T> {}
type Alias<'a, U> = impl Trait<U>;
-//~^ ERROR could not find defining uses
+
fn f<'a>() -> Alias<'a, ()> {}
//~^ ERROR non-defining opaque type use in defining scope
error: non-defining opaque type use in defining scope
- --> $DIR/issue-68368-non-defining-use.rs:9:15
+ --> $DIR/issue-68368-non-defining-use.rs:9:29
|
LL | fn f<'a>() -> Alias<'a, ()> {}
- | ^^^^^^^^^^^^^
+ | ^^
|
note: used non-generic type `()` for generic parameter
--> $DIR/issue-68368-non-defining-use.rs:7:16
LL | type Alias<'a, U> = impl Trait<U>;
| ^
-error: could not find defining uses
- --> $DIR/issue-68368-non-defining-use.rs:7:21
- |
-LL | type Alias<'a, U> = impl Trait<U>;
- | ^^^^^^^^^^^^^
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
error[E0308]: mismatched types
--> $DIR/issue-74280.rs:9:5
|
+LL | type Test = impl Copy;
+ | --------- the expected opaque type
+...
LL | 7
| ^ expected `()`, found integer
+ |
+ = note: expected opaque type `Test`
+ found type `{integer}`
error: aborting due to previous error
| --------^-
| | |
| | not allowed in type signatures
- | help: replace with the correct return type: `Box<i32>`
+ | help: replace with the correct return type: `Pointer<i32>`
error: aborting due to previous error
--> $DIR/issue-89686.rs:7:17
|
LL | type G<'a, T> = impl Future<Output = ()>;
- | ^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found associated type
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ expected associated type, found `()`
...
LL | async move { self.f().await }
- | ------------------ the found `async` block
+ | ------------------ the expected `async` block
|
::: $SRC_DIR/core/src/future/mod.rs:LL:COL
|
LL | pub const fn from_generator<T>(gen: T) -> impl Future<Output = T::Return>
- | ------------------------------- the found opaque type
+ | ------------------------------- the expected opaque type
|
- = note: expected unit type `()`
- found associated type `<impl Future<Output = [async output]> as Future>::Output`
+ = note: expected associated type `<impl Future<Output = [async output]> as Future>::Output`
+ found unit type `()`
= help: consider constraining the associated type `<impl Future<Output = [async output]> as Future>::Output` to `()`
= note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
--- /dev/null
+#![feature(type_alias_impl_trait)]
+
+// this test used to stack overflow due to infinite recursion.
+// check-pass
+// compile-flags: --edition=2018
+
+use std::future::Future;
+
+fn main() {
+ let _ = move || async move {
+ let value = 0u8;
+ blah(&value).await;
+ };
+}
+
+type BlahFut<'a> = impl Future<Output = ()> + Send + 'a;
+fn blah<'a>(_value: &'a u8) -> BlahFut<'a> {
+ async {}
+}
--- /dev/null
+// https://github.com/rust-lang/rust/issues/73481
+// This test used to cause unsoundness, since one of the two possible
+// resolutions was chosen at random instead of erroring due to conflicts.
+
+#![feature(type_alias_impl_trait)]
+
+type Y<A, B> = impl std::fmt::Debug;
+
+fn g<A, B>() -> (Y<A, B>, Y<B, A>) {
+ (42_i64, 60) //~^ ERROR concrete type differs from previous defining opaque type use
+}
+
+fn main() {}
--- /dev/null
+error: concrete type differs from previous defining opaque type use
+ --> $DIR/multiple-def-uses-in-one-fn-infer.rs:9:1
+ |
+LL | fn g<A, B>() -> (Y<A, B>, Y<B, A>) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `i64`, got `i32`
+ |
+note: previous use here
+ --> $DIR/multiple-def-uses-in-one-fn-infer.rs:9:1
+ |
+LL | fn g<A, B>() -> (Y<A, B>, Y<B, A>) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
--- /dev/null
+#![feature(type_alias_impl_trait)]
+
+type Foo<'a, 'b> = impl std::fmt::Debug;
+
+fn foo<'x, 'y>(i: &'x i32, j: &'y i32) -> (Foo<'x, 'y>, Foo<'y, 'x>) {
+ (i, i) //~^ ERROR concrete type differs from previous
+}
+
+fn main() {}
--- /dev/null
+error: concrete type differs from previous defining opaque type use
+ --> $DIR/multiple-def-uses-in-one-fn-lifetimes.rs:5:1
+ |
+LL | fn foo<'x, 'y>(i: &'x i32, j: &'y i32) -> (Foo<'x, 'y>, Foo<'y, 'x>) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `&'a i32`, got `&'b i32`
+ |
+note: previous use here
+ --> $DIR/multiple-def-uses-in-one-fn-lifetimes.rs:5:1
+ |
+LL | fn foo<'x, 'y>(i: &'x i32, j: &'y i32) -> (Foo<'x, 'y>, Foo<'y, 'x>) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
(a.clone(), a)
}
+type Foo<'a, 'b> = impl std::fmt::Debug;
+
+fn foo<'x, 'y>(i: &'x i32, j: &'y i32) -> (Foo<'x, 'y>, Foo<'y, 'x>) {
+ (i, j)
+}
+
fn main() {
println!("{}", <X<_, _> as ToString>::to_string(&f(42_i32, String::new()).1));
+ let meh = 42;
+ let muh = 69;
+ println!("{:?}", foo(&meh, &muh));
}
type X<A, B> = impl Into<&'static A>;
fn f<A, B: 'static>(a: &'static A, b: B) -> (X<A, B>, X<B, A>) {
- //~^ ERROR the trait bound `&'static B: From<&A>` is not satisfied
(a, a)
+ //~^ ERROR the trait bound `&'static B: From<&A>` is not satisfied
}
fn main() {
error[E0277]: the trait bound `&'static B: From<&A>` is not satisfied
- --> $DIR/multiple-def-uses-in-one-fn.rs:9:45
+ --> $DIR/multiple-def-uses-in-one-fn.rs:10:9
|
-LL | fn f<A, B: 'static>(a: &'static A, b: B) -> (X<A, B>, X<B, A>) {
- | ^^^^^^^^^^^^^^^^^^ the trait `From<&A>` is not implemented for `&'static B`
+LL | (a, a)
+ | ^ the trait `From<&A>` is not implemented for `&'static B`
|
= note: required because of the requirements on the impl of `Into<&'static B>` for `&A`
help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement
error[E0308]: mismatched types
--> $DIR/multiple-def-uses-in-one-fn3.rs:14:9
|
+LL | type X<A: ToString + Clone, B: ToString + Clone> = impl ToString;
+ | ------------- the expected opaque type
+...
LL | fn g<A: ToString + Clone, B: ToString + Clone>(a: A, b: B) -> (X<A, B>, X<A, B>) {
| - - found type parameter
| |
LL | (a, b)
| ^ expected type parameter `A`, found type parameter `B`
|
- = note: expected type parameter `A`
- found type parameter `B`
+ = note: expected opaque type `X<A, B>`
+ found type parameter `B`
= note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound
= note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
-// check-pass
-
#![feature(type_alias_impl_trait)]
#![allow(dead_code)]
impl Foo<()> for () { }
fn foo() -> impl Foo<FooX> {
+ // FIXME(type-alias-impl-trait): We could probably make this work.
()
+ //~^ ERROR: the trait bound `(): Foo<FooX>` is not satisfied
}
fn main() { }
--- /dev/null
+error[E0277]: the trait bound `(): Foo<FooX>` is not satisfied
+ --> $DIR/nested-tait-inference.rs:14:5
+ |
+LL | ()
+ | ^^ the trait `Foo<FooX>` is not implemented for `()`
+ |
+ = help: the following implementations were found:
+ <() as Foo<()>>
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
use std::fmt::Debug;
type FooX = impl Debug;
-//~^ ERROR: could not find defining uses
trait Foo<A> {}
impl Foo<u32> for () {}
fn foo() -> impl Foo<FooX> {
- //~^ ERROR: the trait bound `(): Foo<impl Debug>` is not satisfied [E0277]
()
+ //~^ ERROR: the trait bound `(): Foo<FooX>` is not satisfied
}
fn main() {}
-error[E0277]: the trait bound `(): Foo<impl Debug>` is not satisfied
- --> $DIR/nested-tait-inference2.rs:14:13
+error[E0277]: the trait bound `(): Foo<FooX>` is not satisfied
+ --> $DIR/nested-tait-inference2.rs:14:5
|
-LL | fn foo() -> impl Foo<FooX> {
- | ^^^^^^^^^^^^^^ the trait `Foo<impl Debug>` is not implemented for `()`
+LL | ()
+ | ^^ the trait `Foo<FooX>` is not implemented for `()`
|
= help: the following implementations were found:
<() as Foo<()>>
<() as Foo<u32>>
-error: could not find defining uses
- --> $DIR/nested-tait-inference2.rs:6:13
- |
-LL | type FooX = impl Debug;
- | ^^^^^^^^^^
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+#![feature(type_alias_impl_trait)]
+#![allow(dead_code)]
+
+use std::fmt::Debug;
+
+type FooX = impl Debug;
+//~^ unconstrained opaque type
+
+trait Foo<A> { }
+
+impl Foo<FooX> for () { }
+
+fn foo() -> impl Foo<FooX> {
+ ()
+}
+
+fn main() { }
--- /dev/null
+error: unconstrained opaque type
+ --> $DIR/nested-tait-inference3.rs:6:13
+ |
+LL | type FooX = impl Debug;
+ | ^^^^^^^^^^
+ |
+ = note: `FooX` must be used in combination with a concrete type within the same module
+
+error: aborting due to previous error
+
--- /dev/null
+#![feature(type_alias_impl_trait)]
+
+type Foo = impl std::fmt::Debug;
+type Bar = impl Trait<Foo>;
+
+trait Trait<T> {}
+
+impl<T, U> Trait<T> for U {}
+
+fn bar() -> Bar {
+ 42
+}
+
+fn main() {
+ println!("{:?}", bar());
+ //~^ ERROR `Bar` doesn't implement `Debug`
+}
--- /dev/null
+error[E0277]: `Bar` doesn't implement `Debug`
+ --> $DIR/nested.rs:15:22
+ |
+LL | println!("{:?}", bar());
+ | ^^^^^ `Bar` cannot be formatted using `{:?}` because it doesn't implement `Debug`
+ |
+ = help: the trait `Debug` is not implemented for `Bar`
+ = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
#![feature(type_alias_impl_trait)]
-// build-pass (FIXME(62277): could be check-pass?)
+
mod my_mod {
use std::fmt::Debug;
}
pub fn get_foot() -> Foot {
- get_foo()
+ get_foo() //~ ERROR opaque type's hidden type cannot be another opaque type
}
}
--- /dev/null
+error: opaque type's hidden type cannot be another opaque type from the same scope
+ --> $DIR/nested_type_alias_impl_trait.rs:14:9
+ |
+LL | get_foo()
+ | ^^^^^^^^^ one of the two opaque types used here has to be outside its defining scope
+ |
+note: opaque type whose hidden type is being assigned
+ --> $DIR/nested_type_alias_impl_trait.rs:7:21
+ |
+LL | pub type Foot = impl Debug;
+ | ^^^^^^^^^^
+note: opaque type being used as hidden type
+ --> $DIR/nested_type_alias_impl_trait.rs:6:20
+ |
+LL | pub type Foo = impl Debug;
+ | ^^^^^^^^^^
+
+error: aborting due to previous error
+
#![feature(type_alias_impl_trait)]
-
+// check-pass
fn main() {}
-// don't reveal the concrete type
type NoReveal = impl std::fmt::Debug;
fn define_no_reveal() -> NoReveal {
}
fn no_reveal(x: NoReveal) {
- let _: &'static str = x; //~ mismatched types
- let _ = x as &'static str; //~ non-primitive cast
+ let _: &'static str = x;
+ let _ = x as &'static str;
}
+++ /dev/null
-error[E0308]: mismatched types
- --> $DIR/never_reveal_concrete_type.rs:13:27
- |
-LL | type NoReveal = impl std::fmt::Debug;
- | -------------------- the found opaque type
-...
-LL | let _: &'static str = x;
- | ------------ ^ expected `&str`, found opaque type
- | |
- | expected due to this
- |
- = note: expected reference `&'static str`
- found opaque type `impl Debug`
-
-error[E0605]: non-primitive cast: `impl Debug` as `&'static str`
- --> $DIR/never_reveal_concrete_type.rs:14:13
- |
-LL | let _ = x as &'static str;
- | ^^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
-
-error: aborting due to 2 previous errors
-
-Some errors have detailed explanations: E0308, E0605.
-For more information about an error, try `rustc --explain E0308`.
// Issue 52985: user code provides no use case that allows a type alias `impl Trait`
-// We now emit a 'could not find defining uses' error
+// We now emit a 'unconstrained opaque type' error
#![feature(type_alias_impl_trait)]
-type Foo = impl Copy; //~ could not find defining uses
+type Foo = impl Copy; //~ unconstrained opaque type
// make compiler happy about using 'Foo'
fn bar(x: Foo) -> Foo {
-error: could not find defining uses
+error: unconstrained opaque type
--> $DIR/no_inferrable_concrete_type.rs:6:12
|
LL | type Foo = impl Copy;
| ^^^^^^^^^
+ |
+ = note: `Foo` must be used in combination with a concrete type within the same module
error: aborting due to previous error
| ---------------------- the found opaque type
...
LL | let _: &str = bomp();
- | ---- ^^^^^^ expected `&str`, found opaque type
- | |
- | expected due to this
+ | ^^^^^^ expected `&str`, found opaque type
|
= note: expected reference `&str`
- found opaque type `impl Debug`
+ found opaque type `Boo`
error[E0308]: mismatched types
--> $DIR/no_revealing_outside_defining_module.rs:19:5
LL | pub type Boo = impl ::std::fmt::Debug;
| ---------------------- the expected opaque type
...
-LL | fn bomp() -> boo::Boo {
- | -------- expected `impl Debug` because of return type
LL | ""
| ^^ expected opaque type, found `&str`
|
- = note: expected opaque type `impl Debug`
- found reference `&'static str`
+ = note: expected opaque type `Boo`
+ found reference `&str`
error: aborting due to 2 previous errors
type Two<T, U> = impl Debug;
//~^ ERROR `T` doesn't implement `Debug`
-fn two<T: Debug>(t: T) -> Two<T, u32> {
- //~^ ERROR non-defining opaque type use in defining scope
- (t, 4i8)
-}
-
fn three<T: Debug, U>(t: T) -> Two<T, U> {
(t, 5i8)
}
-error: non-defining opaque type use in defining scope
- --> $DIR/not_a_defining_use.rs:10:27
- |
-LL | fn two<T: Debug>(t: T) -> Two<T, u32> {
- | ^^^^^^^^^^^
- |
-note: used non-generic type `u32` for generic parameter
- --> $DIR/not_a_defining_use.rs:7:13
- |
-LL | type Two<T, U> = impl Debug;
- | ^
-
error: concrete type differs from previous defining opaque type use
- --> $DIR/not_a_defining_use.rs:29:1
+ --> $DIR/not_a_defining_use.rs:24:1
|
LL | fn four<T: Debug, U: Bar>(t: T) -> Two<T, U> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `(T, i8)`, got `(T, <U as Bar>::Blub)`
|
note: previous use here
- --> $DIR/not_a_defining_use.rs:15:1
+ --> $DIR/not_a_defining_use.rs:10:1
|
LL | fn three<T: Debug, U>(t: T) -> Two<T, U> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | type Two<T: std::fmt::Debug, U> = impl Debug;
| +++++++++++++++++
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+#![feature(type_alias_impl_trait)]
+
+type Foo = impl std::fmt::Debug;
+type Bar = impl PartialEq<Foo>;
+
+fn bar() -> Bar {
+ 42_i32 //~ ERROR can't compare `i32` with `Foo`
+}
+
+fn main() {}
--- /dev/null
+error[E0277]: can't compare `i32` with `Foo`
+ --> $DIR/self-referential-2.rs:7:5
+ |
+LL | 42_i32
+ | ^^^^^^ no implementation for `i32 == Foo`
+ |
+ = help: the trait `PartialEq<Foo>` is not implemented for `i32`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+// run-pass
+#![feature(type_alias_impl_trait)]
+
+type Bar<'a, 'b> = impl PartialEq<Bar<'a, 'b>> + std::fmt::Debug;
+
+fn bar<'a, 'b>(i: &'a i32) -> Bar<'a, 'b> {
+ i
+}
+
+fn main() {
+ let meh = 42;
+ let muh = 42;
+ assert_eq!(bar(&meh), bar(&muh));
+}
--- /dev/null
+#![feature(type_alias_impl_trait)]
+
+type Bar<'a, 'b> = impl PartialEq<Bar<'b, 'static>> + std::fmt::Debug;
+
+fn bar<'a, 'b>(i: &'a i32) -> Bar<'a, 'b> {
+ i //~ ERROR can't compare `&i32` with `Bar<'b, 'static>`
+}
+
+type Foo<'a, 'b> = impl PartialEq<Foo<'static, 'b>> + std::fmt::Debug;
+
+fn foo<'a, 'b>(i: &'a i32) -> Foo<'a, 'b> {
+ i //~ ERROR can't compare `&i32` with `Foo<'static, 'b>`
+}
+
+type Moo<'a, 'b> = impl PartialEq<Moo<'static, 'a>> + std::fmt::Debug;
+
+fn moo<'a, 'b>(i: &'a i32) -> Moo<'a, 'b> {
+ i //~ ERROR can't compare `&i32` with `Moo<'static, 'a>`
+}
+
+fn main() {
+ let meh = 42;
+ let muh = 69;
+ assert_eq!(bar(&meh), bar(&meh));
+}
--- /dev/null
+error[E0277]: can't compare `&i32` with `Bar<'b, 'static>`
+ --> $DIR/self-referential-4.rs:6:5
+ |
+LL | i
+ | ^ no implementation for `&i32 == Bar<'b, 'static>`
+ |
+ = help: the trait `PartialEq<Bar<'b, 'static>>` is not implemented for `&i32`
+
+error[E0277]: can't compare `&i32` with `Foo<'static, 'b>`
+ --> $DIR/self-referential-4.rs:12:5
+ |
+LL | i
+ | ^ no implementation for `&i32 == Foo<'static, 'b>`
+ |
+ = help: the trait `PartialEq<Foo<'static, 'b>>` is not implemented for `&i32`
+
+error[E0277]: can't compare `&i32` with `Moo<'static, 'a>`
+ --> $DIR/self-referential-4.rs:18:5
+ |
+LL | i
+ | ^ no implementation for `&i32 == Moo<'static, 'a>`
+ |
+ = help: the trait `PartialEq<Moo<'static, 'a>>` is not implemented for `&i32`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+#![feature(type_alias_impl_trait)]
+
+type Bar<'a, 'b> = impl PartialEq<Bar<'b, 'a>> + std::fmt::Debug;
+
+fn bar<'a, 'b>(i: &'a i32) -> Bar<'a, 'b> {
+ i //~ ERROR can't compare `&i32` with `Bar<'b, 'a>`
+}
+
+type Foo<'a, 'b> = (i32, impl PartialEq<Foo<'a, 'b>> + std::fmt::Debug);
+
+fn foo<'a, 'b>(i: &'a i32) -> Foo<'a, 'b> {
+ (42, i) //~ ERROR can't compare `&i32` with `(i32, &i32)`
+}
+
+type Moo<'a, 'b> = (i32, impl PartialEq<Moo<'b, 'a>> + std::fmt::Debug);
+
+fn moo<'a, 'b>(i: &'a i32) -> Moo<'a, 'b> {
+ (42, i) //~ ERROR can't compare `&i32` with `(i32, Moo<'b, 'a>::{opaque#0})`
+}
+
+fn main() {
+ let meh = 42;
+ let muh = 69;
+ assert_eq!(bar(&meh), bar(&meh));
+}
--- /dev/null
+error[E0277]: can't compare `&i32` with `Bar<'b, 'a>`
+ --> $DIR/self-referential.rs:6:5
+ |
+LL | i
+ | ^ no implementation for `&i32 == Bar<'b, 'a>`
+ |
+ = help: the trait `PartialEq<Bar<'b, 'a>>` is not implemented for `&i32`
+
+error[E0277]: can't compare `&i32` with `(i32, &i32)`
+ --> $DIR/self-referential.rs:12:10
+ |
+LL | (42, i)
+ | ^ no implementation for `&i32 == (i32, &i32)`
+ |
+ = help: the trait `PartialEq<(i32, &i32)>` is not implemented for `&i32`
+
+error[E0277]: can't compare `&i32` with `(i32, Moo<'b, 'a>::{opaque#0})`
+ --> $DIR/self-referential.rs:18:10
+ |
+LL | (42, i)
+ | ^ no implementation for `&i32 == (i32, Moo<'b, 'a>::{opaque#0})`
+ |
+ = help: the trait `PartialEq<(i32, Moo<'b, 'a>::{opaque#0})>` is not implemented for `&i32`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
#![feature(type_alias_impl_trait)]
#![allow(dead_code)]
-// FIXME: This should compile, but it currently doesn't
+// check-pass
use std::fmt::Debug;
-type Foo = impl Debug; //~ ERROR could not find defining uses
+type Foo = impl Debug;
-static FOO1: Foo = 22_u32; //~ ERROR mismatched types
-const FOO2: Foo = 22_u32; //~ ERROR mismatched types
+static FOO1: Foo = 22_u32;
+const FOO2: Foo = 22_u32;
fn main() {}
+++ /dev/null
-error[E0308]: mismatched types
- --> $DIR/static-const-types.rs:10:20
- |
-LL | type Foo = impl Debug;
- | ---------- the expected opaque type
-LL |
-LL | static FOO1: Foo = 22_u32;
- | ^^^^^^ expected opaque type, found `u32`
- |
- = note: expected opaque type `impl Debug`
- found type `u32`
-
-error[E0308]: mismatched types
- --> $DIR/static-const-types.rs:11:19
- |
-LL | type Foo = impl Debug;
- | ---------- the expected opaque type
-...
-LL | const FOO2: Foo = 22_u32;
- | ^^^^^^ expected opaque type, found `u32`
- |
- = note: expected opaque type `impl Debug`
- found type `u32`
-
-error: could not find defining uses
- --> $DIR/static-const-types.rs:8:12
- |
-LL | type Foo = impl Debug;
- | ^^^^^^^^^^
-
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0308`.
const LEAK_FREE: Bar = leak_free();
fn leak_free_test() {
- match todo!() {
+ match LEAK_FREE {
LEAK_FREE => (),
- //~^ `impl Send` cannot be used in patterns
+ //~^ `Bar` cannot be used in patterns
_ => (),
}
}
-error: `impl Send` cannot be used in patterns
+error: `Bar` cannot be used in patterns
--> $DIR/structural-match-no-leak.rs:15:9
|
LL | LEAK_FREE => (),
const VALUE: Foo = value();
fn test() {
- match todo!() {
+ match VALUE {
VALUE => (),
- //~^ `impl Send` cannot be used in patterns
+ //~^ `Foo` cannot be used in patterns
_ => (),
}
}
-error: `impl Send` cannot be used in patterns
+error: `Foo` cannot be used in patterns
--> $DIR/structural-match.rs:16:9
|
LL | VALUE => (),
#![feature(type_alias_impl_trait)]
-
+// check-pass
// Ensures that `const` items can constrain an opaque `impl Trait`.
use std::fmt::Debug;
pub type Foo = impl Debug;
-//~^ ERROR could not find defining uses
const _FOO: Foo = 5;
-//~^ ERROR mismatched types [E0308]
fn main() {}
+++ /dev/null
-error[E0308]: mismatched types
- --> $DIR/type-alias-impl-trait-const.rs:10:19
- |
-LL | pub type Foo = impl Debug;
- | ---------- the expected opaque type
-...
-LL | const _FOO: Foo = 5;
- | ^ expected opaque type, found integer
- |
- = note: expected opaque type `impl Debug`
- found type `{integer}`
-
-error: could not find defining uses
- --> $DIR/type-alias-impl-trait-const.rs:7:16
- |
-LL | pub type Foo = impl Debug;
- | ^^^^^^^^^^
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0308`.
#![feature(type_alias_impl_trait)]
type Foo = impl Fn() -> Foo;
-//~^ ERROR: could not find defining uses
+//~^ ERROR: unconstrained opaque type
fn crash(x: Foo) -> Foo {
x
-error: could not find defining uses
+error: unconstrained opaque type
--> $DIR/type-alias-impl-trait-with-cycle-error.rs:3:12
|
LL | type Foo = impl Fn() -> Foo;
| ^^^^^^^^^^^^^^^^
+ |
+ = note: `Foo` must be used in combination with a concrete type within the same module
error: aborting due to previous error
}
type Foo = impl Bar<Foo, Item = Foo>;
-//~^ ERROR: could not find defining uses
+//~^ ERROR: unconstrained opaque type
fn crash(x: Foo) -> Foo {
x
-error: could not find defining uses
+error: unconstrained opaque type
--> $DIR/type-alias-impl-trait-with-cycle-error2.rs:7:12
|
LL | type Foo = impl Bar<Foo, Item = Foo>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: `Foo` must be used in combination with a concrete type within the same module
error: aborting due to previous error
-// run-pass
+// check-pass
#![allow(dead_code)]
#![allow(unused_assignments)]
--- /dev/null
+// check-pass
+
+#![allow(dead_code)]
+#![allow(unused_assignments)]
+#![allow(unused_variables)]
+#![feature(type_alias_impl_trait)]
+
+fn main() {
+ assert_eq!(foo().to_string(), "foo");
+ assert_eq!(bar1().to_string(), "bar1");
+ assert_eq!(bar2().to_string(), "bar2");
+ let mut x = bar1();
+ x = bar2();
+ assert_eq!(my_iter(42u8).collect::<Vec<u8>>(), vec![42u8]);
+}
+
+use defining_use_scope::*;
+
+mod defining_use_scope {
+ // single definition
+ pub type Foo = impl std::fmt::Display;
+
+ pub fn foo() -> Foo {
+ "foo"
+ }
+
+ // two definitions
+ pub type Bar = impl std::fmt::Display;
+
+ pub fn bar1() -> Bar {
+ "bar1"
+ }
+
+ pub fn bar2() -> Bar {
+ "bar2"
+ }
+
+ pub type MyIter<T> = impl Iterator<Item = T>;
+
+ pub fn my_iter<T>(t: T) -> MyIter<T> {
+ std::iter::once(t)
+ }
+
+ fn my_iter2<T>(t: T) -> MyIter<T> {
+ std::iter::once(t)
+ }
+
+ // param names should not have an effect!
+ fn my_iter3<U>(u: U) -> MyIter<U> {
+ std::iter::once(u)
+ }
+
+ // param position should not have an effect!
+ fn my_iter4<U, V>(_: U, v: V) -> MyIter<V> {
+ std::iter::once(v)
+ }
+
+ // param names should not have an effect!
+ type MyOtherIter<T> = impl Iterator<Item = T>;
+
+ fn my_other_iter<U>(u: U) -> MyOtherIter<U> {
+ std::iter::once(u)
+ }
+
+ trait Trait {}
+ type GenericBound<'a, T: Trait + 'a> = impl Sized + 'a;
+
+ fn generic_bound<'a, T: Trait + 'a>(t: T) -> GenericBound<'a, T> {
+ t
+ }
+
+ mod pass_through {
+ pub type Passthrough<T: 'static> = impl Sized + 'static;
+
+ fn define_passthrough<T: 'static>(t: T) -> Passthrough<T> {
+ t
+ }
+ }
+
+ fn use_passthrough(x: pass_through::Passthrough<u32>) -> pass_through::Passthrough<u32> {
+ x
+ }
+
+}
#![feature(type_alias_impl_trait)]
#![allow(dead_code)]
-// FIXME This should compile, but it currently doesn't
-
use std::fmt::Debug;
type Foo = impl Debug;
-//~^ ERROR: could not find defining uses
fn foo1() -> u32 {
let x: Foo = 22_u32;
- //~^ ERROR: mismatched types [E0308]
x
- //~^ ERROR: mismatched types [E0308]
}
fn foo2() -> u32 {
let x: Foo = 22_u32;
- //~^ ERROR: mismatched types [E0308]
let y: Foo = x;
- same_type((x, y));
- y
- //~^ ERROR: mismatched types [E0308]
+ same_type((x, y)); //~ ERROR use of moved value
+ y //~ ERROR use of moved value
}
fn same_type<T>(x: (T, T)) {}
-error[E0308]: mismatched types
- --> $DIR/type_of_a_let.rs:12:18
+error[E0382]: use of moved value: `x`
+ --> $DIR/type_of_a_let.rs:16:16
|
-LL | type Foo = impl Debug;
- | ---------- the expected opaque type
-...
LL | let x: Foo = 22_u32;
- | --- ^^^^^^ expected opaque type, found `u32`
- | |
- | expected due to this
- |
- = note: expected opaque type `impl Debug`
- found type `u32`
-
-error[E0308]: mismatched types
- --> $DIR/type_of_a_let.rs:14:5
- |
-LL | type Foo = impl Debug;
- | ---------- the found opaque type
-...
-LL | fn foo1() -> u32 {
- | --- expected `u32` because of return type
-...
-LL | x
- | ^ expected `u32`, found opaque type
- |
- = note: expected type `u32`
- found opaque type `impl Debug`
+ | - move occurs because `x` has type `Foo`, which does not implement the `Copy` trait
+LL | let y: Foo = x;
+ | - value moved here
+LL | same_type((x, y));
+ | ^ value used here after move
-error[E0308]: mismatched types
- --> $DIR/type_of_a_let.rs:19:18
- |
-LL | type Foo = impl Debug;
- | ---------- the expected opaque type
-...
-LL | let x: Foo = 22_u32;
- | --- ^^^^^^ expected opaque type, found `u32`
- | |
- | expected due to this
+error[E0382]: use of moved value: `y`
+ --> $DIR/type_of_a_let.rs:17:5
|
- = note: expected opaque type `impl Debug`
- found type `u32`
-
-error[E0308]: mismatched types
- --> $DIR/type_of_a_let.rs:23:5
- |
-LL | type Foo = impl Debug;
- | ---------- the found opaque type
-...
-LL | fn foo2() -> u32 {
- | --- expected `u32` because of return type
-...
+LL | let y: Foo = x;
+ | - move occurs because `y` has type `Foo`, which does not implement the `Copy` trait
+LL | same_type((x, y));
+ | - value moved here
LL | y
- | ^ expected `u32`, found opaque type
- |
- = note: expected type `u32`
- found opaque type `impl Debug`
-
-error: could not find defining uses
- --> $DIR/type_of_a_let.rs:8:12
- |
-LL | type Foo = impl Debug;
- | ^^^^^^^^^^
+ | ^ value used here after move
-error: aborting due to 5 previous errors
+error: aborting due to 2 previous errors
-For more information about this error, try `rustc --explain E0308`.
+For more information about this error, try `rustc --explain E0382`.
| ty::PredicateKind::Projection(_)
| ty::PredicateKind::ConstEvaluatable(..)
| ty::PredicateKind::ConstEquate(..)
+ | ty::PredicateKind::OpaqueType(..)
| ty::PredicateKind::TypeWellFormedFromEnv(..) => continue,
ty::PredicateKind::ObjectSafe(_) => panic!("object safe predicate on function: {:#?}", predicate),
ty::PredicateKind::ClosureKind(..) => panic!("closure kind predicate on function: {:#?}", predicate),
name,
ignore,
should_panic,
- allow_fail: false,
compile_fail: false,
no_run: false,
test_type: test::TestType::Unknown,
+ #[cfg(bootstrap)]
+ allow_fail: false,
}
}