Auto merge of #137406 - matthiaskrgr:rollup-9nknrsb, r=matthiaskrgr
Rollup of 8 pull requests Successful merges: - #136458 (Do not deduplicate list of associated types provided by dyn principal) - #136474 ([`compiletest`-related cleanups 3/7] Make the distinction between sources root vs test suite sources root in compiletest less confusing) - #136592 (Make sure we don't overrun the stack in canonicalizer) - #136787 (Remove `lifetime_capture_rules_2024` feature) - #137207 (Add #[track_caller] to Duration Div impl) - #137245 (Tweak E0277 when predicate comes indirectly from ?) - #137257 (Ignore fake borrows for packed field check) - #137399 (fix ICE in layout computation with unnormalizable const) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
b87eda7fdf
65 changed files with 785 additions and 386 deletions
|
|
@ -135,6 +135,8 @@ declare_features! (
|
|||
Some("removed as it caused some confusion and discussion was inactive for years")),
|
||||
/// Lazily evaluate constants. This allows constants to depend on type parameters.
|
||||
(removed, lazy_normalization_consts, "1.46.0", Some(72219), Some("superseded by `generic_const_exprs`")),
|
||||
/// Changes `impl Trait` to capture all lifetimes in scope.
|
||||
(removed, lifetime_capture_rules_2024, "1.76.0", None, Some("unnecessary -- use edition 2024 instead")),
|
||||
/// Allows using the `#[link_args]` attribute.
|
||||
(removed, link_args, "1.53.0", Some(29596),
|
||||
Some("removed in favor of using `-C link-arg=ARG` on command line, \
|
||||
|
|
|
|||
|
|
@ -214,8 +214,6 @@ declare_features! (
|
|||
(internal, intrinsics, "1.0.0", None),
|
||||
/// Allows using `#[lang = ".."]` attribute for linking items to special compiler logic.
|
||||
(internal, lang_items, "1.0.0", None),
|
||||
/// Changes `impl Trait` to capture all lifetimes in scope.
|
||||
(unstable, lifetime_capture_rules_2024, "1.76.0", None),
|
||||
/// Allows `#[link(..., cfg(..))]`; perma-unstable per #37406
|
||||
(internal, link_cfg, "1.14.0", None),
|
||||
/// Allows using `?Trait` trait bounds in more contexts.
|
||||
|
|
|
|||
|
|
@ -305,21 +305,15 @@ fn generic_param_def_as_bound_arg(param: &ty::GenericParamDef) -> ty::BoundVaria
|
|||
}
|
||||
|
||||
/// Whether this opaque always captures lifetimes in scope.
|
||||
/// Right now, this is all RPITIT and TAITs, and when `lifetime_capture_rules_2024`
|
||||
/// is enabled. We don't check the span of the edition, since this is done
|
||||
/// on a per-opaque basis to account for nested opaques.
|
||||
fn opaque_captures_all_in_scope_lifetimes<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
opaque: &'tcx hir::OpaqueTy<'tcx>,
|
||||
) -> bool {
|
||||
/// Right now, this is all RPITIT and TAITs, and when the opaque
|
||||
/// is coming from a span corresponding to edition 2024.
|
||||
fn opaque_captures_all_in_scope_lifetimes<'tcx>(opaque: &'tcx hir::OpaqueTy<'tcx>) -> bool {
|
||||
match opaque.origin {
|
||||
// if the opaque has the `use<...>` syntax, the user is telling us that they only want
|
||||
// to account for those lifetimes, so do not try to be clever.
|
||||
_ if opaque.bounds.iter().any(|bound| matches!(bound, hir::GenericBound::Use(..))) => false,
|
||||
hir::OpaqueTyOrigin::AsyncFn { .. } | hir::OpaqueTyOrigin::TyAlias { .. } => true,
|
||||
_ if tcx.features().lifetime_capture_rules_2024() || opaque.span.at_least_rust_2024() => {
|
||||
true
|
||||
}
|
||||
_ if opaque.span.at_least_rust_2024() => true,
|
||||
hir::OpaqueTyOrigin::FnReturn { in_trait_or_impl, .. } => in_trait_or_impl.is_some(),
|
||||
}
|
||||
}
|
||||
|
|
@ -519,8 +513,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
|
|||
fn visit_opaque_ty(&mut self, opaque: &'tcx rustc_hir::OpaqueTy<'tcx>) {
|
||||
let captures = RefCell::new(FxIndexMap::default());
|
||||
|
||||
let capture_all_in_scope_lifetimes =
|
||||
opaque_captures_all_in_scope_lifetimes(self.tcx, opaque);
|
||||
let capture_all_in_scope_lifetimes = opaque_captures_all_in_scope_lifetimes(opaque);
|
||||
if capture_all_in_scope_lifetimes {
|
||||
let lifetime_ident = |def_id: LocalDefId| {
|
||||
let name = self.tcx.item_name(def_id.to_def_id());
|
||||
|
|
@ -2276,7 +2269,7 @@ fn is_late_bound_map(
|
|||
}
|
||||
|
||||
let mut appears_in_output =
|
||||
AllCollector { tcx, has_fully_capturing_opaque: false, regions: Default::default() };
|
||||
AllCollector { has_fully_capturing_opaque: false, regions: Default::default() };
|
||||
intravisit::walk_fn_ret_ty(&mut appears_in_output, &sig.decl.output);
|
||||
if appears_in_output.has_fully_capturing_opaque {
|
||||
appears_in_output.regions.extend(generics.params.iter().map(|param| param.def_id));
|
||||
|
|
@ -2289,7 +2282,7 @@ fn is_late_bound_map(
|
|||
// Subtle point: because we disallow nested bindings, we can just
|
||||
// ignore binders here and scrape up all names we see.
|
||||
let mut appears_in_where_clause =
|
||||
AllCollector { tcx, has_fully_capturing_opaque: true, regions: Default::default() };
|
||||
AllCollector { has_fully_capturing_opaque: true, regions: Default::default() };
|
||||
appears_in_where_clause.visit_generics(generics);
|
||||
debug!(?appears_in_where_clause.regions);
|
||||
|
||||
|
|
@ -2455,23 +2448,21 @@ fn is_late_bound_map(
|
|||
}
|
||||
}
|
||||
|
||||
struct AllCollector<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
struct AllCollector {
|
||||
has_fully_capturing_opaque: bool,
|
||||
regions: FxHashSet<LocalDefId>,
|
||||
}
|
||||
|
||||
impl<'v> Visitor<'v> for AllCollector<'v> {
|
||||
fn visit_lifetime(&mut self, lifetime_ref: &'v hir::Lifetime) {
|
||||
impl<'tcx> Visitor<'tcx> for AllCollector {
|
||||
fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) {
|
||||
if let hir::LifetimeName::Param(def_id) = lifetime_ref.res {
|
||||
self.regions.insert(def_id);
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_opaque_ty(&mut self, opaque: &'v hir::OpaqueTy<'v>) {
|
||||
fn visit_opaque_ty(&mut self, opaque: &'tcx hir::OpaqueTy<'tcx>) {
|
||||
if !self.has_fully_capturing_opaque {
|
||||
self.has_fully_capturing_opaque =
|
||||
opaque_captures_all_in_scope_lifetimes(self.tcx, opaque);
|
||||
self.has_fully_capturing_opaque = opaque_captures_all_in_scope_lifetimes(opaque);
|
||||
}
|
||||
intravisit::walk_opaque_ty(self, opaque);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
|
||||
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
|
||||
use rustc_errors::codes::*;
|
||||
use rustc_errors::struct_span_code_err;
|
||||
use rustc_hir as hir;
|
||||
|
|
@ -58,9 +58,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
}
|
||||
}
|
||||
|
||||
let (trait_bounds, mut projection_bounds) =
|
||||
let (elaborated_trait_bounds, elaborated_projection_bounds) =
|
||||
traits::expand_trait_aliases(tcx, user_written_bounds.iter().copied());
|
||||
let (regular_traits, mut auto_traits): (Vec<_>, Vec<_>) = trait_bounds
|
||||
let (regular_traits, mut auto_traits): (Vec<_>, Vec<_>) = elaborated_trait_bounds
|
||||
.into_iter()
|
||||
.partition(|(trait_ref, _)| !tcx.trait_is_auto(trait_ref.def_id()));
|
||||
|
||||
|
|
@ -103,29 +103,81 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
}
|
||||
}
|
||||
|
||||
// Map the projection bounds onto a key that makes it easy to remove redundant
|
||||
// bounds that are constrained by supertraits of the principal def id.
|
||||
//
|
||||
// Also make sure we detect conflicting bounds from expanding a trait alias and
|
||||
// also specifying it manually, like:
|
||||
// ```
|
||||
// type Alias = Trait<Assoc = i32>;
|
||||
// let _: &dyn Alias<Assoc = u32> = /* ... */;
|
||||
// ```
|
||||
let mut projection_bounds = FxIndexMap::default();
|
||||
for (proj, proj_span) in elaborated_projection_bounds {
|
||||
let key = (
|
||||
proj.skip_binder().projection_term.def_id,
|
||||
tcx.anonymize_bound_vars(
|
||||
proj.map_bound(|proj| proj.projection_term.trait_ref(tcx)),
|
||||
),
|
||||
);
|
||||
if let Some((old_proj, old_proj_span)) =
|
||||
projection_bounds.insert(key, (proj, proj_span))
|
||||
&& tcx.anonymize_bound_vars(proj) != tcx.anonymize_bound_vars(old_proj)
|
||||
{
|
||||
let item = tcx.item_name(proj.item_def_id());
|
||||
self.dcx()
|
||||
.struct_span_err(
|
||||
span,
|
||||
format!(
|
||||
"conflicting associated type bounds for `{item}` when \
|
||||
expanding trait alias"
|
||||
),
|
||||
)
|
||||
.with_span_label(
|
||||
old_proj_span,
|
||||
format!("`{item}` is specified to be `{}` here", old_proj.term()),
|
||||
)
|
||||
.with_span_label(
|
||||
proj_span,
|
||||
format!("`{item}` is specified to be `{}` here", proj.term()),
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
|
||||
let principal_trait = regular_traits.into_iter().next();
|
||||
|
||||
let mut needed_associated_types = FxIndexSet::default();
|
||||
if let Some((principal_trait, spans)) = &principal_trait {
|
||||
let pred: ty::Predicate<'tcx> = (*principal_trait).upcast(tcx);
|
||||
for ClauseWithSupertraitSpan { pred, supertrait_span } in traits::elaborate(
|
||||
let mut needed_associated_types = vec![];
|
||||
if let Some((principal_trait, ref spans)) = principal_trait {
|
||||
let principal_trait = principal_trait.map_bound(|trait_pred| {
|
||||
assert_eq!(trait_pred.polarity, ty::PredicatePolarity::Positive);
|
||||
trait_pred.trait_ref
|
||||
});
|
||||
|
||||
for ClauseWithSupertraitSpan { clause, supertrait_span } in traits::elaborate(
|
||||
tcx,
|
||||
[ClauseWithSupertraitSpan::new(pred, *spans.last().unwrap())],
|
||||
[ClauseWithSupertraitSpan::new(
|
||||
ty::TraitRef::identity(tcx, principal_trait.def_id()).upcast(tcx),
|
||||
*spans.last().unwrap(),
|
||||
)],
|
||||
)
|
||||
.filter_only_self()
|
||||
{
|
||||
debug!("observing object predicate `{pred:?}`");
|
||||
let clause = clause.instantiate_supertrait(tcx, principal_trait);
|
||||
debug!("observing object predicate `{clause:?}`");
|
||||
|
||||
let bound_predicate = pred.kind();
|
||||
let bound_predicate = clause.kind();
|
||||
match bound_predicate.skip_binder() {
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => {
|
||||
ty::ClauseKind::Trait(pred) => {
|
||||
// FIXME(negative_bounds): Handle this correctly...
|
||||
let trait_ref =
|
||||
tcx.anonymize_bound_vars(bound_predicate.rebind(pred.trait_ref));
|
||||
needed_associated_types.extend(
|
||||
tcx.associated_items(trait_ref.def_id())
|
||||
tcx.associated_items(pred.trait_ref.def_id)
|
||||
.in_definition_order()
|
||||
// We only care about associated types.
|
||||
.filter(|item| item.kind == ty::AssocKind::Type)
|
||||
// No RPITITs -- even with `async_fn_in_dyn_trait`, they are implicit.
|
||||
.filter(|item| !item.is_impl_trait_in_trait())
|
||||
// If the associated type has a `where Self: Sized` bound,
|
||||
// we do not need to constrain the associated type.
|
||||
|
|
@ -133,7 +185,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
.map(|item| (item.def_id, trait_ref)),
|
||||
);
|
||||
}
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::Projection(pred)) => {
|
||||
ty::ClauseKind::Projection(pred) => {
|
||||
let pred = bound_predicate.rebind(pred);
|
||||
// A `Self` within the original bound will be instantiated with a
|
||||
// `trait_object_dummy_self`, so check for that.
|
||||
|
|
@ -161,8 +213,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
// `dyn MyTrait<MyOutput = X, Output = X>`, which is uglier but works. See
|
||||
// the discussion in #56288 for alternatives.
|
||||
if !references_self {
|
||||
// Include projections defined on supertraits.
|
||||
projection_bounds.push((pred, supertrait_span));
|
||||
let key = (
|
||||
pred.skip_binder().projection_term.def_id,
|
||||
tcx.anonymize_bound_vars(
|
||||
pred.map_bound(|proj| proj.projection_term.trait_ref(tcx)),
|
||||
),
|
||||
);
|
||||
if !projection_bounds.contains_key(&key) {
|
||||
projection_bounds.insert(key, (pred, supertrait_span));
|
||||
}
|
||||
}
|
||||
|
||||
self.check_elaborated_projection_mentions_input_lifetimes(
|
||||
|
|
@ -182,12 +241,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
// types that we expect to be provided by the user, so the following loop
|
||||
// removes all the associated types that have a corresponding `Projection`
|
||||
// clause, either from expanding trait aliases or written by the user.
|
||||
for &(projection_bound, span) in &projection_bounds {
|
||||
for &(projection_bound, span) in projection_bounds.values() {
|
||||
let def_id = projection_bound.item_def_id();
|
||||
let trait_ref = tcx.anonymize_bound_vars(
|
||||
projection_bound.map_bound(|p| p.projection_term.trait_ref(tcx)),
|
||||
);
|
||||
needed_associated_types.swap_remove(&(def_id, trait_ref));
|
||||
if tcx.generics_require_sized_self(def_id) {
|
||||
tcx.emit_node_span_lint(
|
||||
UNUSED_ASSOCIATED_TYPE_BOUNDS,
|
||||
|
|
@ -198,9 +253,22 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
}
|
||||
}
|
||||
|
||||
let mut missing_assoc_types = FxIndexSet::default();
|
||||
let projection_bounds: Vec<_> = needed_associated_types
|
||||
.into_iter()
|
||||
.filter_map(|key| {
|
||||
if let Some(assoc) = projection_bounds.get(&key) {
|
||||
Some(*assoc)
|
||||
} else {
|
||||
missing_assoc_types.insert(key);
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
if let Err(guar) = self.check_for_required_assoc_tys(
|
||||
principal_trait.as_ref().map_or(smallvec![], |(_, spans)| spans.clone()),
|
||||
needed_associated_types,
|
||||
missing_assoc_types,
|
||||
potential_assoc_types,
|
||||
hir_bounds,
|
||||
) {
|
||||
|
|
@ -266,7 +334,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
})
|
||||
});
|
||||
|
||||
let existential_projections = projection_bounds.iter().map(|(bound, _)| {
|
||||
let existential_projections = projection_bounds.into_iter().map(|(bound, _)| {
|
||||
bound.map_bound(|mut b| {
|
||||
assert_eq!(b.projection_term.self_ty(), dummy_self);
|
||||
|
||||
|
|
@ -291,12 +359,16 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
})
|
||||
});
|
||||
|
||||
let auto_trait_predicates = auto_traits.into_iter().map(|(trait_pred, _)| {
|
||||
assert_eq!(trait_pred.polarity(), ty::PredicatePolarity::Positive);
|
||||
assert_eq!(trait_pred.self_ty().skip_binder(), dummy_self);
|
||||
let mut auto_trait_predicates: Vec<_> = auto_traits
|
||||
.into_iter()
|
||||
.map(|(trait_pred, _)| {
|
||||
assert_eq!(trait_pred.polarity(), ty::PredicatePolarity::Positive);
|
||||
assert_eq!(trait_pred.self_ty().skip_binder(), dummy_self);
|
||||
|
||||
ty::Binder::dummy(ty::ExistentialPredicate::AutoTrait(trait_pred.def_id()))
|
||||
});
|
||||
ty::Binder::dummy(ty::ExistentialPredicate::AutoTrait(trait_pred.def_id()))
|
||||
})
|
||||
.collect();
|
||||
auto_trait_predicates.dedup();
|
||||
|
||||
// N.b. principal, projections, auto traits
|
||||
// FIXME: This is actually wrong with multiple principals in regards to symbol mangling
|
||||
|
|
@ -306,7 +378,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
.chain(auto_trait_predicates)
|
||||
.collect::<SmallVec<[_; 8]>>();
|
||||
v.sort_by(|a, b| a.skip_binder().stable_cmp(tcx, &b.skip_binder()));
|
||||
v.dedup();
|
||||
let existential_predicates = tcx.mk_poly_existential_predicates(&v);
|
||||
|
||||
// Use explicitly-specified region bound, unless the bound is missing.
|
||||
|
|
|
|||
|
|
@ -86,8 +86,7 @@ declare_lint! {
|
|||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust,compile_fail
|
||||
/// # #![feature(lifetime_capture_rules_2024)]
|
||||
/// ```rust,edition2024,compile_fail
|
||||
/// # #![deny(impl_trait_redundant_captures)]
|
||||
/// fn test<'a>(x: &'a i32) -> impl Sized + use<'a> { x }
|
||||
/// ```
|
||||
|
|
@ -268,8 +267,7 @@ where
|
|||
&& parent == self.parent_def_id
|
||||
{
|
||||
let opaque_span = self.tcx.def_span(opaque_def_id);
|
||||
let new_capture_rules = opaque_span.at_least_rust_2024()
|
||||
|| self.tcx.features().lifetime_capture_rules_2024();
|
||||
let new_capture_rules = opaque_span.at_least_rust_2024();
|
||||
if !new_capture_rules
|
||||
&& !opaque.bounds.iter().any(|bound| matches!(bound, hir::GenericBound::Use(..)))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1364,13 +1364,13 @@ impl PlaceContext {
|
|||
matches!(self, PlaceContext::MutatingUse(MutatingUseContext::Drop))
|
||||
}
|
||||
|
||||
/// Returns `true` if this place context represents a borrow.
|
||||
/// Returns `true` if this place context represents a borrow, excluding fake borrows
|
||||
/// (which are an artifact of borrowck and not actually borrows in runtime MIR).
|
||||
pub fn is_borrow(self) -> bool {
|
||||
matches!(
|
||||
self,
|
||||
PlaceContext::NonMutatingUse(
|
||||
NonMutatingUseContext::SharedBorrow | NonMutatingUseContext::FakeBorrow
|
||||
) | PlaceContext::MutatingUse(MutatingUseContext::Borrow)
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow)
|
||||
| PlaceContext::MutatingUse(MutatingUseContext::Borrow)
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ use std::borrow::Cow;
|
|||
use std::hash::{Hash, Hasher};
|
||||
use std::sync::Arc;
|
||||
|
||||
use rustc_errors::{Applicability, Diag, EmissionGuarantee};
|
||||
use rustc_errors::{Applicability, Diag, EmissionGuarantee, ErrorGuaranteed};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::HirId;
|
||||
use rustc_hir::def_id::DefId;
|
||||
|
|
@ -996,4 +996,7 @@ pub enum CodegenObligationError {
|
|||
/// but was included during typeck due to the trivial_bounds feature.
|
||||
Unimplemented,
|
||||
FulfillmentError,
|
||||
/// The selected impl has unconstrained generic parameters. This will emit an error
|
||||
/// during impl WF checking.
|
||||
UnconstrainedParam(ErrorGuaranteed),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -79,20 +79,14 @@ impl<'tcx> Relate<TyCtxt<'tcx>> for &'tcx ty::List<ty::PolyExistentialPredicate<
|
|||
b: Self,
|
||||
) -> RelateResult<'tcx, Self> {
|
||||
let tcx = relation.cx();
|
||||
|
||||
// FIXME: this is wasteful, but want to do a perf run to see how slow it is.
|
||||
// We need to perform this deduplication as we sometimes generate duplicate projections
|
||||
// in `a`.
|
||||
let mut a_v: Vec<_> = a.into_iter().collect();
|
||||
let mut b_v: Vec<_> = b.into_iter().collect();
|
||||
a_v.dedup();
|
||||
b_v.dedup();
|
||||
if a_v.len() != b_v.len() {
|
||||
// Fast path for when the auto traits do not match, or if the principals
|
||||
// are from different traits and therefore the projections definitely don't
|
||||
// match up.
|
||||
if a.len() != b.len() {
|
||||
return Err(TypeError::ExistentialMismatch(ExpectedFound::new(a, b)));
|
||||
}
|
||||
|
||||
let v = iter::zip(a_v, b_v).map(|(ep_a, ep_b)| {
|
||||
match (ep_a.skip_binder(), ep_b.skip_binder()) {
|
||||
let v =
|
||||
iter::zip(a, b).map(|(ep_a, ep_b)| match (ep_a.skip_binder(), ep_b.skip_binder()) {
|
||||
(ty::ExistentialPredicate::Trait(a), ty::ExistentialPredicate::Trait(b)) => {
|
||||
Ok(ep_a.rebind(ty::ExistentialPredicate::Trait(
|
||||
relation.relate(ep_a.rebind(a), ep_b.rebind(b))?.skip_binder(),
|
||||
|
|
@ -109,8 +103,7 @@ impl<'tcx> Relate<TyCtxt<'tcx>> for &'tcx ty::List<ty::PolyExistentialPredicate<
|
|||
ty::ExistentialPredicate::AutoTrait(b),
|
||||
) if a == b => Ok(ep_a.rebind(ty::ExistentialPredicate::AutoTrait(a))),
|
||||
_ => Err(TypeError::ExistentialMismatch(ExpectedFound::new(a, b))),
|
||||
}
|
||||
});
|
||||
});
|
||||
tcx.mk_poly_existential_predicates_from_iter(v)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, extension
|
|||
use rustc_span::{DUMMY_SP, Span, Symbol, sym};
|
||||
use rustc_type_ir::TyKind::*;
|
||||
use rustc_type_ir::visit::TypeVisitableExt;
|
||||
use rustc_type_ir::{self as ir, BoundVar, CollectAndApply, DynKind};
|
||||
use rustc_type_ir::{self as ir, BoundVar, CollectAndApply, DynKind, elaborate};
|
||||
use tracing::instrument;
|
||||
use ty::util::{AsyncDropGlueMorphology, IntTypeExt};
|
||||
|
||||
|
|
@ -720,6 +720,34 @@ impl<'tcx> Ty<'tcx> {
|
|||
reg: ty::Region<'tcx>,
|
||||
repr: DynKind,
|
||||
) -> Ty<'tcx> {
|
||||
if cfg!(debug_assertions) {
|
||||
let projection_count = obj.projection_bounds().count();
|
||||
let expected_count: usize = obj
|
||||
.principal_def_id()
|
||||
.into_iter()
|
||||
.flat_map(|principal_def_id| {
|
||||
// NOTE: This should agree with `needed_associated_types` in
|
||||
// dyn trait lowering, or else we'll have ICEs.
|
||||
elaborate::supertraits(
|
||||
tcx,
|
||||
ty::Binder::dummy(ty::TraitRef::identity(tcx, principal_def_id)),
|
||||
)
|
||||
.map(|principal| {
|
||||
tcx.associated_items(principal.def_id())
|
||||
.in_definition_order()
|
||||
.filter(|item| item.kind == ty::AssocKind::Type)
|
||||
.filter(|item| !item.is_impl_trait_in_trait())
|
||||
.filter(|item| !tcx.generics_require_sized_self(item.def_id))
|
||||
.count()
|
||||
})
|
||||
})
|
||||
.sum();
|
||||
assert_eq!(
|
||||
projection_count, expected_count,
|
||||
"expected {obj:?} to have {expected_count} projections, \
|
||||
but it has {projection_count}"
|
||||
);
|
||||
}
|
||||
Ty::new(tcx, Dynamic(obj, reg, repr))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use std::cmp::Ordering;
|
||||
|
||||
use rustc_type_ir::data_structures::HashMap;
|
||||
use rustc_type_ir::data_structures::{HashMap, ensure_sufficient_stack};
|
||||
use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
|
||||
use rustc_type_ir::inherent::*;
|
||||
use rustc_type_ir::solve::{Goal, QueryInput};
|
||||
|
|
@ -389,7 +389,7 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
|
|||
| ty::Alias(_, _)
|
||||
| ty::Bound(_, _)
|
||||
| ty::Error(_) => {
|
||||
return t.super_fold_with(self);
|
||||
return ensure_sufficient_stack(|| t.super_fold_with(self));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -192,19 +192,38 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
|
||||
let have_alt_message = message.is_some() || label.is_some();
|
||||
let is_try_conversion = self.is_try_conversion(span, main_trait_predicate.def_id());
|
||||
let is_question_mark = matches!(
|
||||
root_obligation.cause.code().peel_derives(),
|
||||
ObligationCauseCode::QuestionMark,
|
||||
) && !(
|
||||
self.tcx.is_diagnostic_item(sym::FromResidual, main_trait_predicate.def_id())
|
||||
|| self.tcx.is_lang_item(main_trait_predicate.def_id(), LangItem::Try)
|
||||
);
|
||||
let is_unsize =
|
||||
self.tcx.is_lang_item(leaf_trait_predicate.def_id(), LangItem::Unsize);
|
||||
let question_mark_message = "the question mark operation (`?`) implicitly \
|
||||
performs a conversion on the error value \
|
||||
using the `From` trait";
|
||||
let (message, notes, append_const_msg) = if is_try_conversion {
|
||||
// We have a `-> Result<_, E1>` and `gives_E2()?`.
|
||||
(
|
||||
Some(format!(
|
||||
"`?` couldn't convert the error to `{}`",
|
||||
main_trait_predicate.skip_binder().self_ty(),
|
||||
)),
|
||||
vec![
|
||||
"the question mark operation (`?`) implicitly performs a \
|
||||
conversion on the error value using the `From` trait"
|
||||
.to_owned(),
|
||||
],
|
||||
vec![question_mark_message.to_owned()],
|
||||
Some(AppendConstMessage::Default),
|
||||
)
|
||||
} else if is_question_mark {
|
||||
// Similar to the case above, but in this case the conversion is for a
|
||||
// trait object: `-> Result<_, Box<dyn Error>` and `gives_E()?` when
|
||||
// `E: Error` isn't met.
|
||||
(
|
||||
Some(format!(
|
||||
"`?` couldn't convert the error: `{main_trait_predicate}` is \
|
||||
not satisfied",
|
||||
)),
|
||||
vec![question_mark_message.to_owned()],
|
||||
Some(AppendConstMessage::Default),
|
||||
)
|
||||
} else {
|
||||
|
|
@ -220,8 +239,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
&mut long_ty_file,
|
||||
);
|
||||
|
||||
let (err_msg, safe_transmute_explanation) = if self.tcx.is_lang_item(main_trait_predicate.def_id(), LangItem::TransmuteTrait)
|
||||
{
|
||||
let (err_msg, safe_transmute_explanation) = if self.tcx.is_lang_item(
|
||||
main_trait_predicate.def_id(),
|
||||
LangItem::TransmuteTrait,
|
||||
) {
|
||||
// Recompute the safe transmute reason and use that for the error reporting
|
||||
match self.get_safe_transmute_error_and_reason(
|
||||
obligation.clone(),
|
||||
|
|
@ -249,18 +270,22 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
*err.long_ty_path() = long_ty_file;
|
||||
|
||||
let mut suggested = false;
|
||||
if is_try_conversion {
|
||||
if is_try_conversion || is_question_mark {
|
||||
suggested = self.try_conversion_context(&obligation, main_trait_predicate, &mut err);
|
||||
}
|
||||
|
||||
if is_try_conversion && let Some(ret_span) = self.return_type_span(&obligation) {
|
||||
err.span_label(
|
||||
ret_span,
|
||||
format!(
|
||||
"expected `{}` because of this",
|
||||
main_trait_predicate.skip_binder().self_ty()
|
||||
),
|
||||
);
|
||||
if let Some(ret_span) = self.return_type_span(&obligation) {
|
||||
if is_try_conversion {
|
||||
err.span_label(
|
||||
ret_span,
|
||||
format!(
|
||||
"expected `{}` because of this",
|
||||
main_trait_predicate.skip_binder().self_ty()
|
||||
),
|
||||
);
|
||||
} else if is_question_mark {
|
||||
err.span_label(ret_span, format!("required `{main_trait_predicate}` because of this"));
|
||||
}
|
||||
}
|
||||
|
||||
if tcx.is_lang_item(leaf_trait_predicate.def_id(), LangItem::Tuple) {
|
||||
|
|
@ -302,10 +327,14 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
// If it has a custom `#[rustc_on_unimplemented]`
|
||||
// error message, let's display it as the label!
|
||||
err.span_label(span, s);
|
||||
if !matches!(leaf_trait_predicate.skip_binder().self_ty().kind(), ty::Param(_)) {
|
||||
if !matches!(leaf_trait_predicate.skip_binder().self_ty().kind(), ty::Param(_))
|
||||
// When the self type is a type param We don't need to "the trait
|
||||
// `std::marker::Sized` is not implemented for `T`" as we will point
|
||||
// at the type param with a label to suggest constraining it.
|
||||
&& !self.tcx.is_diagnostic_item(sym::FromResidual, leaf_trait_predicate.def_id())
|
||||
// Don't say "the trait `FromResidual<Option<Infallible>>` is
|
||||
// not implemented for `Result<T, E>`".
|
||||
{
|
||||
err.help(explanation);
|
||||
}
|
||||
} else if let Some(custom_explanation) = safe_transmute_explanation {
|
||||
|
|
@ -932,16 +961,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
let Some(typeck) = &self.typeck_results else {
|
||||
return false;
|
||||
};
|
||||
let Some((ObligationCauseCode::QuestionMark, Some(y))) =
|
||||
obligation.cause.code().parent_with_predicate()
|
||||
else {
|
||||
let ObligationCauseCode::QuestionMark = obligation.cause.code().peel_derives() else {
|
||||
return false;
|
||||
};
|
||||
if !self.tcx.is_diagnostic_item(sym::FromResidual, y.def_id()) {
|
||||
return false;
|
||||
}
|
||||
let self_ty = trait_pred.skip_binder().self_ty();
|
||||
let found_ty = trait_pred.skip_binder().trait_ref.args.get(1).and_then(|a| a.as_type());
|
||||
self.note_missing_impl_for_question_mark(err, self_ty, found_ty, trait_pred);
|
||||
|
||||
let mut prev_ty = self.resolve_vars_if_possible(
|
||||
typeck.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(self.tcx)),
|
||||
|
|
@ -1106,6 +1131,56 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
suggested
|
||||
}
|
||||
|
||||
fn note_missing_impl_for_question_mark(
|
||||
&self,
|
||||
err: &mut Diag<'_>,
|
||||
self_ty: Ty<'_>,
|
||||
found_ty: Option<Ty<'_>>,
|
||||
trait_pred: ty::PolyTraitPredicate<'tcx>,
|
||||
) {
|
||||
match (self_ty.kind(), found_ty) {
|
||||
(ty::Adt(def, _), Some(ty))
|
||||
if let ty::Adt(found, _) = ty.kind()
|
||||
&& def.did().is_local()
|
||||
&& found.did().is_local() =>
|
||||
{
|
||||
err.span_note(
|
||||
self.tcx.def_span(def.did()),
|
||||
format!("`{self_ty}` needs to implement `From<{ty}>`"),
|
||||
);
|
||||
err.span_note(
|
||||
self.tcx.def_span(found.did()),
|
||||
format!("alternatively, `{ty}` needs to implement `Into<{self_ty}>`"),
|
||||
);
|
||||
}
|
||||
(ty::Adt(def, _), None) if def.did().is_local() => {
|
||||
err.span_note(
|
||||
self.tcx.def_span(def.did()),
|
||||
format!(
|
||||
"`{self_ty}` needs to implement `{}`",
|
||||
trait_pred.skip_binder().trait_ref.print_only_trait_path(),
|
||||
),
|
||||
);
|
||||
}
|
||||
(ty::Adt(def, _), Some(ty)) if def.did().is_local() => {
|
||||
err.span_note(
|
||||
self.tcx.def_span(def.did()),
|
||||
format!("`{self_ty}` needs to implement `From<{ty}>`"),
|
||||
);
|
||||
}
|
||||
(_, Some(ty))
|
||||
if let ty::Adt(def, _) = ty.kind()
|
||||
&& def.did().is_local() =>
|
||||
{
|
||||
err.span_note(
|
||||
self.tcx.def_span(def.did()),
|
||||
format!("`{ty}` needs to implement `Into<{self_ty}>`"),
|
||||
);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn report_const_param_not_wf(
|
||||
&self,
|
||||
ty: Ty<'tcx>,
|
||||
|
|
@ -2035,6 +2110,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
return false;
|
||||
}
|
||||
if let &[cand] = &candidates[..] {
|
||||
if self.tcx.is_diagnostic_item(sym::FromResidual, cand.def_id)
|
||||
&& !self.tcx.features().enabled(sym::try_trait_v2)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
let (desc, mention_castable) =
|
||||
match (cand.self_ty().kind(), trait_pred.self_ty().skip_binder().kind()) {
|
||||
(ty::FnPtr(..), ty::FnDef(..)) => {
|
||||
|
|
|
|||
|
|
@ -80,16 +80,14 @@ pub(crate) fn codegen_select_candidate<'tcx>(
|
|||
// but never resolved, causing the return value of a query to contain inference
|
||||
// vars. We do not have a concept for this and will in fact ICE in stable hashing
|
||||
// of the return value. So bail out instead.
|
||||
match impl_source {
|
||||
ImplSource::UserDefined(impl_) => {
|
||||
tcx.dcx().span_delayed_bug(
|
||||
tcx.def_span(impl_.impl_def_id),
|
||||
"this impl has unconstrained generic parameters",
|
||||
);
|
||||
}
|
||||
let guar = match impl_source {
|
||||
ImplSource::UserDefined(impl_) => tcx.dcx().span_delayed_bug(
|
||||
tcx.def_span(impl_.impl_def_id),
|
||||
"this impl has unconstrained generic parameters",
|
||||
),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
return Err(CodegenObligationError::FulfillmentError);
|
||||
};
|
||||
return Err(CodegenObligationError::UnconstrainedParam(guar));
|
||||
}
|
||||
|
||||
Ok(&*tcx.arena.alloc(impl_source))
|
||||
|
|
|
|||
|
|
@ -112,6 +112,7 @@ fn resolve_associated_item<'tcx>(
|
|||
| CodegenObligationError::Unimplemented
|
||||
| CodegenObligationError::FulfillmentError,
|
||||
) => return Ok(None),
|
||||
Err(CodegenObligationError::UnconstrainedParam(guar)) => return Err(guar),
|
||||
};
|
||||
|
||||
// Now that we know which impl is being used, we can dispatch to
|
||||
|
|
|
|||
|
|
@ -147,12 +147,25 @@ fn extract_const_value<'tcx>(
|
|||
) -> Result<ty::Value<'tcx>, &'tcx LayoutError<'tcx>> {
|
||||
match ct.kind() {
|
||||
ty::ConstKind::Value(cv) => Ok(cv),
|
||||
ty::ConstKind::Param(_) | ty::ConstKind::Expr(_) | ty::ConstKind::Unevaluated(_) => {
|
||||
ty::ConstKind::Param(_) | ty::ConstKind::Expr(_) => {
|
||||
if !ct.has_param() {
|
||||
bug!("failed to normalize const, but it is not generic: {ct:?}");
|
||||
}
|
||||
Err(error(cx, LayoutError::TooGeneric(ty)))
|
||||
}
|
||||
ty::ConstKind::Unevaluated(_) => {
|
||||
let err = if ct.has_param() {
|
||||
LayoutError::TooGeneric(ty)
|
||||
} else {
|
||||
// This case is reachable with unsatisfiable predicates and GCE (which will
|
||||
// cause anon consts to inherit the unsatisfiable predicates). For example
|
||||
// if we have an unsatisfiable `u8: Trait` bound, then it's not a compile
|
||||
// error to mention `[u8; <u8 as Trait>::CONST]`, but we can't compute its
|
||||
// layout.
|
||||
LayoutError::Unknown(ty)
|
||||
};
|
||||
Err(error(cx, err))
|
||||
}
|
||||
ty::ConstKind::Infer(_)
|
||||
| ty::ConstKind::Bound(..)
|
||||
| ty::ConstKind::Placeholder(_)
|
||||
|
|
|
|||
|
|
@ -44,25 +44,22 @@ pub trait Elaboratable<I: Interner> {
|
|||
}
|
||||
|
||||
pub struct ClauseWithSupertraitSpan<I: Interner> {
|
||||
pub pred: I::Predicate,
|
||||
pub clause: I::Clause,
|
||||
// Span of the supertrait predicatae that lead to this clause.
|
||||
pub supertrait_span: I::Span,
|
||||
}
|
||||
impl<I: Interner> ClauseWithSupertraitSpan<I> {
|
||||
pub fn new(pred: I::Predicate, span: I::Span) -> Self {
|
||||
ClauseWithSupertraitSpan { pred, supertrait_span: span }
|
||||
pub fn new(clause: I::Clause, span: I::Span) -> Self {
|
||||
ClauseWithSupertraitSpan { clause, supertrait_span: span }
|
||||
}
|
||||
}
|
||||
impl<I: Interner> Elaboratable<I> for ClauseWithSupertraitSpan<I> {
|
||||
fn predicate(&self) -> <I as Interner>::Predicate {
|
||||
self.pred
|
||||
self.clause.as_predicate()
|
||||
}
|
||||
|
||||
fn child(&self, clause: <I as Interner>::Clause) -> Self {
|
||||
ClauseWithSupertraitSpan {
|
||||
pred: clause.as_predicate(),
|
||||
supertrait_span: self.supertrait_span,
|
||||
}
|
||||
ClauseWithSupertraitSpan { clause, supertrait_span: self.supertrait_span }
|
||||
}
|
||||
|
||||
fn child_with_derived_cause(
|
||||
|
|
@ -72,7 +69,7 @@ impl<I: Interner> Elaboratable<I> for ClauseWithSupertraitSpan<I> {
|
|||
_parent_trait_pred: crate::Binder<I, crate::TraitPredicate<I>>,
|
||||
_index: usize,
|
||||
) -> Self {
|
||||
ClauseWithSupertraitSpan { pred: clause.as_predicate(), supertrait_span }
|
||||
ClauseWithSupertraitSpan { clause, supertrait_span }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1168,6 +1168,7 @@ impl Div<u32> for Duration {
|
|||
type Output = Duration;
|
||||
|
||||
#[inline]
|
||||
#[track_caller]
|
||||
fn div(self, rhs: u32) -> Duration {
|
||||
self.checked_div(rhs).expect("divide by zero error when dividing duration by scalar")
|
||||
}
|
||||
|
|
@ -1176,6 +1177,7 @@ impl Div<u32> for Duration {
|
|||
#[stable(feature = "time_augmented_assignment", since = "1.9.0")]
|
||||
impl DivAssign<u32> for Duration {
|
||||
#[inline]
|
||||
#[track_caller]
|
||||
fn div_assign(&mut self, rhs: u32) {
|
||||
*self = *self / rhs;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1762,7 +1762,9 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the
|
|||
cmd.arg("--coverage-dump-path").arg(coverage_dump);
|
||||
}
|
||||
|
||||
cmd.arg("--src-base").arg(builder.src.join("tests").join(suite));
|
||||
cmd.arg("--src-root").arg(&builder.src);
|
||||
cmd.arg("--src-test-suite-root").arg(builder.src.join("tests").join(suite));
|
||||
|
||||
cmd.arg("--build-base").arg(testdir(builder, compiler.host).join(suite));
|
||||
|
||||
// When top stage is 0, that means that we're testing an externally provided compiler.
|
||||
|
|
|
|||
|
|
@ -215,8 +215,10 @@ pub struct Config {
|
|||
/// `None` then these tests will be ignored.
|
||||
pub run_clang_based_tests_with: Option<String>,
|
||||
|
||||
/// The directory containing the tests to run
|
||||
pub src_base: PathBuf,
|
||||
/// The directory containing the sources.
|
||||
pub src_root: PathBuf,
|
||||
/// The directory containing the test suite sources. Must be a subdirectory of `src_root`.
|
||||
pub src_test_suite_root: PathBuf,
|
||||
|
||||
/// The directory where programs should be built
|
||||
pub build_base: PathBuf,
|
||||
|
|
|
|||
|
|
@ -1026,19 +1026,6 @@ impl Config {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn find_rust_src_root(&self) -> Option<PathBuf> {
|
||||
let mut path = self.src_base.clone();
|
||||
let path_postfix = Path::new("src/etc/lldb_batchmode.py");
|
||||
|
||||
while path.pop() {
|
||||
if path.join(&path_postfix).is_file() {
|
||||
return Some(path);
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
fn parse_edition(&self, line: &str) -> Option<String> {
|
||||
self.parse_name_value_directive(line, "edition")
|
||||
}
|
||||
|
|
@ -1098,7 +1085,7 @@ fn expand_variables(mut value: String, config: &Config) -> String {
|
|||
}
|
||||
|
||||
if value.contains(SRC_BASE) {
|
||||
value = value.replace(SRC_BASE, &config.src_base.to_string_lossy());
|
||||
value = value.replace(SRC_BASE, &config.src_test_suite_root.to_str().unwrap());
|
||||
}
|
||||
|
||||
if value.contains(BUILD_BASE) {
|
||||
|
|
|
|||
|
|
@ -153,7 +153,8 @@ impl ConfigBuilder {
|
|||
"--run-lib-path=",
|
||||
"--python=",
|
||||
"--jsondocck-path=",
|
||||
"--src-base=",
|
||||
"--src-root=",
|
||||
"--src-test-suite-root=",
|
||||
"--build-base=",
|
||||
"--sysroot-base=",
|
||||
"--cc=c",
|
||||
|
|
|
|||
|
|
@ -61,7 +61,8 @@ pub fn parse_config(args: Vec<String>) -> Config {
|
|||
.optopt("", "jsondoclint-path", "path to jsondoclint to use for doc tests", "PATH")
|
||||
.optopt("", "run-clang-based-tests-with", "path to Clang executable", "PATH")
|
||||
.optopt("", "llvm-filecheck", "path to LLVM's FileCheck binary", "DIR")
|
||||
.reqopt("", "src-base", "directory to scan for test files", "PATH")
|
||||
.reqopt("", "src-root", "directory containing sources", "PATH")
|
||||
.reqopt("", "src-test-suite-root", "directory containing test suite sources", "PATH")
|
||||
.reqopt("", "build-base", "directory to deposit test outputs", "PATH")
|
||||
.reqopt("", "sysroot-base", "directory containing the compiler sysroot", "PATH")
|
||||
.reqopt("", "stage", "stage number under test", "N")
|
||||
|
|
@ -243,7 +244,6 @@ pub fn parse_config(args: Vec<String>) -> Config {
|
|||
|| header::extract_llvm_version_from_binary(&matches.opt_str("llvm-filecheck")?),
|
||||
);
|
||||
|
||||
let src_base = opt_path(matches, "src-base");
|
||||
let run_ignored = matches.opt_present("ignored");
|
||||
let with_rustc_debug_assertions = matches.opt_present("with-rustc-debug-assertions");
|
||||
let with_std_debug_assertions = matches.opt_present("with-std-debug-assertions");
|
||||
|
|
@ -300,6 +300,15 @@ pub fn parse_config(args: Vec<String>) -> Config {
|
|||
None => panic!("`--stage` is required"),
|
||||
};
|
||||
|
||||
let src_root = opt_path(matches, "src-root");
|
||||
let src_test_suite_root = opt_path(matches, "src-test-suite-root");
|
||||
assert!(
|
||||
src_test_suite_root.starts_with(&src_root),
|
||||
"`src-root` must be a parent of `src-test-suite-root`: `src-root`=`{}`, `src-test-suite-root` = `{}`",
|
||||
src_root.display(),
|
||||
src_test_suite_root.display()
|
||||
);
|
||||
|
||||
Config {
|
||||
bless: matches.opt_present("bless"),
|
||||
compile_lib_path: make_absolute(opt_path(matches, "compile-lib-path")),
|
||||
|
|
@ -314,7 +323,10 @@ pub fn parse_config(args: Vec<String>) -> Config {
|
|||
run_clang_based_tests_with: matches.opt_str("run-clang-based-tests-with"),
|
||||
llvm_filecheck: matches.opt_str("llvm-filecheck").map(PathBuf::from),
|
||||
llvm_bin_dir: matches.opt_str("llvm-bin-dir").map(PathBuf::from),
|
||||
src_base,
|
||||
|
||||
src_root,
|
||||
src_test_suite_root,
|
||||
|
||||
build_base: opt_path(matches, "build-base"),
|
||||
sysroot_base: opt_path(matches, "sysroot-base"),
|
||||
|
||||
|
|
@ -422,7 +434,10 @@ pub fn log_config(config: &Config) {
|
|||
logv(c, format!("rustc_path: {:?}", config.rustc_path.display()));
|
||||
logv(c, format!("cargo_path: {:?}", config.cargo_path));
|
||||
logv(c, format!("rustdoc_path: {:?}", config.rustdoc_path));
|
||||
logv(c, format!("src_base: {:?}", config.src_base.display()));
|
||||
|
||||
logv(c, format!("src_root: {}", config.src_root.display()));
|
||||
logv(c, format!("src_test_suite_root: {}", config.src_test_suite_root.display()));
|
||||
|
||||
logv(c, format!("build_base: {:?}", config.build_base.display()));
|
||||
logv(c, format!("stage: {}", config.stage));
|
||||
logv(c, format!("stage_id: {}", config.stage_id));
|
||||
|
|
@ -620,20 +635,29 @@ struct TestCollector {
|
|||
/// regardless of whether any filters/tests were specified on the command-line,
|
||||
/// because filtering is handled later by libtest.
|
||||
pub fn collect_and_make_tests(config: Arc<Config>) -> Vec<test::TestDescAndFn> {
|
||||
debug!("making tests from {:?}", config.src_base.display());
|
||||
debug!("making tests from {}", config.src_test_suite_root.display());
|
||||
let common_inputs_stamp = common_inputs_stamp(&config);
|
||||
let modified_tests = modified_tests(&config, &config.src_base).unwrap_or_else(|err| {
|
||||
panic!("modified_tests got error from dir: {}, error: {}", config.src_base.display(), err)
|
||||
});
|
||||
let modified_tests =
|
||||
modified_tests(&config, &config.src_test_suite_root).unwrap_or_else(|err| {
|
||||
panic!(
|
||||
"modified_tests got error from dir: {}, error: {}",
|
||||
config.src_test_suite_root.display(),
|
||||
err
|
||||
)
|
||||
});
|
||||
let cache = HeadersCache::load(&config);
|
||||
|
||||
let cx = TestCollectorCx { config, cache, common_inputs_stamp, modified_tests };
|
||||
let mut collector =
|
||||
TestCollector { tests: vec![], found_path_stems: HashSet::new(), poisoned: false };
|
||||
|
||||
collect_tests_from_dir(&cx, &mut collector, &cx.config.src_base, Path::new("")).unwrap_or_else(
|
||||
|reason| panic!("Could not read tests from {}: {reason}", cx.config.src_base.display()),
|
||||
);
|
||||
collect_tests_from_dir(&cx, &mut collector, &cx.config.src_test_suite_root, Path::new(""))
|
||||
.unwrap_or_else(|reason| {
|
||||
panic!(
|
||||
"Could not read tests from {}: {reason}",
|
||||
cx.config.src_test_suite_root.display()
|
||||
)
|
||||
});
|
||||
|
||||
let TestCollector { tests, found_path_stems, poisoned } = collector;
|
||||
|
||||
|
|
@ -655,7 +679,7 @@ pub fn collect_and_make_tests(config: Arc<Config>) -> Vec<test::TestDescAndFn> {
|
|||
/// common to some subset of tests, and are hopefully unlikely to be modified
|
||||
/// while working on other tests.)
|
||||
fn common_inputs_stamp(config: &Config) -> Stamp {
|
||||
let rust_src_dir = config.find_rust_src_root().expect("Could not find Rust source root");
|
||||
let src_root = &config.src_root;
|
||||
|
||||
let mut stamp = Stamp::from_path(&config.rustc_path);
|
||||
|
||||
|
|
@ -670,17 +694,17 @@ fn common_inputs_stamp(config: &Config) -> Stamp {
|
|||
"src/etc/lldb_providers.py",
|
||||
];
|
||||
for file in &pretty_printer_files {
|
||||
let path = rust_src_dir.join(file);
|
||||
let path = src_root.join(file);
|
||||
stamp.add_path(&path);
|
||||
}
|
||||
|
||||
stamp.add_dir(&rust_src_dir.join("src/etc/natvis"));
|
||||
stamp.add_dir(&src_root.join("src/etc/natvis"));
|
||||
|
||||
stamp.add_dir(&config.run_lib_path);
|
||||
|
||||
if let Some(ref rustdoc_path) = config.rustdoc_path {
|
||||
stamp.add_path(&rustdoc_path);
|
||||
stamp.add_path(&rust_src_dir.join("src/etc/htmldocck.py"));
|
||||
stamp.add_path(&src_root.join("src/etc/htmldocck.py"));
|
||||
}
|
||||
|
||||
// Re-run coverage tests if the `coverage-dump` tool was modified,
|
||||
|
|
@ -689,10 +713,10 @@ fn common_inputs_stamp(config: &Config) -> Stamp {
|
|||
stamp.add_path(coverage_dump_path)
|
||||
}
|
||||
|
||||
stamp.add_dir(&rust_src_dir.join("src/tools/run-make-support"));
|
||||
stamp.add_dir(&src_root.join("src/tools/run-make-support"));
|
||||
|
||||
// Compiletest itself.
|
||||
stamp.add_dir(&rust_src_dir.join("src/tools/compiletest/"));
|
||||
stamp.add_dir(&src_root.join("src/tools/compiletest"));
|
||||
|
||||
stamp
|
||||
}
|
||||
|
|
@ -933,10 +957,7 @@ fn files_related_to_test(
|
|||
}
|
||||
|
||||
// `minicore.rs` test auxiliary: we need to make sure tests get rerun if this changes.
|
||||
//
|
||||
// FIXME(jieyouxu): untangle these paths, we should provide both a path to root `tests/` or
|
||||
// `tests/auxiliary/` and the test suite in question. `src_base` is also a terrible name.
|
||||
related.push(config.src_base.parent().unwrap().join("auxiliary").join("minicore.rs"));
|
||||
related.push(config.src_root.join("tests").join("auxiliary").join("minicore.rs"));
|
||||
|
||||
related
|
||||
}
|
||||
|
|
@ -1026,10 +1047,8 @@ fn make_test_name(
|
|||
testpaths: &TestPaths,
|
||||
revision: Option<&str>,
|
||||
) -> test::TestName {
|
||||
// Print the name of the file, relative to the repository root.
|
||||
// `src_base` looks like `/path/to/rust/tests/ui`
|
||||
let root_directory = config.src_base.parent().unwrap().parent().unwrap();
|
||||
let path = testpaths.file.strip_prefix(root_directory).unwrap();
|
||||
// Print the name of the file, relative to the sources root.
|
||||
let path = testpaths.file.strip_prefix(&config.src_root).unwrap();
|
||||
let debugger = match config.debugger {
|
||||
Some(d) => format!("-{}", d),
|
||||
None => String::new(),
|
||||
|
|
|
|||
|
|
@ -1365,7 +1365,7 @@ impl<'test> TestCx<'test> {
|
|||
//
|
||||
// Note: avoid adding a subdirectory of an already filtered directory here, otherwise the
|
||||
// same slice of text will be double counted and the truncation might not happen.
|
||||
add_path(&self.config.src_base);
|
||||
add_path(&self.config.src_test_suite_root);
|
||||
add_path(&self.config.build_base);
|
||||
|
||||
read2_abbreviated(child, &filter_paths_from_len).expect("failed to read output")
|
||||
|
|
@ -1471,7 +1471,7 @@ impl<'test> TestCx<'test> {
|
|||
// Similarly, vendored sources shouldn't be shown when running from a dist tarball.
|
||||
rustc.arg("-Z").arg(format!(
|
||||
"ignore-directory-in-diagnostics-source-blocks={}",
|
||||
self.config.find_rust_src_root().unwrap().join("vendor").display(),
|
||||
self.config.src_root.join("vendor").to_str().unwrap(),
|
||||
));
|
||||
|
||||
// Optionally prevent default --sysroot if specified in test compile-flags.
|
||||
|
|
@ -1632,7 +1632,7 @@ impl<'test> TestCx<'test> {
|
|||
if self.props.remap_src_base {
|
||||
rustc.arg(format!(
|
||||
"--remap-path-prefix={}={}",
|
||||
self.config.src_base.display(),
|
||||
self.config.src_test_suite_root.to_str().unwrap(),
|
||||
FAKE_SRC_BASE,
|
||||
));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -257,11 +257,8 @@ impl TestCx<'_> {
|
|||
println!("Adb process is already finished.");
|
||||
}
|
||||
} else {
|
||||
let rust_src_root =
|
||||
self.config.find_rust_src_root().expect("Could not find Rust source root");
|
||||
let rust_pp_module_rel_path = Path::new("./src/etc");
|
||||
let rust_pp_module_abs_path =
|
||||
rust_src_root.join(rust_pp_module_rel_path).to_str().unwrap().to_owned();
|
||||
let rust_pp_module_abs_path = self.config.src_root.join("src").join("etc");
|
||||
let rust_pp_module_abs_path = rust_pp_module_abs_path.to_str().unwrap();
|
||||
// write debugger script
|
||||
let mut script_str = String::with_capacity(2048);
|
||||
script_str.push_str(&format!("set charset {}\n", Self::charset()));
|
||||
|
|
@ -338,7 +335,7 @@ impl TestCx<'_> {
|
|||
let pythonpath = if let Ok(pp) = std::env::var("PYTHONPATH") {
|
||||
format!("{pp}:{rust_pp_module_abs_path}")
|
||||
} else {
|
||||
rust_pp_module_abs_path
|
||||
rust_pp_module_abs_path.to_string()
|
||||
};
|
||||
gdb.args(debugger_opts).env("PYTHONPATH", pythonpath);
|
||||
|
||||
|
|
@ -407,11 +404,8 @@ impl TestCx<'_> {
|
|||
// Make LLDB emit its version, so we have it documented in the test output
|
||||
script_str.push_str("version\n");
|
||||
|
||||
// Switch LLDB into "Rust mode"
|
||||
let rust_src_root =
|
||||
self.config.find_rust_src_root().expect("Could not find Rust source root");
|
||||
let rust_pp_module_rel_path = Path::new("./src/etc");
|
||||
let rust_pp_module_abs_path = rust_src_root.join(rust_pp_module_rel_path);
|
||||
// Switch LLDB into "Rust mode".
|
||||
let rust_pp_module_abs_path = self.config.src_root.join("src/etc");
|
||||
|
||||
script_str.push_str(&format!(
|
||||
"command script import {}/lldb_lookup.py\n",
|
||||
|
|
@ -445,7 +439,7 @@ impl TestCx<'_> {
|
|||
let debugger_script = self.make_out_name("debugger.script");
|
||||
|
||||
// Let LLDB execute the script via lldb_batchmode.py
|
||||
let debugger_run_result = self.run_lldb(&exe_file, &debugger_script, &rust_src_root);
|
||||
let debugger_run_result = self.run_lldb(&exe_file, &debugger_script);
|
||||
|
||||
if !debugger_run_result.status.success() {
|
||||
self.fatal_proc_rec("Error while running LLDB", &debugger_run_result);
|
||||
|
|
@ -456,18 +450,13 @@ impl TestCx<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
fn run_lldb(
|
||||
&self,
|
||||
test_executable: &Path,
|
||||
debugger_script: &Path,
|
||||
rust_src_root: &Path,
|
||||
) -> ProcRes {
|
||||
fn run_lldb(&self, test_executable: &Path, debugger_script: &Path) -> ProcRes {
|
||||
// Prepare the lldb_batchmode which executes the debugger script
|
||||
let lldb_script_path = rust_src_root.join("src/etc/lldb_batchmode.py");
|
||||
let lldb_script_path = self.config.src_root.join("src/etc/lldb_batchmode.py");
|
||||
let pythonpath = if let Ok(pp) = std::env::var("PYTHONPATH") {
|
||||
format!("{pp}:{}", self.config.lldb_python_dir.as_ref().unwrap())
|
||||
} else {
|
||||
self.config.lldb_python_dir.as_ref().unwrap().to_string()
|
||||
self.config.lldb_python_dir.clone().unwrap()
|
||||
};
|
||||
self.run_command_to_procres(
|
||||
Command::new(&self.config.python)
|
||||
|
|
|
|||
|
|
@ -9,12 +9,11 @@ impl TestCx<'_> {
|
|||
|
||||
self.document(&out_dir, &self.testpaths);
|
||||
|
||||
let root = self.config.find_rust_src_root().unwrap();
|
||||
let file_stem =
|
||||
self.testpaths.file.file_stem().and_then(|f| f.to_str()).expect("no file stem");
|
||||
let res = self.run_command_to_procres(
|
||||
Command::new(&nodejs)
|
||||
.arg(root.join("src/tools/rustdoc-js/tester.js"))
|
||||
.arg(self.config.src_root.join("src/tools/rustdoc-js/tester.js"))
|
||||
.arg("--doc-folder")
|
||||
.arg(out_dir)
|
||||
.arg("--crate-name")
|
||||
|
|
|
|||
|
|
@ -21,8 +21,6 @@ impl TestCx<'_> {
|
|||
|
||||
fn run_rmake_legacy_test(&self) {
|
||||
let cwd = env::current_dir().unwrap();
|
||||
let src_root = self.config.src_base.parent().unwrap().parent().unwrap();
|
||||
let src_root = cwd.join(&src_root);
|
||||
|
||||
// FIXME(Zalathar): This should probably be `output_base_dir` to avoid
|
||||
// an unnecessary extra subdirectory, but since legacy Makefile tests
|
||||
|
|
@ -51,7 +49,7 @@ impl TestCx<'_> {
|
|||
.stderr(Stdio::piped())
|
||||
.env("TARGET", &self.config.target)
|
||||
.env("PYTHON", &self.config.python)
|
||||
.env("S", src_root)
|
||||
.env("S", &self.config.src_root)
|
||||
.env("RUST_BUILD_STAGE", &self.config.stage_id)
|
||||
.env("RUSTC", cwd.join(&self.config.rustc_path))
|
||||
.env("TMPDIR", &tmpdir)
|
||||
|
|
@ -181,28 +179,10 @@ impl TestCx<'_> {
|
|||
// library.
|
||||
// 2. We need to run the recipe binary.
|
||||
|
||||
// So we assume the rust-lang/rust project setup looks like the following (our `.` is the
|
||||
// top-level directory, irrelevant entries to our purposes omitted):
|
||||
//
|
||||
// ```
|
||||
// . // <- `source_root`
|
||||
// ├── build/ // <- `build_root`
|
||||
// ├── compiler/
|
||||
// ├── library/
|
||||
// ├── src/
|
||||
// │ └── tools/
|
||||
// │ └── run_make_support/
|
||||
// └── tests
|
||||
// └── run-make/
|
||||
// ```
|
||||
|
||||
// `source_root` is the top-level directory containing the rust-lang/rust checkout.
|
||||
let source_root =
|
||||
self.config.find_rust_src_root().expect("could not determine rust source root");
|
||||
// `self.config.build_base` is actually the build base folder + "test" + test suite name, it
|
||||
// looks like `build/<host_triple>/test/run-make`. But we want `build/<host_triple>/`. Note
|
||||
// that the `build` directory does not need to be called `build`, nor does it need to be
|
||||
// under `source_root`, so we must compute it based off of `self.config.build_base`.
|
||||
// under `src_root`, so we must compute it based off of `self.config.build_base`.
|
||||
let build_root =
|
||||
self.config.build_base.parent().and_then(Path::parent).unwrap().to_path_buf();
|
||||
|
||||
|
|
@ -389,10 +369,9 @@ impl TestCx<'_> {
|
|||
.env("TARGET", &self.config.target)
|
||||
// Some tests unfortunately still need Python, so provide path to a Python interpreter.
|
||||
.env("PYTHON", &self.config.python)
|
||||
// Provide path to checkout root. This is the top-level directory containing
|
||||
// rust-lang/rust checkout.
|
||||
.env("SOURCE_ROOT", &source_root)
|
||||
// Path to the build directory. This is usually the same as `source_root.join("build").join("host")`.
|
||||
// Provide path to sources root.
|
||||
.env("SOURCE_ROOT", &self.config.src_root)
|
||||
// Path to the host build directory.
|
||||
.env("BUILD_ROOT", &build_root)
|
||||
// Provide path to stage-corresponding rustc.
|
||||
.env("RUSTC", &self.config.rustc_path)
|
||||
|
|
@ -408,11 +387,11 @@ impl TestCx<'_> {
|
|||
.env("LLVM_COMPONENTS", &self.config.llvm_components);
|
||||
|
||||
if let Some(ref cargo) = self.config.cargo_path {
|
||||
cmd.env("CARGO", source_root.join(cargo));
|
||||
cmd.env("CARGO", cargo);
|
||||
}
|
||||
|
||||
if let Some(ref rustdoc) = self.config.rustdoc_path {
|
||||
cmd.env("RUSTDOC", source_root.join(rustdoc));
|
||||
cmd.env("RUSTDOC", rustdoc);
|
||||
}
|
||||
|
||||
if let Some(ref node) = self.config.nodejs {
|
||||
|
|
|
|||
|
|
@ -17,9 +17,10 @@ impl TestCx<'_> {
|
|||
if self.props.check_test_line_numbers_match {
|
||||
self.check_rustdoc_test_option(proc_res);
|
||||
} else {
|
||||
let root = self.config.find_rust_src_root().unwrap();
|
||||
let mut cmd = Command::new(&self.config.python);
|
||||
cmd.arg(root.join("src/etc/htmldocck.py")).arg(&out_dir).arg(&self.testpaths.file);
|
||||
cmd.arg(self.config.src_root.join("src/etc/htmldocck.py"))
|
||||
.arg(&out_dir)
|
||||
.arg(&self.testpaths.file);
|
||||
if self.config.bless {
|
||||
cmd.arg("--bless");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,20 +0,0 @@
|
|||
//@ known-bug: rust-lang/rust#125957
|
||||
#![feature(generic_const_exprs)]
|
||||
#![allow(incomplete_features)]
|
||||
#![feature(associated_const_equality)]
|
||||
|
||||
pub struct Equal<const T: usize, const R: usize>();
|
||||
|
||||
pub enum ParseMode {
|
||||
Raw,
|
||||
}
|
||||
pub trait Parse {
|
||||
const PARSE_MODE: ParseMode;
|
||||
}
|
||||
pub trait RenderRaw: Parse<PARSE_MODE = { ParseMode::Raw }> {}
|
||||
|
||||
trait GenericVec<T> {
|
||||
fn unwrap() -> dyn RenderRaw;
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
//@ known-bug: #132330
|
||||
//@compile-flags: -Znext-solver=globally
|
||||
|
||||
trait Service {
|
||||
type S;
|
||||
}
|
||||
|
||||
trait Framing {
|
||||
type F;
|
||||
}
|
||||
|
||||
impl Framing for () {
|
||||
type F = ();
|
||||
}
|
||||
|
||||
trait HttpService<F: Framing>: Service<S = F::F> {}
|
||||
|
||||
type BoxService = Box<dyn HttpService<(), S = ()>>;
|
||||
|
||||
fn build_server<F: FnOnce() -> BoxService>(_: F) {}
|
||||
|
||||
fn make_server<F: Framing>() -> Box<dyn HttpService<F, S = F::F>> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn main() {
|
||||
build_server(|| make_server())
|
||||
}
|
||||
|
|
@ -2,11 +2,13 @@
|
|||
// Similar to stress testing, the test case requires a larger call stack,
|
||||
// so we ignore rustc's debug assertions.
|
||||
|
||||
//@ build-pass
|
||||
// ignore-tidy-linelength
|
||||
|
||||
// Regression for #93775, needs build-pass to test it.
|
||||
|
||||
//@ build-pass
|
||||
//@ revisions: current next
|
||||
//@ ignore-compare-mode-next-solver (explicit revisions)
|
||||
//@[next] compile-flags: -Znext-solver
|
||||
|
||||
#![recursion_limit = "1001"]
|
||||
|
||||
use std::marker::PhantomData;
|
||||
|
|
@ -14,7 +16,64 @@ use std::marker::PhantomData;
|
|||
struct Z;
|
||||
struct S<T>(PhantomData<T>);
|
||||
|
||||
type Nested = S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<Z>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>;
|
||||
type Nested = S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S
|
||||
<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S
|
||||
<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S
|
||||
<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S
|
||||
<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S
|
||||
<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S
|
||||
<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S
|
||||
<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S
|
||||
<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S
|
||||
<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S
|
||||
<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S
|
||||
<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S
|
||||
<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S
|
||||
<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S
|
||||
<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S
|
||||
<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S
|
||||
<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S
|
||||
<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S
|
||||
<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S
|
||||
<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S
|
||||
<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S
|
||||
<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S
|
||||
<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S
|
||||
<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S
|
||||
<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S
|
||||
<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S
|
||||
<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S
|
||||
<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S
|
||||
<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S
|
||||
<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S
|
||||
<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S
|
||||
<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S
|
||||
<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S
|
||||
<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S
|
||||
<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S
|
||||
<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S
|
||||
<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S
|
||||
<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S
|
||||
<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<Z>>>>>>>>>>>>>>
|
||||
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>;
|
||||
|
||||
trait AsNum {
|
||||
const NUM: u32;
|
||||
|
|
|
|||
|
|
@ -4,5 +4,5 @@ trait I32Iterator = Iterator<Item = i32>;
|
|||
|
||||
fn main() {
|
||||
let _: &dyn I32Iterator<Item = u32> = &vec![42].into_iter();
|
||||
//~^ ERROR expected `IntoIter<u32>` to be an iterator that yields `i32`, but it yields `u32`
|
||||
//~^ ERROR conflicting associated type bounds
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,13 @@
|
|||
error[E0271]: expected `IntoIter<u32>` to be an iterator that yields `i32`, but it yields `u32`
|
||||
--> $DIR/associated-types-overridden-binding-2.rs:6:43
|
||||
error: conflicting associated type bounds for `Item` when expanding trait alias
|
||||
--> $DIR/associated-types-overridden-binding-2.rs:6:13
|
||||
|
|
||||
LL | trait I32Iterator = Iterator<Item = i32>;
|
||||
| ---------- `Item` is specified to be `i32` here
|
||||
...
|
||||
LL | let _: &dyn I32Iterator<Item = u32> = &vec![42].into_iter();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `u32`
|
||||
|
|
||||
= note: required for the cast from `&std::vec::IntoIter<u32>` to `&dyn Iterator<Item = u32, Item = i32>`
|
||||
| ^^^^^^^^^^^^^^^^----------^
|
||||
| |
|
||||
| `Item` is specified to be `u32` here
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0271`.
|
||||
|
|
|
|||
|
|
@ -8,4 +8,5 @@ trait U32Iterator = I32Iterator<Item = u32>; //~ ERROR type annotations needed
|
|||
|
||||
fn main() {
|
||||
let _: &dyn I32Iterator<Item = u32>;
|
||||
//~^ ERROR conflicting associated type bounds
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,17 @@ note: required by a bound in `I32Iterator`
|
|||
LL | trait I32Iterator = Iterator<Item = i32>;
|
||||
| ^^^^^^^^^^ required by this bound in `I32Iterator`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
error: conflicting associated type bounds for `Item` when expanding trait alias
|
||||
--> $DIR/associated-types-overridden-binding.rs:10:13
|
||||
|
|
||||
LL | trait I32Iterator = Iterator<Item = i32>;
|
||||
| ---------- `Item` is specified to be `i32` here
|
||||
...
|
||||
LL | let _: &dyn I32Iterator<Item = u32>;
|
||||
| ^^^^^^^^^^^^^^^^----------^
|
||||
| |
|
||||
| `Item` is specified to be `u32` here
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0284`.
|
||||
|
|
|
|||
|
|
@ -17,8 +17,6 @@ LL | | test()?;
|
|||
... |
|
||||
LL | | }
|
||||
| |_- this function should return `Result` or `Option` to accept `?`
|
||||
|
|
||||
= help: the trait `FromResidual<_>` is not implemented for `()`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
|
|
|||
|
|
@ -6,8 +6,6 @@ LL | async {
|
|||
LL | let x: Option<u32> = None;
|
||||
LL | x?;
|
||||
| ^ cannot use the `?` operator in an async block that returns `{integer}`
|
||||
|
|
||||
= help: the trait `FromResidual<Option<Infallible>>` is not implemented for `{integer}`
|
||||
|
||||
error[E0277]: the `?` operator can only be used in an async closure that returns `Result` or `Option` (or another type that implements `FromResidual`)
|
||||
--> $DIR/try-on-option-in-async.rs:16:10
|
||||
|
|
@ -20,8 +18,6 @@ LL | | x?;
|
|||
LL | | 22_u32
|
||||
LL | | };
|
||||
| |_____- this function should return `Result` or `Option` to accept `?`
|
||||
|
|
||||
= help: the trait `FromResidual<Option<Infallible>>` is not implemented for `u32`
|
||||
|
||||
error[E0277]: the `?` operator can only be used in an async function that returns `Result` or `Option` (or another type that implements `FromResidual`)
|
||||
--> $DIR/try-on-option-in-async.rs:25:6
|
||||
|
|
@ -34,8 +30,6 @@ LL | | x?;
|
|||
LL | | 22
|
||||
LL | | }
|
||||
| |_- this function should return `Result` or `Option` to accept `?`
|
||||
|
|
||||
= help: the trait `FromResidual<Option<Infallible>>` is not implemented for `u32`
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
|
|
|
|||
18
tests/ui/closures/deduce-from-object-supertrait.rs
Normal file
18
tests/ui/closures/deduce-from-object-supertrait.rs
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
//@ check-pass
|
||||
|
||||
// This test checks that we look at consider the super traits of trait objects
|
||||
// when deducing closure signatures.
|
||||
|
||||
trait Foo: Fn(Bar) {}
|
||||
impl<T> Foo for T where T: Fn(Bar) {}
|
||||
|
||||
struct Bar;
|
||||
impl Bar {
|
||||
fn bar(&self) {}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x: &dyn Foo = &|x| {
|
||||
x.bar();
|
||||
};
|
||||
}
|
||||
21
tests/ui/dyn-compatibility/multiple-supers-should-work.rs
Normal file
21
tests/ui/dyn-compatibility/multiple-supers-should-work.rs
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
//@ check-pass
|
||||
|
||||
// We previously incorrectly deduplicated the list of projection bounds
|
||||
// of trait objects, causing us to incorrectly reject this code, cc #136458.
|
||||
|
||||
trait Sup<T> {
|
||||
type Assoc;
|
||||
}
|
||||
|
||||
impl<T> Sup<T> for () {
|
||||
type Assoc = T;
|
||||
}
|
||||
|
||||
trait Trait<A, B>: Sup<A, Assoc = A> + Sup<B, Assoc = B> {}
|
||||
|
||||
impl<T, U> Trait<T, U> for () {}
|
||||
|
||||
fn main() {
|
||||
let x: &dyn Trait<(), _> = &();
|
||||
let y: &dyn Trait<_, ()> = x;
|
||||
}
|
||||
|
|
@ -1,13 +1,13 @@
|
|||
//@ known-bug: #117647
|
||||
//@ edition: 2024
|
||||
|
||||
#![feature(lifetime_capture_rules_2024)]
|
||||
#![feature(rustc_attrs)]
|
||||
#![allow(internal_features)]
|
||||
#![rustc_variance_of_opaques]
|
||||
|
||||
use std::ops::Deref;
|
||||
|
||||
fn foo(x: Vec<i32>) -> Box<dyn for<'a> Deref<Target = impl ?Sized>> {
|
||||
fn foo(x: Vec<i32>) -> Box<dyn for<'a> Deref<Target = impl ?Sized>> { //~ ['a: o]
|
||||
//~^ ERROR cannot capture higher-ranked lifetime
|
||||
Box::new(x)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,17 +1,17 @@
|
|||
error[E0657]: `impl Trait` cannot capture higher-ranked lifetime from `dyn` type
|
||||
--> $DIR/implicit-capture-late.rs:10:55
|
||||
--> $DIR/implicit-capture-late.rs:9:55
|
||||
|
|
||||
LL | fn foo(x: Vec<i32>) -> Box<dyn for<'a> Deref<Target = impl ?Sized>> {
|
||||
| ^^^^^^^^^^^ `impl Trait` implicitly captures all lifetimes in scope
|
||||
|
|
||||
note: lifetime declared here
|
||||
--> $DIR/implicit-capture-late.rs:10:36
|
||||
--> $DIR/implicit-capture-late.rs:9:36
|
||||
|
|
||||
LL | fn foo(x: Vec<i32>) -> Box<dyn for<'a> Deref<Target = impl ?Sized>> {
|
||||
| ^^
|
||||
|
||||
error: ['a: o]
|
||||
--> $DIR/implicit-capture-late.rs:10:55
|
||||
--> $DIR/implicit-capture-late.rs:9:55
|
||||
|
|
||||
LL | fn foo(x: Vec<i32>) -> Box<dyn for<'a> Deref<Target = impl ?Sized>> {
|
||||
| ^^^^^^^^^^^
|
||||
|
|
|
|||
|
|
@ -1,9 +1,8 @@
|
|||
//@ check-pass
|
||||
//@ edition: 2024
|
||||
|
||||
// Show how precise captures allow us to skip capturing a higher-ranked lifetime
|
||||
|
||||
#![feature(lifetime_capture_rules_2024)]
|
||||
|
||||
trait Trait<'a> {
|
||||
type Item;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,8 @@
|
|||
//@ check-pass
|
||||
//@ edition: 2024
|
||||
|
||||
// Show that precise captures allow us to skip a lifetime param for outlives
|
||||
|
||||
#![feature(lifetime_capture_rules_2024)]
|
||||
|
||||
fn hello<'a: 'a, 'b: 'b>() -> impl Sized + use<'a> { }
|
||||
|
||||
fn outlives<'a, T: 'a>(_: T) {}
|
||||
|
|
|
|||
|
|
@ -1,23 +1,23 @@
|
|||
error: ['a: *, 'a: o]
|
||||
--> $DIR/variance.rs:13:36
|
||||
--> $DIR/variance.rs:11:36
|
||||
|
|
||||
LL | fn not_captured_early<'a: 'a>() -> impl Sized {}
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: ['a: *, 'a: o]
|
||||
--> $DIR/variance.rs:18:32
|
||||
--> $DIR/variance.rs:15:32
|
||||
|
|
||||
LL | fn captured_early<'a: 'a>() -> impl Sized + Captures<'a> {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: ['a: o]
|
||||
--> $DIR/variance.rs:20:40
|
||||
--> $DIR/variance.rs:17:40
|
||||
|
|
||||
LL | fn not_captured_late<'a>(_: &'a ()) -> impl Sized {}
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: ['a: o]
|
||||
--> $DIR/variance.rs:25:36
|
||||
--> $DIR/variance.rs:21:36
|
||||
|
|
||||
LL | fn captured_late<'a>(_: &'a ()) -> impl Sized + Captures<'a> {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
|
|||
|
|
@ -1,26 +0,0 @@
|
|||
error: ['a: *, 'a: o]
|
||||
--> $DIR/variance.rs:13:36
|
||||
|
|
||||
LL | fn not_captured_early<'a: 'a>() -> impl Sized {}
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: ['a: *, 'a: o]
|
||||
--> $DIR/variance.rs:18:32
|
||||
|
|
||||
LL | fn captured_early<'a: 'a>() -> impl Sized + Captures<'a> {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: ['a: o]
|
||||
--> $DIR/variance.rs:20:40
|
||||
|
|
||||
LL | fn not_captured_late<'a>(_: &'a ()) -> impl Sized {}
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: ['a: o]
|
||||
--> $DIR/variance.rs:25:36
|
||||
|
|
||||
LL | fn captured_late<'a>(_: &'a ()) -> impl Sized + Captures<'a> {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
|
|
@ -1,23 +1,23 @@
|
|||
error: ['a: *]
|
||||
--> $DIR/variance.rs:13:36
|
||||
--> $DIR/variance.rs:11:36
|
||||
|
|
||||
LL | fn not_captured_early<'a: 'a>() -> impl Sized {}
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: ['a: *, 'a: o]
|
||||
--> $DIR/variance.rs:18:32
|
||||
--> $DIR/variance.rs:15:32
|
||||
|
|
||||
LL | fn captured_early<'a: 'a>() -> impl Sized + Captures<'a> {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: []
|
||||
--> $DIR/variance.rs:20:40
|
||||
--> $DIR/variance.rs:17:40
|
||||
|
|
||||
LL | fn not_captured_late<'a>(_: &'a ()) -> impl Sized {}
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: ['a: o]
|
||||
--> $DIR/variance.rs:25:36
|
||||
--> $DIR/variance.rs:21:36
|
||||
|
|
||||
LL | fn captured_late<'a>(_: &'a ()) -> impl Sized + Captures<'a> {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
//@ revisions: old new e2024
|
||||
//@ revisions: old e2024
|
||||
//@[e2024] edition: 2024
|
||||
|
||||
#![cfg_attr(new, feature(lifetime_capture_rules_2024))]
|
||||
|
||||
#![feature(rustc_attrs)]
|
||||
#![allow(internal_features)]
|
||||
#![rustc_variance_of_opaques]
|
||||
|
|
@ -12,15 +10,13 @@ impl<T> Captures<'_> for T {}
|
|||
|
||||
fn not_captured_early<'a: 'a>() -> impl Sized {}
|
||||
//[old]~^ ['a: *]
|
||||
//[new]~^^ ['a: *, 'a: o]
|
||||
//[e2024]~^^^ ['a: *, 'a: o]
|
||||
//[e2024]~^^ ['a: *, 'a: o]
|
||||
|
||||
fn captured_early<'a: 'a>() -> impl Sized + Captures<'a> {} //~ ['a: *, 'a: o]
|
||||
|
||||
fn not_captured_late<'a>(_: &'a ()) -> impl Sized {}
|
||||
//[old]~^ []
|
||||
//[new]~^^ ['a: o]
|
||||
//[e2024]~^^^ ['a: o]
|
||||
//[e2024]~^^ ['a: o]
|
||||
|
||||
fn captured_late<'a>(_: &'a ()) -> impl Sized + Captures<'a> {} //~ ['a: o]
|
||||
|
||||
|
|
|
|||
27
tests/ui/layout/gce-rigid-const-in-array-len.rs
Normal file
27
tests/ui/layout/gce-rigid-const-in-array-len.rs
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
//! With `feature(generic_const_exprs)`, anon consts (e.g. length in array types) will
|
||||
//! inherit their parent's predicates. When combined with `feature(trivial_bounds)`, it
|
||||
//! is possible to have an unevaluated constant that is rigid, but not generic.
|
||||
//!
|
||||
//! This is what happens below: `u8: A` does not hold in the global environment, but
|
||||
//! with trivial bounds + GCE it it possible that `<u8 as A>::B` can appear in an array
|
||||
//! length without causing a compile error. This constant is *rigid* (i.e. it cannot be
|
||||
//! normalized further), but it is *not generic* (i.e. it does not depend on any generic
|
||||
//! parameters).
|
||||
//!
|
||||
//! This test ensures that we do not ICE in layout computation when encountering such a
|
||||
//! constant.
|
||||
|
||||
#![feature(rustc_attrs)]
|
||||
#![feature(generic_const_exprs)] //~ WARNING: the feature `generic_const_exprs` is incomplete
|
||||
#![feature(trivial_bounds)]
|
||||
|
||||
#![crate_type = "lib"]
|
||||
|
||||
trait A {
|
||||
const B: usize;
|
||||
}
|
||||
|
||||
#[rustc_layout(debug)]
|
||||
struct S([u8; <u8 as A>::B]) //~ ERROR: the type `[u8; <u8 as A>::B]` has an unknown layout
|
||||
where
|
||||
u8: A;
|
||||
17
tests/ui/layout/gce-rigid-const-in-array-len.stderr
Normal file
17
tests/ui/layout/gce-rigid-const-in-array-len.stderr
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||
--> $DIR/gce-rigid-const-in-array-len.rs:15:12
|
||||
|
|
||||
LL | #![feature(generic_const_exprs)]
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #76560 <https://github.com/rust-lang/rust/issues/76560> for more information
|
||||
= note: `#[warn(incomplete_features)]` on by default
|
||||
|
||||
error: the type `[u8; <u8 as A>::B]` has an unknown layout
|
||||
--> $DIR/gce-rigid-const-in-array-len.rs:25:1
|
||||
|
|
||||
LL | struct S([u8; <u8 as A>::B])
|
||||
| ^^^^^^^^
|
||||
|
||||
error: aborting due to 1 previous error; 1 warning emitted
|
||||
|
||||
18
tests/ui/layout/unconstrained-param-ice-137308.rs
Normal file
18
tests/ui/layout/unconstrained-param-ice-137308.rs
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
//! Regression test for <https://github.com/rust-lang/rust/issues/137308>.
|
||||
//!
|
||||
//! This used to ICE in layout computation, because `<u8 as A>::B` fails to normalize
|
||||
//! due to the unconstrained param on the impl.
|
||||
|
||||
#![feature(rustc_attrs)]
|
||||
#![crate_type = "lib"]
|
||||
|
||||
trait A {
|
||||
const B: usize;
|
||||
}
|
||||
|
||||
impl<C: ?Sized> A for u8 { //~ ERROR: the type parameter `C` is not constrained
|
||||
const B: usize = 42;
|
||||
}
|
||||
|
||||
#[rustc_layout(debug)]
|
||||
struct S([u8; <u8 as A>::B]); //~ ERROR: the type has an unknown layout
|
||||
15
tests/ui/layout/unconstrained-param-ice-137308.stderr
Normal file
15
tests/ui/layout/unconstrained-param-ice-137308.stderr
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
error[E0207]: the type parameter `C` is not constrained by the impl trait, self type, or predicates
|
||||
--> $DIR/unconstrained-param-ice-137308.rs:13:6
|
||||
|
|
||||
LL | impl<C: ?Sized> A for u8 {
|
||||
| ^ unconstrained type parameter
|
||||
|
||||
error: the type has an unknown layout
|
||||
--> $DIR/unconstrained-param-ice-137308.rs:18:1
|
||||
|
|
||||
LL | struct S([u8; <u8 as A>::B]);
|
||||
| ^^^^^^^^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0207`.
|
||||
27
tests/ui/lint/unaligned_references_fake_borrow.rs
Normal file
27
tests/ui/lint/unaligned_references_fake_borrow.rs
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
//@ check-pass
|
||||
|
||||
// Regression test for <https://github.com/rust-lang/rust/issues/137250>.
|
||||
|
||||
// Ensure that we don't emit unaligned packed field reference errors for the fake
|
||||
// borrows that we generate during match lowering. These fake borrows are there to
|
||||
// ensure in *borrow-checking* that we don't modify the value being matched, but
|
||||
// they are removed after the MIR is processed by `CleanupPostBorrowck`.
|
||||
|
||||
#[repr(packed)]
|
||||
pub struct Packed(i32);
|
||||
|
||||
fn f(x: Packed) {
|
||||
match &x {
|
||||
Packed(4) => {},
|
||||
_ if true => {},
|
||||
_ => {}
|
||||
}
|
||||
|
||||
match x {
|
||||
Packed(4) => {},
|
||||
_ if true => {},
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -6,7 +6,6 @@ LL | fn test1() {
|
|||
LL | let mut _file = File::create("foo.txt")?;
|
||||
| ^ cannot use the `?` operator in a function that returns `()`
|
||||
|
|
||||
= help: the trait `FromResidual<Result<Infallible, std::io::Error>>` is not implemented for `()`
|
||||
help: consider adding return type
|
||||
|
|
||||
LL ~ fn test1() -> Result<(), Box<dyn std::error::Error>> {
|
||||
|
|
@ -23,7 +22,6 @@ LL | fn test2() {
|
|||
LL | let mut _file = File::create("foo.txt")?;
|
||||
| ^ cannot use the `?` operator in a function that returns `()`
|
||||
|
|
||||
= help: the trait `FromResidual<Result<Infallible, std::io::Error>>` is not implemented for `()`
|
||||
help: consider adding return type
|
||||
|
|
||||
LL ~ fn test2() -> Result<(), Box<dyn std::error::Error>> {
|
||||
|
|
@ -41,7 +39,6 @@ LL | fn test4(&self) {
|
|||
LL | let mut _file = File::create("foo.txt")?;
|
||||
| ^ cannot use the `?` operator in a method that returns `()`
|
||||
|
|
||||
= help: the trait `FromResidual<Result<Infallible, std::io::Error>>` is not implemented for `()`
|
||||
help: consider adding return type
|
||||
|
|
||||
LL ~ fn test4(&self) -> Result<(), Box<dyn std::error::Error>> {
|
||||
|
|
@ -59,7 +56,6 @@ LL | fn test5(&self) {
|
|||
LL | let mut _file = File::create("foo.txt")?;
|
||||
| ^ cannot use the `?` operator in a method that returns `()`
|
||||
|
|
||||
= help: the trait `FromResidual<Result<Infallible, std::io::Error>>` is not implemented for `()`
|
||||
help: consider adding return type
|
||||
|
|
||||
LL ~ fn test5(&self) -> Result<(), Box<dyn std::error::Error>> {
|
||||
|
|
@ -78,7 +74,6 @@ LL | fn main() {
|
|||
LL | let mut _file = File::create("foo.txt")?;
|
||||
| ^ cannot use the `?` operator in a function that returns `()`
|
||||
|
|
||||
= help: the trait `FromResidual<Result<Infallible, std::io::Error>>` is not implemented for `()`
|
||||
help: consider adding return type
|
||||
|
|
||||
LL ~ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
|
|
@ -99,7 +94,6 @@ LL | let mut _file = File::create("foo.txt")?;
|
|||
LL | mac!();
|
||||
| ------ in this macro invocation
|
||||
|
|
||||
= help: the trait `FromResidual<Result<Infallible, std::io::Error>>` is not implemented for `()`
|
||||
= note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
help: consider adding return type
|
||||
|
|
||||
|
|
|
|||
|
|
@ -1,9 +1,12 @@
|
|||
//@ known-bug: rust-lang/rust#126944
|
||||
//@ check-pass
|
||||
|
||||
// Regression test for #126944.
|
||||
|
||||
// Step 1: Create two names for a single type: `Thing` and `AlsoThing`
|
||||
|
||||
struct Thing;
|
||||
struct Dummy;
|
||||
pub trait DummyTrait {
|
||||
trait DummyTrait {
|
||||
type DummyType;
|
||||
}
|
||||
impl DummyTrait for Dummy {
|
||||
|
|
@ -13,7 +16,7 @@ type AlsoThing = <Dummy as DummyTrait>::DummyType;
|
|||
|
||||
// Step 2: Create names for a single trait object type: `TraitObject` and `AlsoTraitObject`
|
||||
|
||||
pub trait SomeTrait {
|
||||
trait SomeTrait {
|
||||
type Item;
|
||||
}
|
||||
type TraitObject = dyn SomeTrait<Item = AlsoThing>;
|
||||
|
|
@ -21,12 +24,12 @@ type AlsoTraitObject = dyn SomeTrait<Item = Thing>;
|
|||
|
||||
// Step 3: Force the compiler to check whether the two names are the same type
|
||||
|
||||
pub trait Supertrait {
|
||||
trait Supertrait {
|
||||
type Foo;
|
||||
}
|
||||
pub trait Subtrait: Supertrait<Foo = TraitObject> {}
|
||||
trait Subtrait: Supertrait<Foo = TraitObject> {}
|
||||
|
||||
pub trait HasOutput<A: ?Sized> {
|
||||
trait HasOutput<A: ?Sized> {
|
||||
type Output;
|
||||
}
|
||||
|
||||
|
|
@ -36,3 +39,5 @@ where
|
|||
{
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
// Regression test for #133361.
|
||||
|
||||
trait Sup<T> {
|
||||
type Assoc;
|
||||
}
|
||||
|
||||
impl<T> Sup<T> for () {
|
||||
type Assoc = T;
|
||||
}
|
||||
impl<T, U> Dyn<T, U> for () {}
|
||||
|
||||
trait Dyn<A, B>: Sup<A, Assoc = A> + Sup<B, Assoc = B> {}
|
||||
|
||||
trait Trait {
|
||||
type Assoc;
|
||||
}
|
||||
impl Trait for dyn Dyn<(), ()> {
|
||||
type Assoc = &'static str;
|
||||
}
|
||||
impl<A, B> Trait for dyn Dyn<A, B> {
|
||||
//~^ ERROR conflicting implementations of trait `Trait` for type `(dyn Dyn<(), ()> + 'static)`
|
||||
type Assoc = usize;
|
||||
}
|
||||
|
||||
fn call<A, B>(x: usize) -> <dyn Dyn<A, B> as Trait>::Assoc {
|
||||
x
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x: &'static str = call::<(), ()>(0xDEADBEEF);
|
||||
println!("{x}");
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
error[E0119]: conflicting implementations of trait `Trait` for type `(dyn Dyn<(), ()> + 'static)`
|
||||
--> $DIR/incomplete-multiple-super-projection.rs:20:1
|
||||
|
|
||||
LL | impl Trait for dyn Dyn<(), ()> {
|
||||
| ------------------------------ first implementation here
|
||||
...
|
||||
LL | impl<A, B> Trait for dyn Dyn<A, B> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn Dyn<(), ()> + 'static)`
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0119`.
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
//@ known-bug: #79590
|
||||
//@ check-pass
|
||||
|
||||
trait Database: Restriction<Inner = u32> {}
|
||||
|
||||
24
tests/ui/traits/object/outlives-super-proj.rs
Normal file
24
tests/ui/traits/object/outlives-super-proj.rs
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
//@ check-pass
|
||||
|
||||
// Make sure that we still deduce outlives bounds from supertrait projections
|
||||
// and require them for well-formedness.
|
||||
|
||||
trait Trait {
|
||||
type Assoc;
|
||||
}
|
||||
|
||||
trait Bar {
|
||||
type Assoc;
|
||||
}
|
||||
|
||||
trait Foo<'a, T: 'a>: Bar<Assoc = &'a T> {
|
||||
|
||||
}
|
||||
|
||||
fn outlives<'a, T: 'a>() {}
|
||||
|
||||
fn implied_outlives<'a, T: Trait>(x: &dyn Foo<'a, T::Assoc>) {
|
||||
outlives::<'a, T::Assoc>();
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -154,12 +154,12 @@ error[E0308]: mismatched types
|
|||
--> $DIR/pretty.rs:41:56
|
||||
|
|
||||
LL | fn dyn_has_gat(x: &dyn HasGat<u8, Assoc<bool> = ()>) { x }
|
||||
| - ^ expected `()`, found `&dyn HasGat<u8, Assoc<bool> = ()>`
|
||||
| - ^ expected `()`, found `&dyn HasGat<u8>`
|
||||
| |
|
||||
| help: try adding a return type: `-> &dyn HasGat<u8, Assoc<bool> = ()>`
|
||||
| help: try adding a return type: `-> &dyn HasGat<u8>`
|
||||
|
|
||||
= note: expected unit type `()`
|
||||
found reference `&dyn HasGat<u8, Assoc<bool> = ()>`
|
||||
found reference `&dyn HasGat<u8>`
|
||||
|
||||
error: aborting due to 14 previous errors; 1 warning emitted
|
||||
|
||||
|
|
|
|||
12
tests/ui/traits/object/redundant.rs
Normal file
12
tests/ui/traits/object/redundant.rs
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
//@ check-pass
|
||||
|
||||
trait Foo: Bar<Out = ()> {}
|
||||
trait Bar {
|
||||
type Out;
|
||||
}
|
||||
|
||||
fn w(x: &dyn Foo<Out = ()>) {
|
||||
let x: &dyn Foo = x;
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -20,9 +20,6 @@ LL | fn option_to_result() -> Result<u64, String> {
|
|||
| -------------------------------------------- this function returns a `Result`
|
||||
LL | Some(3)?;
|
||||
| ^ use `.ok_or(...)?` to provide an error compatible with `Result<u64, String>`
|
||||
|
|
||||
= help: the trait `FromResidual<Option<Infallible>>` is not implemented for `Result<u64, String>`
|
||||
= help: the trait `FromResidual<Result<Infallible, E>>` is implemented for `Result<T, F>`
|
||||
|
||||
error[E0277]: the `?` operator can only be used on `Result`s in a function that returns `Result`
|
||||
--> $DIR/bad-interconversion.rs:15:31
|
||||
|
|
@ -31,9 +28,6 @@ LL | fn control_flow_to_result() -> Result<u64, String> {
|
|||
| -------------------------------------------------- this function returns a `Result`
|
||||
LL | Ok(ControlFlow::Break(123)?)
|
||||
| ^ this `?` produces `ControlFlow<{integer}, Infallible>`, which is incompatible with `Result<u64, String>`
|
||||
|
|
||||
= help: the trait `FromResidual<ControlFlow<{integer}, Infallible>>` is not implemented for `Result<u64, String>`
|
||||
= help: the trait `FromResidual<Result<Infallible, E>>` is implemented for `Result<T, F>`
|
||||
|
||||
error[E0277]: the `?` operator can only be used on `Option`s, not `Result`s, in a function that returns `Option`
|
||||
--> $DIR/bad-interconversion.rs:20:22
|
||||
|
|
@ -42,9 +36,6 @@ LL | fn result_to_option() -> Option<u16> {
|
|||
| ------------------------------------ this function returns an `Option`
|
||||
LL | Some(Err("hello")?)
|
||||
| ^ use `.ok()?` if you want to discard the `Result<Infallible, &str>` error information
|
||||
|
|
||||
= help: the trait `FromResidual<Result<Infallible, &str>>` is not implemented for `Option<u16>`
|
||||
= help: the trait `FromResidual<Option<Infallible>>` is implemented for `Option<T>`
|
||||
|
||||
error[E0277]: the `?` operator can only be used on `Option`s in a function that returns `Option`
|
||||
--> $DIR/bad-interconversion.rs:25:33
|
||||
|
|
@ -53,9 +44,6 @@ LL | fn control_flow_to_option() -> Option<u64> {
|
|||
| ------------------------------------------ this function returns an `Option`
|
||||
LL | Some(ControlFlow::Break(123)?)
|
||||
| ^ this `?` produces `ControlFlow<{integer}, Infallible>`, which is incompatible with `Option<u64>`
|
||||
|
|
||||
= help: the trait `FromResidual<ControlFlow<{integer}, Infallible>>` is not implemented for `Option<u64>`
|
||||
= help: the trait `FromResidual<Option<Infallible>>` is implemented for `Option<T>`
|
||||
|
||||
error[E0277]: the `?` operator can only be used on `ControlFlow`s in a function that returns `ControlFlow`
|
||||
--> $DIR/bad-interconversion.rs:30:39
|
||||
|
|
|
|||
29
tests/ui/try-trait/bad-question-mark-on-trait-object.rs
Normal file
29
tests/ui/try-trait/bad-question-mark-on-trait-object.rs
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
struct E;
|
||||
//~^ NOTE `E` needs to implement `std::error::Error`
|
||||
//~| NOTE alternatively, `E` needs to implement `Into<X>`
|
||||
struct X; //~ NOTE `X` needs to implement `From<E>`
|
||||
|
||||
fn foo() -> Result<(), Box<dyn std::error::Error>> { //~ NOTE required `E: std::error::Error` because of this
|
||||
Ok(bar()?)
|
||||
//~^ ERROR `?` couldn't convert the error: `E: std::error::Error` is not satisfied
|
||||
//~| NOTE the trait `std::error::Error` is not implemented for `E`
|
||||
//~| NOTE the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
|
||||
//~| NOTE required for `Box<dyn std::error::Error>` to implement `From<E>`
|
||||
//~| NOTE this has type `Result<_, E>`
|
||||
//~| NOTE in this expansion
|
||||
//~| NOTE in this expansion
|
||||
//~| NOTE in this expansion
|
||||
}
|
||||
fn bat() -> Result<(), X> { //~ NOTE expected `X` because of this
|
||||
Ok(bar()?)
|
||||
//~^ ERROR `?` couldn't convert the error to `X`
|
||||
//~| NOTE the trait `From<E>` is not implemented for `X`
|
||||
//~| NOTE this can't be annotated with `?` because it has type `Result<_, E>`
|
||||
//~| NOTE the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
|
||||
//~| NOTE in this expansion
|
||||
//~| NOTE in this expansion
|
||||
}
|
||||
fn bar() -> Result<(), E> {
|
||||
Err(E)
|
||||
}
|
||||
fn main() {}
|
||||
43
tests/ui/try-trait/bad-question-mark-on-trait-object.stderr
Normal file
43
tests/ui/try-trait/bad-question-mark-on-trait-object.stderr
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
error[E0277]: `?` couldn't convert the error: `E: std::error::Error` is not satisfied
|
||||
--> $DIR/bad-question-mark-on-trait-object.rs:7:13
|
||||
|
|
||||
LL | fn foo() -> Result<(), Box<dyn std::error::Error>> {
|
||||
| -------------------------------------- required `E: std::error::Error` because of this
|
||||
LL | Ok(bar()?)
|
||||
| -----^ the trait `std::error::Error` is not implemented for `E`
|
||||
| |
|
||||
| this has type `Result<_, E>`
|
||||
|
|
||||
note: `E` needs to implement `std::error::Error`
|
||||
--> $DIR/bad-question-mark-on-trait-object.rs:1:1
|
||||
|
|
||||
LL | struct E;
|
||||
| ^^^^^^^^
|
||||
= note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
|
||||
= note: required for `Box<dyn std::error::Error>` to implement `From<E>`
|
||||
|
||||
error[E0277]: `?` couldn't convert the error to `X`
|
||||
--> $DIR/bad-question-mark-on-trait-object.rs:18:13
|
||||
|
|
||||
LL | fn bat() -> Result<(), X> {
|
||||
| ------------- expected `X` because of this
|
||||
LL | Ok(bar()?)
|
||||
| -----^ the trait `From<E>` is not implemented for `X`
|
||||
| |
|
||||
| this can't be annotated with `?` because it has type `Result<_, E>`
|
||||
|
|
||||
note: `X` needs to implement `From<E>`
|
||||
--> $DIR/bad-question-mark-on-trait-object.rs:4:1
|
||||
|
|
||||
LL | struct X;
|
||||
| ^^^^^^^^
|
||||
note: alternatively, `E` needs to implement `Into<X>`
|
||||
--> $DIR/bad-question-mark-on-trait-object.rs:1:1
|
||||
|
|
||||
LL | struct E;
|
||||
| ^^^^^^^^
|
||||
= note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
||||
|
|
@ -6,9 +6,6 @@ LL | fn test_result() -> Result<(),()> {
|
|||
LL | let a:Option<()> = Some(());
|
||||
LL | a?;
|
||||
| ^ use `.ok_or(...)?` to provide an error compatible with `Result<(), ()>`
|
||||
|
|
||||
= help: the trait `FromResidual<Option<Infallible>>` is not implemented for `Result<(), ()>`
|
||||
= help: the trait `FromResidual<Result<Infallible, E>>` is implemented for `Result<T, F>`
|
||||
|
||||
error[E0277]: the `?` operator can only be used on `Option`s, not `Result`s, in a function that returns `Option`
|
||||
--> $DIR/option-to-result.rs:11:6
|
||||
|
|
@ -18,9 +15,6 @@ LL | fn test_option() -> Option<i32>{
|
|||
LL | let a:Result<i32, i32> = Ok(5);
|
||||
LL | a?;
|
||||
| ^ use `.ok()?` if you want to discard the `Result<Infallible, i32>` error information
|
||||
|
|
||||
= help: the trait `FromResidual<Result<Infallible, i32>>` is not implemented for `Option<i32>`
|
||||
= help: the trait `FromResidual<Option<Infallible>>` is implemented for `Option<T>`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
|
|
|||
|
|
@ -6,8 +6,6 @@ LL | fn a_function() -> u32 {
|
|||
LL | let x: Option<u32> = None;
|
||||
LL | x?;
|
||||
| ^ cannot use the `?` operator in a function that returns `u32`
|
||||
|
|
||||
= help: the trait `FromResidual<Option<Infallible>>` is not implemented for `u32`
|
||||
|
||||
error[E0277]: the `?` operator can only be used in a closure that returns `Result` or `Option` (or another type that implements `FromResidual`)
|
||||
--> $DIR/try-on-option-diagnostics.rs:14:10
|
||||
|
|
@ -17,8 +15,6 @@ LL | let a_closure = || {
|
|||
LL | let x: Option<u32> = None;
|
||||
LL | x?;
|
||||
| ^ cannot use the `?` operator in a closure that returns `{integer}`
|
||||
|
|
||||
= help: the trait `FromResidual<Option<Infallible>>` is not implemented for `{integer}`
|
||||
|
||||
error[E0277]: the `?` operator can only be used in a method that returns `Result` or `Option` (or another type that implements `FromResidual`)
|
||||
--> $DIR/try-on-option-diagnostics.rs:26:14
|
||||
|
|
@ -28,8 +24,6 @@ LL | fn a_method() {
|
|||
LL | let x: Option<u32> = None;
|
||||
LL | x?;
|
||||
| ^ cannot use the `?` operator in a method that returns `()`
|
||||
|
|
||||
= help: the trait `FromResidual<Option<Infallible>>` is not implemented for `()`
|
||||
|
||||
error[E0277]: the `?` operator can only be used in a trait method that returns `Result` or `Option` (or another type that implements `FromResidual`)
|
||||
--> $DIR/try-on-option-diagnostics.rs:39:14
|
||||
|
|
@ -39,8 +33,6 @@ LL | fn a_trait_method() {
|
|||
LL | let x: Option<u32> = None;
|
||||
LL | x?;
|
||||
| ^ cannot use the `?` operator in a trait method that returns `()`
|
||||
|
|
||||
= help: the trait `FromResidual<Option<Infallible>>` is not implemented for `()`
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
|
|
|
|||
|
|
@ -6,9 +6,6 @@ LL | fn foo() -> Result<u32, ()> {
|
|||
LL | let x: Option<u32> = None;
|
||||
LL | x?;
|
||||
| ^ use `.ok_or(...)?` to provide an error compatible with `Result<u32, ()>`
|
||||
|
|
||||
= help: the trait `FromResidual<Option<Infallible>>` is not implemented for `Result<u32, ()>`
|
||||
= help: the trait `FromResidual<Result<Infallible, E>>` is implemented for `Result<T, F>`
|
||||
|
||||
error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`)
|
||||
--> $DIR/try-on-option.rs:11:6
|
||||
|
|
@ -18,8 +15,6 @@ LL | fn bar() -> u32 {
|
|||
LL | let x: Option<u32> = None;
|
||||
LL | x?;
|
||||
| ^ cannot use the `?` operator in a function that returns `u32`
|
||||
|
|
||||
= help: the trait `FromResidual<Option<Infallible>>` is not implemented for `u32`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ LL | // error for a `Try` type on a non-`Try` fn
|
|||
LL | std::fs::File::open("foo")?;
|
||||
| ^ cannot use the `?` operator in a function that returns `()`
|
||||
|
|
||||
= help: the trait `FromResidual<Result<Infallible, std::io::Error>>` is not implemented for `()`
|
||||
help: consider adding return type
|
||||
|
|
||||
LL ~ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
|
|
@ -33,8 +32,6 @@ LL | fn main() {
|
|||
...
|
||||
LL | ()?;
|
||||
| ^ cannot use the `?` operator in a function that returns `()`
|
||||
|
|
||||
= help: the trait `FromResidual<_>` is not implemented for `()`
|
||||
|
||||
error[E0277]: the trait bound `(): Try` is not satisfied
|
||||
--> $DIR/try-operator-on-main.rs:14:25
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue