mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-02 18:12:51 +00:00
Auto merge of #128213 - matthiaskrgr:rollup-v40q1j3, r=matthiaskrgr
Rollup of 7 pull requests Successful merges: - #126090 (Fix supertrait associated type unsoundness) - #127220 (Graciously handle `Drop` impls introducing more generic parameters than the ADT) - #127950 (Use `#[rustfmt::skip]` on some `use` groups to prevent reordering.) - #128085 (Various notes on match lowering) - #128150 (Stop using `unsized_const_parameters` in core/std) - #128194 (LLVM: LLVM-20.0 removes MMX types) - #128211 (fix: compilation issue w/ refactored type) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
72d73cec61
@ -305,7 +305,6 @@ pub enum TypeKind {
|
||||
Pointer = 12,
|
||||
Vector = 13,
|
||||
Metadata = 14,
|
||||
X86_MMX = 15,
|
||||
Token = 16,
|
||||
ScalableVector = 17,
|
||||
BFloat = 18,
|
||||
@ -330,7 +329,6 @@ impl TypeKind {
|
||||
TypeKind::Pointer => rustc_codegen_ssa::common::TypeKind::Pointer,
|
||||
TypeKind::Vector => rustc_codegen_ssa::common::TypeKind::Vector,
|
||||
TypeKind::Metadata => rustc_codegen_ssa::common::TypeKind::Metadata,
|
||||
TypeKind::X86_MMX => rustc_codegen_ssa::common::TypeKind::X86_MMX,
|
||||
TypeKind::Token => rustc_codegen_ssa::common::TypeKind::Token,
|
||||
TypeKind::ScalableVector => rustc_codegen_ssa::common::TypeKind::ScalableVector,
|
||||
TypeKind::BFloat => rustc_codegen_ssa::common::TypeKind::BFloat,
|
||||
|
@ -91,7 +91,6 @@ pub enum TypeKind {
|
||||
Pointer,
|
||||
Vector,
|
||||
Metadata,
|
||||
X86_MMX,
|
||||
Token,
|
||||
ScalableVector,
|
||||
BFloat,
|
||||
|
@ -34,6 +34,8 @@ use super::{
|
||||
Pointer, Projectable, Scalar, ValueVisitor,
|
||||
};
|
||||
|
||||
// for the validation errors
|
||||
#[rustfmt::skip]
|
||||
use super::InterpError::UndefinedBehavior as Ub;
|
||||
use super::InterpError::Unsupported as Unsup;
|
||||
use super::UndefinedBehaviorInfo::*;
|
||||
|
@ -6,10 +6,10 @@ use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_errors::{codes::*, struct_span_code_err, ErrorGuaranteed};
|
||||
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
|
||||
use rustc_infer::infer::{RegionResolutionError, TyCtxtInferExt};
|
||||
use rustc_infer::traits::ObligationCauseCode;
|
||||
use rustc_infer::traits::{ObligationCause, ObligationCauseCode};
|
||||
use rustc_middle::ty::util::CheckRegions;
|
||||
use rustc_middle::ty::GenericArgsRef;
|
||||
use rustc_middle::ty::{self, TyCtxt};
|
||||
use rustc_middle::ty::{GenericArgsRef, Ty};
|
||||
use rustc_trait_selection::regions::InferCtxtRegionExt;
|
||||
use rustc_trait_selection::traits::{self, ObligationCtxt};
|
||||
|
||||
@ -115,8 +115,9 @@ fn ensure_drop_params_and_item_params_correspond<'tcx>(
|
||||
Err(err.emit())
|
||||
}
|
||||
|
||||
/// Confirms that every predicate imposed by dtor_predicates is
|
||||
/// implied by assuming the predicates attached to self_type_did.
|
||||
/// Confirms that all predicates defined on the `Drop` impl (`drop_impl_def_id`) are able to be
|
||||
/// proven from within `adt_def_id`'s environment. I.e. all the predicates on the impl are
|
||||
/// implied by the ADT being well formed.
|
||||
fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
drop_impl_def_id: LocalDefId,
|
||||
@ -126,6 +127,8 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>(
|
||||
let infcx = tcx.infer_ctxt().build();
|
||||
let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
|
||||
|
||||
let impl_span = tcx.def_span(drop_impl_def_id.to_def_id());
|
||||
|
||||
// Take the param-env of the adt and instantiate the args that show up in
|
||||
// the implementation's self type. This gives us the assumptions that the
|
||||
// self ty of the implementation is allowed to know just from it being a
|
||||
@ -135,14 +138,27 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>(
|
||||
// We don't need to normalize this param-env or anything, since we're only
|
||||
// instantiating it with free params, so no additional param-env normalization
|
||||
// can occur on top of what has been done in the param_env query itself.
|
||||
let param_env =
|
||||
//
|
||||
// Note: Ideally instead of instantiating the `ParamEnv` with the arguments from the impl ty we
|
||||
// could instead use identity args for the adt. Unfortunately this would cause any errors to
|
||||
// reference the params from the ADT instead of from the impl which is bad UX. To resolve
|
||||
// this we "rename" the ADT's params to be the impl's params which should not affect behaviour.
|
||||
let impl_adt_ty = Ty::new_adt(tcx, tcx.adt_def(adt_def_id), adt_to_impl_args);
|
||||
let adt_env =
|
||||
ty::EarlyBinder::bind(tcx.param_env(adt_def_id)).instantiate(tcx, adt_to_impl_args);
|
||||
|
||||
for (pred, span) in tcx.predicates_of(drop_impl_def_id).instantiate_identity(tcx) {
|
||||
let fresh_impl_args = infcx.fresh_args_for_item(impl_span, drop_impl_def_id.to_def_id());
|
||||
let fresh_adt_ty =
|
||||
tcx.impl_trait_ref(drop_impl_def_id).unwrap().instantiate(tcx, fresh_impl_args).self_ty();
|
||||
|
||||
ocx.eq(&ObligationCause::dummy_with_span(impl_span), adt_env, fresh_adt_ty, impl_adt_ty)
|
||||
.unwrap();
|
||||
|
||||
for (clause, span) in tcx.predicates_of(drop_impl_def_id).instantiate(tcx, fresh_impl_args) {
|
||||
let normalize_cause = traits::ObligationCause::misc(span, adt_def_id);
|
||||
let pred = ocx.normalize(&normalize_cause, param_env, pred);
|
||||
let pred = ocx.normalize(&normalize_cause, adt_env, clause);
|
||||
let cause = traits::ObligationCause::new(span, adt_def_id, ObligationCauseCode::DropImpl);
|
||||
ocx.register_obligation(traits::Obligation::new(tcx, cause, param_env, pred));
|
||||
ocx.register_obligation(traits::Obligation::new(tcx, cause, adt_env, pred));
|
||||
}
|
||||
|
||||
// All of the custom error reporting logic is to preserve parity with the old
|
||||
@ -176,7 +192,7 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>(
|
||||
return Err(guar.unwrap());
|
||||
}
|
||||
|
||||
let errors = ocx.infcx.resolve_regions(&OutlivesEnvironment::new(param_env));
|
||||
let errors = ocx.infcx.resolve_regions(&OutlivesEnvironment::new(adt_env));
|
||||
if !errors.is_empty() {
|
||||
let mut guar = None;
|
||||
for error in errors {
|
||||
|
@ -122,6 +122,7 @@ use types::*;
|
||||
use unit_bindings::*;
|
||||
use unused::*;
|
||||
|
||||
#[rustfmt::skip]
|
||||
pub use builtin::{MissingDoc, SoftLints};
|
||||
pub use context::{CheckLintNameResult, FindLintError, LintStore};
|
||||
pub use context::{EarlyContext, LateContext, LintContext};
|
||||
|
@ -1419,8 +1419,6 @@ extern "C" LLVMTypeKind LLVMRustGetTypeKind(LLVMTypeRef Ty) {
|
||||
return LLVMPointerTypeKind;
|
||||
case Type::FixedVectorTyID:
|
||||
return LLVMVectorTypeKind;
|
||||
case Type::X86_MMXTyID:
|
||||
return LLVMX86_MMXTypeKind;
|
||||
case Type::TokenTyID:
|
||||
return LLVMTokenTypeKind;
|
||||
case Type::ScalableVectorTyID:
|
||||
|
@ -528,12 +528,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
end_block.unit()
|
||||
}
|
||||
|
||||
/// Binds the variables and ascribes types for a given `match` arm or
|
||||
/// `let` binding.
|
||||
/// For a top-level `match` arm or a `let` binding, binds the variables and
|
||||
/// ascribes types, and also checks the match arm guard (if present).
|
||||
///
|
||||
/// Also check if the guard matches, if it's provided.
|
||||
/// `arm_scope` should be `Some` if and only if this is called for a
|
||||
/// `match` arm.
|
||||
///
|
||||
/// In the presence of or-patterns, a match arm might have multiple
|
||||
/// sub-branches representing different ways to match, with each sub-branch
|
||||
/// requiring its own bindings and its own copy of the guard. This method
|
||||
/// handles those sub-branches individually, and then has them jump together
|
||||
/// to a common block.
|
||||
///
|
||||
/// Returns a single block that the match arm can be lowered into.
|
||||
/// (For `let` bindings, this is the code that can use the bindings.)
|
||||
fn bind_pattern(
|
||||
&mut self,
|
||||
outer_source_info: SourceInfo,
|
||||
@ -638,12 +646,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
|
||||
// Optimize the case of `let x: T = ...` to write directly
|
||||
// into `x` and then require that `T == typeof(x)`.
|
||||
//
|
||||
// Weirdly, this is needed to prevent the
|
||||
// `intrinsic-move-val.rs` test case from crashing. That
|
||||
// test works with uninitialized values in a rather
|
||||
// dubious way, so it may be that the test is kind of
|
||||
// broken.
|
||||
PatKind::AscribeUserType {
|
||||
subpattern:
|
||||
box Pat {
|
||||
@ -1022,7 +1024,8 @@ impl<'tcx> PatternExtraData<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
/// A pattern in a form suitable for generating code.
|
||||
/// A pattern in a form suitable for lowering the match tree, with all irrefutable
|
||||
/// patterns simplified away, and or-patterns sorted to the end.
|
||||
///
|
||||
/// Here, "flat" indicates that the pattern's match pairs have been recursively
|
||||
/// simplified by [`Builder::simplify_match_pairs`]. They are not necessarily
|
||||
@ -1055,36 +1058,89 @@ impl<'tcx, 'pat> FlatPat<'pat, 'tcx> {
|
||||
ascriptions: Vec::new(),
|
||||
is_never: pattern.is_never_pattern(),
|
||||
};
|
||||
// Partly-flatten and sort the match pairs, while recording extra data.
|
||||
// Recursively remove irrefutable match pairs, while recording their
|
||||
// bindings/ascriptions, and sort or-patterns after other match pairs.
|
||||
cx.simplify_match_pairs(&mut match_pairs, &mut extra_data);
|
||||
|
||||
Self { match_pairs, extra_data }
|
||||
}
|
||||
}
|
||||
|
||||
/// Candidates are a generalization of (a) top-level match arms, and
|
||||
/// (b) sub-branches of or-patterns, allowing the match-lowering process to handle
|
||||
/// them both in a mostly-uniform way. For example, the list of candidates passed
|
||||
/// to [`Builder::match_candidates`] will often contain a mixture of top-level
|
||||
/// candidates and or-pattern subcandidates.
|
||||
///
|
||||
/// At the start of match lowering, there is one candidate for each match arm.
|
||||
/// During match lowering, arms with or-patterns will be expanded into a tree
|
||||
/// of candidates, where each "leaf" candidate represents one of the ways for
|
||||
/// the arm pattern to successfully match.
|
||||
#[derive(Debug)]
|
||||
struct Candidate<'pat, 'tcx> {
|
||||
/// For the candidate to match, all of these must be satisfied...
|
||||
// Invariant: all the match pairs are recursively simplified.
|
||||
// Invariant: or-patterns must be sorted at the end.
|
||||
///
|
||||
/// ---
|
||||
/// Initially contains a list of match pairs created by [`FlatPat`], but is
|
||||
/// subsequently mutated (in a queue-like way) while lowering the match tree.
|
||||
/// When this list becomes empty, the candidate is fully matched and becomes
|
||||
/// a leaf (see [`Builder::select_matched_candidate`]).
|
||||
///
|
||||
/// Key mutations include:
|
||||
///
|
||||
/// - When a match pair is fully satisfied by a test, it is removed from the
|
||||
/// list, and its subpairs are added instead (see [`Builder::sort_candidate`]).
|
||||
/// - During or-pattern expansion, any leading or-pattern is removed, and is
|
||||
/// converted into subcandidates (see [`Builder::expand_and_match_or_candidates`]).
|
||||
/// - After a candidate's subcandidates have been lowered, a copy of any remaining
|
||||
/// or-patterns is added to each leaf subcandidate
|
||||
/// (see [`Builder::test_remaining_match_pairs_after_or`]).
|
||||
///
|
||||
/// Invariants:
|
||||
/// - All [`TestCase::Irrefutable`] patterns have been removed by simplification.
|
||||
/// - All or-patterns ([`TestCase::Or`]) have been sorted to the end.
|
||||
match_pairs: Vec<MatchPairTree<'pat, 'tcx>>,
|
||||
|
||||
/// ...and if this is non-empty, one of these subcandidates also has to match...
|
||||
// Invariant: at the end of the algorithm, this must never contain a `is_never` candidate
|
||||
// because that would break binding consistency.
|
||||
///
|
||||
/// ---
|
||||
/// Initially a candidate has no subcandidates; they are added (and then immediately
|
||||
/// lowered) during or-pattern expansion. Their main function is to serve as _output_
|
||||
/// of match tree lowering, allowing later steps to see the leaf candidates that
|
||||
/// represent a match of the entire match arm.
|
||||
///
|
||||
/// A candidate no subcandidates is either incomplete (if it has match pairs left),
|
||||
/// or is a leaf in the match tree. A candidate with one or more subcandidates is
|
||||
/// an internal node in the match tree.
|
||||
///
|
||||
/// Invariant: at the end of match tree lowering, this must not contain an
|
||||
/// `is_never` candidate, because that would break binding consistency.
|
||||
/// - See [`Builder::remove_never_subcandidates`].
|
||||
subcandidates: Vec<Candidate<'pat, 'tcx>>,
|
||||
|
||||
/// ...and if there is a guard it must be evaluated; if it's `false` then branch to `otherwise_block`.
|
||||
///
|
||||
/// ---
|
||||
/// For subcandidates, this is copied from the parent candidate, so it indicates
|
||||
/// whether the enclosing match arm has a guard.
|
||||
has_guard: bool,
|
||||
|
||||
/// If the candidate matches, bindings and ascriptions must be established.
|
||||
/// Holds extra pattern data that was prepared by [`FlatPat`], including bindings and
|
||||
/// ascriptions that must be established if this candidate succeeds.
|
||||
extra_data: PatternExtraData<'tcx>,
|
||||
|
||||
/// If we filled `self.subcandidate`, we store here the span of the or-pattern they came from.
|
||||
// Invariant: it is `None` iff `subcandidates.is_empty()`.
|
||||
/// When setting `self.subcandidates`, we store here the span of the or-pattern they came from.
|
||||
///
|
||||
/// ---
|
||||
/// Invariant: it is `None` iff `subcandidates.is_empty()`.
|
||||
/// - FIXME: We sometimes don't unset this when clearing `subcandidates`.
|
||||
or_span: Option<Span>,
|
||||
|
||||
/// The block before the `bindings` have been established.
|
||||
///
|
||||
/// After the match tree has been lowered, [`Builder::lower_match_arms`]
|
||||
/// will use this as the start point for lowering bindings and guards, and
|
||||
/// then jump to a shared block containing the arm body.
|
||||
pre_binding_block: Option<BasicBlock>,
|
||||
|
||||
/// The block to branch to if the guard or a nested candidate fails to match.
|
||||
@ -1144,14 +1200,24 @@ impl<'tcx, 'pat> Candidate<'pat, 'tcx> {
|
||||
|
||||
/// A depth-first traversal of the `Candidate` and all of its recursive
|
||||
/// subcandidates.
|
||||
///
|
||||
/// This signature is very generic, to support traversing candidate trees by
|
||||
/// reference or by value, and to allow a mutable "context" to be shared by the
|
||||
/// traversal callbacks. Most traversals can use the simpler
|
||||
/// [`Candidate::visit_leaves`] wrapper instead.
|
||||
fn traverse_candidate<'pat, 'tcx: 'pat, C, T, I>(
|
||||
candidate: C,
|
||||
context: &mut T,
|
||||
// Called when visiting a "leaf" candidate (with no subcandidates).
|
||||
visit_leaf: &mut impl FnMut(C, &mut T),
|
||||
// Called when visiting a "node" candidate (with one or more subcandidates).
|
||||
// Returns an iterator over the candidate's children (by value or reference).
|
||||
// Can perform setup before visiting the node's children.
|
||||
get_children: impl Copy + Fn(C, &mut T) -> I,
|
||||
// Called after visiting a "node" candidate's children.
|
||||
complete_children: impl Copy + Fn(&mut T),
|
||||
) where
|
||||
C: Borrow<Candidate<'pat, 'tcx>>,
|
||||
C: Borrow<Candidate<'pat, 'tcx>>, // Typically `Candidate` or `&mut Candidate`
|
||||
I: Iterator<Item = C>,
|
||||
{
|
||||
if candidate.borrow().subcandidates.is_empty() {
|
||||
@ -1182,6 +1248,24 @@ struct Ascription<'tcx> {
|
||||
variance: ty::Variance,
|
||||
}
|
||||
|
||||
/// Partial summary of a [`thir::Pat`], indicating what sort of test should be
|
||||
/// performed to match/reject the pattern, and what the desired test outcome is.
|
||||
/// This avoids having to perform a full match on [`thir::PatKind`] in some places,
|
||||
/// and helps [`TestKind::Switch`] and [`TestKind::SwitchInt`] know what target
|
||||
/// values to use.
|
||||
///
|
||||
/// Created by [`MatchPairTree::for_pattern`], and then inspected primarily by:
|
||||
/// - [`Builder::pick_test_for_match_pair`] (to choose a test)
|
||||
/// - [`Builder::sort_candidate`] (to see how the test interacts with a match pair)
|
||||
///
|
||||
/// Two variants are unlike the others and deserve special mention:
|
||||
///
|
||||
/// - [`Self::Irrefutable`] is only used temporarily when building a [`MatchPairTree`].
|
||||
/// They are then flattened away by [`Builder::simplify_match_pairs`], with any
|
||||
/// bindings/ascriptions incorporated into the enclosing [`FlatPat`].
|
||||
/// - [`Self::Or`] are not tested directly like the other variants. Instead they
|
||||
/// participate in or-pattern expansion, where they are transformed into subcandidates.
|
||||
/// - See [`Builder::expand_and_match_or_candidates`].
|
||||
#[derive(Debug, Clone)]
|
||||
enum TestCase<'pat, 'tcx> {
|
||||
Irrefutable { binding: Option<Binding<'tcx>>, ascription: Option<Ascription<'tcx>> },
|
||||
@ -1224,6 +1308,12 @@ pub(crate) struct MatchPairTree<'pat, 'tcx> {
|
||||
test_case: TestCase<'pat, 'tcx>,
|
||||
|
||||
/// ... and these subpairs must match.
|
||||
///
|
||||
/// ---
|
||||
/// Subpairs typically represent tests that can only be performed after their
|
||||
/// parent has succeeded. For example, the pattern `Some(3)` might have an
|
||||
/// outer match pair that tests for the variant `Some`, and then a subpair
|
||||
/// that tests its field for the value `3`.
|
||||
subpairs: Vec<Self>,
|
||||
|
||||
/// The pattern this was created from.
|
||||
@ -1234,15 +1324,22 @@ pub(crate) struct MatchPairTree<'pat, 'tcx> {
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
enum TestKind<'tcx> {
|
||||
/// Test what enum variant a value is.
|
||||
///
|
||||
/// The subset of expected variants is not stored here; instead they are
|
||||
/// extracted from the [`TestCase`]s of the candidates participating in the
|
||||
/// test.
|
||||
Switch {
|
||||
/// The enum type being tested.
|
||||
adt_def: ty::AdtDef<'tcx>,
|
||||
},
|
||||
|
||||
/// Test what value an integer or `char` has.
|
||||
///
|
||||
/// The test's target values are not stored here; instead they are extracted
|
||||
/// from the [`TestCase`]s of the candidates participating in the test.
|
||||
SwitchInt,
|
||||
|
||||
/// Test what value a `bool` has.
|
||||
/// Test whether a `bool` is `true` or `false`.
|
||||
If,
|
||||
|
||||
/// Test for equality with value, possibly after an unsizing coercion to
|
||||
@ -1258,7 +1355,7 @@ enum TestKind<'tcx> {
|
||||
/// Test whether the value falls within an inclusive or exclusive range.
|
||||
Range(Box<PatRange<'tcx>>),
|
||||
|
||||
/// Test that the length of the slice is equal to `len`.
|
||||
/// Test that the length of the slice is `== len` or `>= len`.
|
||||
Len { len: u64, op: BinOp },
|
||||
|
||||
/// Call `Deref::deref[_mut]` on the value.
|
||||
@ -1385,20 +1482,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
/// The main match algorithm. It begins with a set of candidates `candidates` and has the job of
|
||||
/// generating code that branches to an appropriate block if the scrutinee matches one of these
|
||||
/// candidates. The
|
||||
/// candidates are sorted such that the first item in the list
|
||||
/// candidates are ordered such that the first item in the list
|
||||
/// has the highest priority. When a candidate is found to match
|
||||
/// the value, we will set and generate a branch to the appropriate
|
||||
/// pre-binding block.
|
||||
///
|
||||
/// If none of the candidates apply, we continue to the returned `otherwise_block`.
|
||||
///
|
||||
/// It might be surprising that the input can be non-exhaustive.
|
||||
/// Indeed, for matches, initially, it is not, because all matches are
|
||||
/// exhaustive in Rust. But during processing we sometimes divide
|
||||
/// up the list of candidates and recurse with a non-exhaustive
|
||||
/// list. This is how our lowering approach (called "backtracking
|
||||
/// automaton" in the literature) works.
|
||||
/// See [`Builder::test_candidates`] for more details.
|
||||
/// Note that while `match` expressions in the Rust language are exhaustive,
|
||||
/// candidate lists passed to this method are often _non-exhaustive_.
|
||||
/// For example, the match lowering process will frequently divide up the
|
||||
/// list of candidates, and recursively call this method with a non-exhaustive
|
||||
/// subset of candidates.
|
||||
/// See [`Builder::test_candidates`] for more details on this
|
||||
/// "backtracking automata" approach.
|
||||
///
|
||||
/// For an example of how we use `otherwise_block`, consider:
|
||||
/// ```
|
||||
@ -1478,14 +1575,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
return start_block;
|
||||
}
|
||||
[first, remaining @ ..] if first.match_pairs.is_empty() => {
|
||||
// The first candidate has satisfied all its match pairs; we link it up and continue
|
||||
// with the remaining candidates.
|
||||
// The first candidate has satisfied all its match pairs.
|
||||
// We record the blocks that will be needed by match arm lowering,
|
||||
// and then continue with the remaining candidates.
|
||||
let remainder_start = self.select_matched_candidate(first, start_block);
|
||||
remainder_start.and(remaining)
|
||||
}
|
||||
candidates if candidates.iter().any(|candidate| candidate.starts_with_or_pattern()) => {
|
||||
// If any candidate starts with an or-pattern, we have to expand the or-pattern before we
|
||||
// can proceed further.
|
||||
// If any candidate starts with an or-pattern, we want to expand or-patterns
|
||||
// before we do any more tests.
|
||||
//
|
||||
// The only candidate we strictly _need_ to expand here is the first one.
|
||||
// But by expanding other candidates as early as possible, we unlock more
|
||||
// opportunities to include them in test outcomes, making the match tree
|
||||
// smaller and simpler.
|
||||
self.expand_and_match_or_candidates(span, scrutinee_span, start_block, candidates)
|
||||
}
|
||||
candidates => {
|
||||
@ -1588,6 +1691,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
let (candidates_to_expand, remaining_candidates) = candidates.split_at_mut(expand_until);
|
||||
|
||||
// Expand one level of or-patterns for each candidate in `candidates_to_expand`.
|
||||
// We take care to preserve the relative ordering of candidates, so that
|
||||
// or-patterns are expanded in their parent's relative position.
|
||||
let mut expanded_candidates = Vec::new();
|
||||
for candidate in candidates_to_expand.iter_mut() {
|
||||
if candidate.starts_with_or_pattern() {
|
||||
@ -1608,7 +1713,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
// Process the expanded candidates.
|
||||
// Recursively lower the part of the match tree represented by the
|
||||
// expanded candidates. This is where subcandidates actually get lowered!
|
||||
let remainder_start = self.match_candidates(
|
||||
span,
|
||||
scrutinee_span,
|
||||
@ -1628,6 +1734,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
self.remove_never_subcandidates(candidate);
|
||||
}
|
||||
}
|
||||
// It's important to perform the above simplifications _before_ dealing
|
||||
// with remaining match pairs, to avoid exponential blowup if possible
|
||||
// (for trivial or-patterns), and avoid useless work (for never patterns).
|
||||
if let Some(last_candidate) = candidates_to_expand.last_mut() {
|
||||
self.test_remaining_match_pairs_after_or(span, scrutinee_span, last_candidate);
|
||||
}
|
||||
@ -1808,6 +1917,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
.all(|match_pair| matches!(match_pair.test_case, TestCase::Or { .. }))
|
||||
);
|
||||
|
||||
// Visit each leaf candidate within this subtree, add a copy of the remaining
|
||||
// match pairs to it, and then recursively lower the rest of the match tree
|
||||
// from that point.
|
||||
candidate.visit_leaves(|leaf_candidate| {
|
||||
// At this point the leaf's own match pairs have all been lowered
|
||||
// and removed, so `extend` and assignment are equivalent,
|
||||
@ -1860,17 +1972,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
(match_place, test)
|
||||
}
|
||||
|
||||
/// Given a test, we sort the input candidates into several buckets. If a candidate only matches
|
||||
/// in one of the branches of `test`, we move it there. If it could match in more than one of
|
||||
/// the branches of `test`, we stop sorting candidates.
|
||||
/// Given a test, we partition the input candidates into several buckets.
|
||||
/// If a candidate matches in exactly one of the branches of `test`
|
||||
/// (and no other branches), we put it into the corresponding bucket.
|
||||
/// If it could match in more than one of the branches of `test`, the test
|
||||
/// doesn't usefully apply to it, and we stop partitioning candidates.
|
||||
///
|
||||
/// Importantly, we also **mutate** the branched candidates to remove match pairs
|
||||
/// that are entailed by the outcome of the test, and add any sub-pairs of the
|
||||
/// removed pairs.
|
||||
///
|
||||
/// This returns a pair of
|
||||
/// - the candidates that weren't sorted;
|
||||
/// - for each possible outcome of the test, the candidates that match in that outcome.
|
||||
///
|
||||
/// Moreover, we transform the branched candidates to reflect the fact that we know which
|
||||
/// outcome of `test` occurred.
|
||||
///
|
||||
/// For example:
|
||||
/// ```
|
||||
/// # let (x, y, z) = (true, true, true);
|
||||
@ -1883,14 +1998,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
/// # ;
|
||||
/// ```
|
||||
///
|
||||
/// Assume we are testing on `x`. There are 2 overlapping candidate sets:
|
||||
/// - If the outcome is that `x` is true, candidates 0, 2, and 3
|
||||
/// - If the outcome is that `x` is false, candidates 1 and 2
|
||||
/// Assume we are testing on `x`. Conceptually, there are 2 overlapping candidate sets:
|
||||
/// - If the outcome is that `x` is true, candidates {0, 2, 3} are possible
|
||||
/// - If the outcome is that `x` is false, candidates {1, 2} are possible
|
||||
///
|
||||
/// Following our algorithm, candidate 0 is sorted into outcome `x == true`, candidate 1 goes
|
||||
/// into outcome `x == false`, and candidate 2 and 3 remain unsorted.
|
||||
/// Following our algorithm:
|
||||
/// - Candidate 0 is sorted into outcome `x == true`
|
||||
/// - Candidate 1 is sorted into outcome `x == false`
|
||||
/// - Candidate 2 remains unsorted, because testing `x` has no effect on it
|
||||
/// - Candidate 3 remains unsorted, because a previous candidate (2) was unsorted
|
||||
/// - This helps preserve the illusion that candidates are tested "in order"
|
||||
///
|
||||
/// The sorted candidates are transformed:
|
||||
/// The sorted candidates are mutated to remove entailed match pairs:
|
||||
/// - candidate 0 becomes `[z @ true]` since we know that `x` was `true`;
|
||||
/// - candidate 1 becomes `[y @ false]` since we know that `x` was `false`.
|
||||
fn sort_candidates<'b, 'c, 'pat>(
|
||||
@ -1933,15 +2052,16 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
(candidates, target_candidates)
|
||||
}
|
||||
|
||||
/// This is the most subtle part of the match lowering algorithm. At this point, the input
|
||||
/// candidates have been fully simplified, so all remaining match-pairs require some sort of
|
||||
/// test.
|
||||
/// This is the most subtle part of the match lowering algorithm. At this point, there are
|
||||
/// no fully-satisfied candidates, and no or-patterns to expand, so we actually need to
|
||||
/// perform some sort of test to make progress.
|
||||
///
|
||||
/// Once we pick what sort of test we are going to perform, this test will help us winnow down
|
||||
/// our candidates. So we walk over the candidates (from high to low priority) and check. We
|
||||
/// compute, for each outcome of the test, a transformed list of candidates. If a candidate
|
||||
/// matches in a single branch of our test, we add it to the corresponding outcome. We also
|
||||
/// transform it to record the fact that we know which outcome occurred.
|
||||
/// compute, for each outcome of the test, a list of (modified) candidates. If a candidate
|
||||
/// matches in exactly one branch of our test, we add it to the corresponding outcome. We also
|
||||
/// **mutate its list of match pairs** if appropriate, to reflect the fact that we know which
|
||||
/// outcome occurred.
|
||||
///
|
||||
/// For example, if we are testing `x.0`'s variant, and we have a candidate `(x.0 @ Some(v), x.1
|
||||
/// @ 22)`, then we would have a resulting candidate of `((x.0 as Some).0 @ v, x.1 @ 22)` in the
|
||||
@ -2036,32 +2156,38 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
candidates: &'b mut [&'c mut Candidate<'pat, 'tcx>],
|
||||
start_block: BasicBlock,
|
||||
) -> BlockAnd<&'b mut [&'c mut Candidate<'pat, 'tcx>]> {
|
||||
// Extract the match-pair from the highest priority candidate and build a test from it.
|
||||
// Choose a match pair from the first candidate, and use it to determine a
|
||||
// test to perform that will confirm or refute that match pair.
|
||||
let (match_place, test) = self.pick_test(candidates);
|
||||
|
||||
// For each of the N possible test outcomes, build the vector of candidates that applies if
|
||||
// the test has that particular outcome.
|
||||
// the test has that particular outcome. This also mutates the candidates to remove match
|
||||
// pairs that are fully satisfied by the relevant outcome.
|
||||
let (remaining_candidates, target_candidates) =
|
||||
self.sort_candidates(match_place, &test, candidates);
|
||||
|
||||
// The block that we should branch to if none of the
|
||||
// `target_candidates` match.
|
||||
// The block that we should branch to if none of the `target_candidates` match.
|
||||
let remainder_start = self.cfg.start_new_block();
|
||||
|
||||
// For each outcome of test, process the candidates that still apply.
|
||||
// For each outcome of the test, recursively lower the rest of the match tree
|
||||
// from that point. (Note that we haven't lowered the actual test yet!)
|
||||
let target_blocks: FxIndexMap<_, _> = target_candidates
|
||||
.into_iter()
|
||||
.map(|(branch, mut candidates)| {
|
||||
let branch_start = self.cfg.start_new_block();
|
||||
// Recursively lower the rest of the match tree after the relevant outcome.
|
||||
let branch_otherwise =
|
||||
self.match_candidates(span, scrutinee_span, branch_start, &mut *candidates);
|
||||
|
||||
// Link up the `otherwise` block of the subtree to `remainder_start`.
|
||||
let source_info = self.source_info(span);
|
||||
self.cfg.goto(branch_otherwise, source_info, remainder_start);
|
||||
(branch, branch_start)
|
||||
})
|
||||
.collect();
|
||||
|
||||
// Perform the test, branching to one of N blocks.
|
||||
// Perform the chosen test, branching to one of the N subtrees prepared above
|
||||
// (or to `remainder_start` if no outcome was satisfied).
|
||||
self.perform_test(
|
||||
span,
|
||||
scrutinee_span,
|
||||
|
@ -51,6 +51,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
|
||||
TestCase::Never => TestKind::Never,
|
||||
|
||||
// Or-patterns are not tested directly; instead they are expanded into subcandidates,
|
||||
// which are then distinguished by testing whatever non-or patterns they contain.
|
||||
TestCase::Or { .. } => bug!("or-patterns should have already been handled"),
|
||||
|
||||
TestCase::Irrefutable { .. } => span_bug!(
|
||||
@ -544,6 +546,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
.enumerate()
|
||||
.find(|&(_, mp)| mp.place == Some(test_place))?;
|
||||
|
||||
// If true, the match pair is completely entailed by its corresponding test
|
||||
// branch, so it can be removed. If false, the match pair is _compatible_
|
||||
// with its test branch, but still needs a more specific test.
|
||||
let fully_matched;
|
||||
let ret = match (&test.kind, &match_pair.test_case) {
|
||||
// If we are performing a variant switch, then this
|
||||
@ -565,8 +570,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
(TestKind::SwitchInt, &TestCase::Constant { value })
|
||||
if is_switch_ty(match_pair.pattern.ty) =>
|
||||
{
|
||||
// Beware: there might be some ranges sorted into the failure case; we must not add
|
||||
// a success case that could be matched by one of these ranges.
|
||||
// An important invariant of candidate sorting is that a candidate
|
||||
// must not match in multiple branches. For `SwitchInt` tests, adding
|
||||
// a new value might invalidate that property for range patterns that
|
||||
// have already been sorted into the failure arm, so we must take care
|
||||
// not to add such values here.
|
||||
let is_covering_range = |test_case: &TestCase<'_, 'tcx>| {
|
||||
test_case.as_range().is_some_and(|range| {
|
||||
matches!(range.contains(value, self.tcx, self.param_env), None | Some(true))
|
||||
@ -591,6 +599,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
(TestKind::SwitchInt, TestCase::Range(range)) => {
|
||||
// When performing a `SwitchInt` test, a range pattern can be
|
||||
// sorted into the failure arm if it doesn't contain _any_ of
|
||||
// the values being tested. (This restricts what values can be
|
||||
// added to the test by subsequent candidates.)
|
||||
fully_matched = false;
|
||||
let not_contained =
|
||||
sorted_candidates.keys().filter_map(|br| br.as_constant()).copied().all(
|
||||
|
@ -12,17 +12,16 @@ use super::elaborate;
|
||||
|
||||
use crate::infer::TyCtxtInferExt;
|
||||
use crate::traits::query::evaluate_obligation::InferCtxtExt;
|
||||
use crate::traits::{self, Obligation, ObligationCause};
|
||||
use crate::traits::{util, Obligation, ObligationCause};
|
||||
use rustc_errors::FatalError;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_middle::query::Providers;
|
||||
use rustc_middle::ty::{
|
||||
self, EarlyBinder, ExistentialPredicateStableCmpExt as _, Ty, TyCtxt, TypeSuperVisitable,
|
||||
TypeVisitable, TypeVisitor,
|
||||
self, EarlyBinder, ExistentialPredicateStableCmpExt as _, GenericArgs, Ty, TyCtxt,
|
||||
TypeFoldable, TypeFolder, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable,
|
||||
TypeVisitableExt, TypeVisitor, Upcast,
|
||||
};
|
||||
use rustc_middle::ty::{GenericArg, GenericArgs};
|
||||
use rustc_middle::ty::{TypeVisitableExt, Upcast};
|
||||
use rustc_span::symbol::Symbol;
|
||||
use rustc_span::Span;
|
||||
use rustc_target::abi::Abi;
|
||||
@ -195,7 +194,13 @@ fn predicates_reference_self(
|
||||
.predicates
|
||||
.iter()
|
||||
.map(|&(predicate, sp)| (predicate.instantiate_supertrait(tcx, trait_ref), sp))
|
||||
.filter_map(|predicate| predicate_references_self(tcx, predicate))
|
||||
.filter_map(|(clause, sp)| {
|
||||
// Super predicates cannot allow self projections, since they're
|
||||
// impossible to make into existential bounds without eager resolution
|
||||
// or something.
|
||||
// e.g. `trait A: B<Item = Self::Assoc>`.
|
||||
predicate_references_self(tcx, trait_def_id, clause, sp, AllowSelfProjections::No)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
@ -204,20 +209,25 @@ fn bounds_reference_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SmallVec<[Span
|
||||
.in_definition_order()
|
||||
.filter(|item| item.kind == ty::AssocKind::Type)
|
||||
.flat_map(|item| tcx.explicit_item_bounds(item.def_id).iter_identity_copied())
|
||||
.filter_map(|c| predicate_references_self(tcx, c))
|
||||
.filter_map(|(clause, sp)| {
|
||||
// Item bounds *can* have self projections, since they never get
|
||||
// their self type erased.
|
||||
predicate_references_self(tcx, trait_def_id, clause, sp, AllowSelfProjections::Yes)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn predicate_references_self<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
(predicate, sp): (ty::Clause<'tcx>, Span),
|
||||
trait_def_id: DefId,
|
||||
predicate: ty::Clause<'tcx>,
|
||||
sp: Span,
|
||||
allow_self_projections: AllowSelfProjections,
|
||||
) -> Option<Span> {
|
||||
let self_ty = tcx.types.self_param;
|
||||
let has_self_ty = |arg: &GenericArg<'tcx>| arg.walk().any(|arg| arg == self_ty.into());
|
||||
match predicate.kind().skip_binder() {
|
||||
ty::ClauseKind::Trait(ref data) => {
|
||||
// In the case of a trait predicate, we can skip the "self" type.
|
||||
data.trait_ref.args[1..].iter().any(has_self_ty).then_some(sp)
|
||||
data.trait_ref.args[1..].iter().any(|&arg| contains_illegal_self_type_reference(tcx, trait_def_id, arg, allow_self_projections)).then_some(sp)
|
||||
}
|
||||
ty::ClauseKind::Projection(ref data) => {
|
||||
// And similarly for projections. This should be redundant with
|
||||
@ -235,9 +245,9 @@ fn predicate_references_self<'tcx>(
|
||||
//
|
||||
// This is ALT2 in issue #56288, see that for discussion of the
|
||||
// possible alternatives.
|
||||
data.projection_term.args[1..].iter().any(has_self_ty).then_some(sp)
|
||||
data.projection_term.args[1..].iter().any(|&arg| contains_illegal_self_type_reference(tcx, trait_def_id, arg, allow_self_projections)).then_some(sp)
|
||||
}
|
||||
ty::ClauseKind::ConstArgHasType(_ct, ty) => has_self_ty(&ty.into()).then_some(sp),
|
||||
ty::ClauseKind::ConstArgHasType(_ct, ty) => contains_illegal_self_type_reference(tcx, trait_def_id, ty, allow_self_projections).then_some(sp),
|
||||
|
||||
ty::ClauseKind::WellFormed(..)
|
||||
| ty::ClauseKind::TypeOutlives(..)
|
||||
@ -383,7 +393,12 @@ fn virtual_call_violations_for_method<'tcx>(
|
||||
let mut errors = Vec::new();
|
||||
|
||||
for (i, &input_ty) in sig.skip_binder().inputs().iter().enumerate().skip(1) {
|
||||
if contains_illegal_self_type_reference(tcx, trait_def_id, sig.rebind(input_ty)) {
|
||||
if contains_illegal_self_type_reference(
|
||||
tcx,
|
||||
trait_def_id,
|
||||
sig.rebind(input_ty),
|
||||
AllowSelfProjections::Yes,
|
||||
) {
|
||||
let span = if let Some(hir::Node::TraitItem(hir::TraitItem {
|
||||
kind: hir::TraitItemKind::Fn(sig, _),
|
||||
..
|
||||
@ -396,7 +411,12 @@ fn virtual_call_violations_for_method<'tcx>(
|
||||
errors.push(MethodViolationCode::ReferencesSelfInput(span));
|
||||
}
|
||||
}
|
||||
if contains_illegal_self_type_reference(tcx, trait_def_id, sig.output()) {
|
||||
if contains_illegal_self_type_reference(
|
||||
tcx,
|
||||
trait_def_id,
|
||||
sig.output(),
|
||||
AllowSelfProjections::Yes,
|
||||
) {
|
||||
errors.push(MethodViolationCode::ReferencesSelfOutput);
|
||||
}
|
||||
if let Some(code) = contains_illegal_impl_trait_in_trait(tcx, method.def_id, sig.output()) {
|
||||
@ -482,7 +502,7 @@ fn virtual_call_violations_for_method<'tcx>(
|
||||
return false;
|
||||
}
|
||||
|
||||
contains_illegal_self_type_reference(tcx, trait_def_id, pred)
|
||||
contains_illegal_self_type_reference(tcx, trait_def_id, pred, AllowSelfProjections::Yes)
|
||||
}) {
|
||||
errors.push(MethodViolationCode::WhereClauseReferencesSelf);
|
||||
}
|
||||
@ -711,121 +731,181 @@ fn receiver_is_dispatchable<'tcx>(
|
||||
infcx.predicate_must_hold_modulo_regions(&obligation)
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
enum AllowSelfProjections {
|
||||
Yes,
|
||||
No,
|
||||
}
|
||||
|
||||
/// This is somewhat subtle. In general, we want to forbid
|
||||
/// references to `Self` in the argument and return types,
|
||||
/// since the value of `Self` is erased. However, there is one
|
||||
/// exception: it is ok to reference `Self` in order to access
|
||||
/// an associated type of the current trait, since we retain
|
||||
/// the value of those associated types in the object type
|
||||
/// itself.
|
||||
///
|
||||
/// ```rust,ignore (example)
|
||||
/// trait SuperTrait {
|
||||
/// type X;
|
||||
/// }
|
||||
///
|
||||
/// trait Trait : SuperTrait {
|
||||
/// type Y;
|
||||
/// fn foo(&self, x: Self) // bad
|
||||
/// fn foo(&self) -> Self // bad
|
||||
/// fn foo(&self) -> Option<Self> // bad
|
||||
/// fn foo(&self) -> Self::Y // OK, desugars to next example
|
||||
/// fn foo(&self) -> <Self as Trait>::Y // OK
|
||||
/// fn foo(&self) -> Self::X // OK, desugars to next example
|
||||
/// fn foo(&self) -> <Self as SuperTrait>::X // OK
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// However, it is not as simple as allowing `Self` in a projected
|
||||
/// type, because there are illegal ways to use `Self` as well:
|
||||
///
|
||||
/// ```rust,ignore (example)
|
||||
/// trait Trait : SuperTrait {
|
||||
/// ...
|
||||
/// fn foo(&self) -> <Self as SomeOtherTrait>::X;
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Here we will not have the type of `X` recorded in the
|
||||
/// object type, and we cannot resolve `Self as SomeOtherTrait`
|
||||
/// without knowing what `Self` is.
|
||||
fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable<TyCtxt<'tcx>>>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
trait_def_id: DefId,
|
||||
value: T,
|
||||
allow_self_projections: AllowSelfProjections,
|
||||
) -> bool {
|
||||
// This is somewhat subtle. In general, we want to forbid
|
||||
// references to `Self` in the argument and return types,
|
||||
// since the value of `Self` is erased. However, there is one
|
||||
// exception: it is ok to reference `Self` in order to access
|
||||
// an associated type of the current trait, since we retain
|
||||
// the value of those associated types in the object type
|
||||
// itself.
|
||||
//
|
||||
// ```rust
|
||||
// trait SuperTrait {
|
||||
// type X;
|
||||
// }
|
||||
//
|
||||
// trait Trait : SuperTrait {
|
||||
// type Y;
|
||||
// fn foo(&self, x: Self) // bad
|
||||
// fn foo(&self) -> Self // bad
|
||||
// fn foo(&self) -> Option<Self> // bad
|
||||
// fn foo(&self) -> Self::Y // OK, desugars to next example
|
||||
// fn foo(&self) -> <Self as Trait>::Y // OK
|
||||
// fn foo(&self) -> Self::X // OK, desugars to next example
|
||||
// fn foo(&self) -> <Self as SuperTrait>::X // OK
|
||||
// }
|
||||
// ```
|
||||
//
|
||||
// However, it is not as simple as allowing `Self` in a projected
|
||||
// type, because there are illegal ways to use `Self` as well:
|
||||
//
|
||||
// ```rust
|
||||
// trait Trait : SuperTrait {
|
||||
// ...
|
||||
// fn foo(&self) -> <Self as SomeOtherTrait>::X;
|
||||
// }
|
||||
// ```
|
||||
//
|
||||
// Here we will not have the type of `X` recorded in the
|
||||
// object type, and we cannot resolve `Self as SomeOtherTrait`
|
||||
// without knowing what `Self` is.
|
||||
value
|
||||
.visit_with(&mut IllegalSelfTypeVisitor {
|
||||
tcx,
|
||||
trait_def_id,
|
||||
supertraits: None,
|
||||
allow_self_projections,
|
||||
})
|
||||
.is_break()
|
||||
}
|
||||
|
||||
struct IllegalSelfTypeVisitor<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
trait_def_id: DefId,
|
||||
supertraits: Option<Vec<DefId>>,
|
||||
}
|
||||
struct IllegalSelfTypeVisitor<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
trait_def_id: DefId,
|
||||
supertraits: Option<Vec<ty::TraitRef<'tcx>>>,
|
||||
allow_self_projections: AllowSelfProjections,
|
||||
}
|
||||
|
||||
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for IllegalSelfTypeVisitor<'tcx> {
|
||||
type Result = ControlFlow<()>;
|
||||
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for IllegalSelfTypeVisitor<'tcx> {
|
||||
type Result = ControlFlow<()>;
|
||||
|
||||
fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result {
|
||||
match t.kind() {
|
||||
ty::Param(_) => {
|
||||
if t == self.tcx.types.self_param {
|
||||
ControlFlow::Break(())
|
||||
} else {
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
ty::Alias(ty::Projection, ref data)
|
||||
if self.tcx.is_impl_trait_in_trait(data.def_id) =>
|
||||
{
|
||||
// We'll deny these later in their own pass
|
||||
fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result {
|
||||
match t.kind() {
|
||||
ty::Param(_) => {
|
||||
if t == self.tcx.types.self_param {
|
||||
ControlFlow::Break(())
|
||||
} else {
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
ty::Alias(ty::Projection, ref data) => {
|
||||
// This is a projected type `<Foo as SomeTrait>::X`.
|
||||
|
||||
// Compute supertraits of current trait lazily.
|
||||
if self.supertraits.is_none() {
|
||||
let trait_ref =
|
||||
ty::Binder::dummy(ty::TraitRef::identity(self.tcx, self.trait_def_id));
|
||||
self.supertraits = Some(
|
||||
traits::supertraits(self.tcx, trait_ref).map(|t| t.def_id()).collect(),
|
||||
);
|
||||
}
|
||||
|
||||
// Determine whether the trait reference `Foo as
|
||||
// SomeTrait` is in fact a supertrait of the
|
||||
// current trait. In that case, this type is
|
||||
// legal, because the type `X` will be specified
|
||||
// in the object type. Note that we can just use
|
||||
// direct equality here because all of these types
|
||||
// are part of the formal parameter listing, and
|
||||
// hence there should be no inference variables.
|
||||
let is_supertrait_of_current_trait = self
|
||||
.supertraits
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.contains(&data.trait_ref(self.tcx).def_id);
|
||||
|
||||
// only walk contained types if it's not a super trait
|
||||
if is_supertrait_of_current_trait {
|
||||
ControlFlow::Continue(())
|
||||
} else {
|
||||
t.super_visit_with(self) // POSSIBLY reporting an error
|
||||
}
|
||||
}
|
||||
_ => t.super_visit_with(self), // walk contained types, if any
|
||||
}
|
||||
}
|
||||
ty::Alias(ty::Projection, ref data) if self.tcx.is_impl_trait_in_trait(data.def_id) => {
|
||||
// We'll deny these later in their own pass
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
ty::Alias(ty::Projection, ref data) => {
|
||||
match self.allow_self_projections {
|
||||
AllowSelfProjections::Yes => {
|
||||
// This is a projected type `<Foo as SomeTrait>::X`.
|
||||
|
||||
fn visit_const(&mut self, ct: ty::Const<'tcx>) -> Self::Result {
|
||||
// Constants can only influence object safety if they are generic and reference `Self`.
|
||||
// This is only possible for unevaluated constants, so we walk these here.
|
||||
self.tcx.expand_abstract_consts(ct).super_visit_with(self)
|
||||
// Compute supertraits of current trait lazily.
|
||||
if self.supertraits.is_none() {
|
||||
self.supertraits = Some(
|
||||
util::supertraits(
|
||||
self.tcx,
|
||||
ty::Binder::dummy(ty::TraitRef::identity(
|
||||
self.tcx,
|
||||
self.trait_def_id,
|
||||
)),
|
||||
)
|
||||
.map(|trait_ref| {
|
||||
self.tcx.erase_regions(
|
||||
self.tcx.instantiate_bound_regions_with_erased(trait_ref),
|
||||
)
|
||||
})
|
||||
.collect(),
|
||||
);
|
||||
}
|
||||
|
||||
// Determine whether the trait reference `Foo as
|
||||
// SomeTrait` is in fact a supertrait of the
|
||||
// current trait. In that case, this type is
|
||||
// legal, because the type `X` will be specified
|
||||
// in the object type. Note that we can just use
|
||||
// direct equality here because all of these types
|
||||
// are part of the formal parameter listing, and
|
||||
// hence there should be no inference variables.
|
||||
let is_supertrait_of_current_trait =
|
||||
self.supertraits.as_ref().unwrap().contains(
|
||||
&data.trait_ref(self.tcx).fold_with(
|
||||
&mut EraseEscapingBoundRegions {
|
||||
tcx: self.tcx,
|
||||
binder: ty::INNERMOST,
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
// only walk contained types if it's not a super trait
|
||||
if is_supertrait_of_current_trait {
|
||||
ControlFlow::Continue(())
|
||||
} else {
|
||||
t.super_visit_with(self) // POSSIBLY reporting an error
|
||||
}
|
||||
}
|
||||
AllowSelfProjections::No => t.super_visit_with(self),
|
||||
}
|
||||
}
|
||||
_ => t.super_visit_with(self),
|
||||
}
|
||||
}
|
||||
|
||||
value
|
||||
.visit_with(&mut IllegalSelfTypeVisitor { tcx, trait_def_id, supertraits: None })
|
||||
.is_break()
|
||||
fn visit_const(&mut self, ct: ty::Const<'tcx>) -> Self::Result {
|
||||
// Constants can only influence object safety if they are generic and reference `Self`.
|
||||
// This is only possible for unevaluated constants, so we walk these here.
|
||||
self.tcx.expand_abstract_consts(ct).super_visit_with(self)
|
||||
}
|
||||
}
|
||||
|
||||
struct EraseEscapingBoundRegions<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
binder: ty::DebruijnIndex,
|
||||
}
|
||||
|
||||
impl<'tcx> TypeFolder<TyCtxt<'tcx>> for EraseEscapingBoundRegions<'tcx> {
|
||||
fn cx(&self) -> TyCtxt<'tcx> {
|
||||
self.tcx
|
||||
}
|
||||
|
||||
fn fold_binder<T>(&mut self, t: ty::Binder<'tcx, T>) -> ty::Binder<'tcx, T>
|
||||
where
|
||||
T: TypeFoldable<TyCtxt<'tcx>>,
|
||||
{
|
||||
self.binder.shift_in(1);
|
||||
let result = t.super_fold_with(self);
|
||||
self.binder.shift_out(1);
|
||||
result
|
||||
}
|
||||
|
||||
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
|
||||
if let ty::ReBound(debruijn, _) = *r
|
||||
&& debruijn < self.binder
|
||||
{
|
||||
r
|
||||
} else {
|
||||
self.tcx.lifetimes.re_erased
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn contains_illegal_impl_trait_in_trait<'tcx>(
|
||||
|
@ -24,6 +24,8 @@ mod convert;
|
||||
mod decode;
|
||||
mod methods;
|
||||
|
||||
// stable re-exports
|
||||
#[rustfmt::skip]
|
||||
#[stable(feature = "try_from", since = "1.34.0")]
|
||||
pub use self::convert::CharTryFromError;
|
||||
#[stable(feature = "char_from_str", since = "1.20.0")]
|
||||
@ -31,11 +33,14 @@ pub use self::convert::ParseCharError;
|
||||
#[stable(feature = "decode_utf16", since = "1.9.0")]
|
||||
pub use self::decode::{DecodeUtf16, DecodeUtf16Error};
|
||||
|
||||
// perma-unstable re-exports
|
||||
#[rustfmt::skip]
|
||||
#[unstable(feature = "char_internals", reason = "exposed only for libstd", issue = "none")]
|
||||
pub use self::methods::encode_utf16_raw; // perma-unstable
|
||||
#[unstable(feature = "char_internals", reason = "exposed only for libstd", issue = "none")]
|
||||
pub use self::methods::encode_utf8_raw; // perma-unstable
|
||||
|
||||
#[rustfmt::skip]
|
||||
use crate::ascii;
|
||||
use crate::error::Error;
|
||||
use crate::escape;
|
||||
|
@ -243,18 +243,6 @@ extern "rust-intrinsic" {
|
||||
#[rustc_nounwind]
|
||||
pub fn simd_shuffle<T, U, V>(x: T, y: T, idx: U) -> V;
|
||||
|
||||
/// Shuffle two vectors by const indices.
|
||||
///
|
||||
/// `T` must be a vector.
|
||||
///
|
||||
/// `U` must be a vector with the same element type as `T` and the same length as `IDX`.
|
||||
///
|
||||
/// Returns a new vector such that element `i` is selected from `xy[IDX[i]]`, where `xy`
|
||||
/// is the concatenation of `x` and `y`. It is a compile-time error if `IDX[i]` is out-of-bounds
|
||||
/// of `xy`.
|
||||
#[rustc_nounwind]
|
||||
pub fn simd_shuffle_generic<T, U, const IDX: &'static [u32]>(x: T, y: T) -> U;
|
||||
|
||||
/// Read a vector of pointers.
|
||||
///
|
||||
/// `T` must be a vector.
|
||||
|
@ -249,7 +249,6 @@
|
||||
#![feature(transparent_unions)]
|
||||
#![feature(try_blocks)]
|
||||
#![feature(unboxed_closures)]
|
||||
#![feature(unsized_const_params)]
|
||||
#![feature(unsized_fn_params)]
|
||||
#![feature(with_negative_coherence)]
|
||||
// tidy-alphabetical-end
|
||||
|
@ -42,6 +42,8 @@ use crate::hash::Hasher;
|
||||
/// }
|
||||
/// ```
|
||||
#[unstable(feature = "internal_impls_macro", issue = "none")]
|
||||
// Allow implementations of `UnsizedConstParamTy` even though std cannot use that feature.
|
||||
#[allow_internal_unstable(unsized_const_params)]
|
||||
macro marker_impls {
|
||||
( $(#[$($meta:tt)*])* $Trait:ident for $({$($bounds:tt)*})? $T:ty $(, $($rest:tt)*)? ) => {
|
||||
$(#[$($meta)*])* impl< $($($bounds)*)? > $Trait for $T {}
|
||||
|
@ -1,13 +1,15 @@
|
||||
#![unstable(feature = "unicode_internals", issue = "none")]
|
||||
#![allow(missing_docs)]
|
||||
|
||||
// The `pub use` ones are for use in alloc, and are not re-exported in std.
|
||||
|
||||
pub(crate) use unicode_data::alphabetic::lookup as Alphabetic;
|
||||
// for use in alloc, not re-exported in std.
|
||||
#[rustfmt::skip]
|
||||
pub use unicode_data::case_ignorable::lookup as Case_Ignorable;
|
||||
pub use unicode_data::cased::lookup as Cased;
|
||||
pub(crate) use unicode_data::cc::lookup as Cc;
|
||||
pub use unicode_data::conversions;
|
||||
|
||||
#[rustfmt::skip]
|
||||
pub(crate) use unicode_data::alphabetic::lookup as Alphabetic;
|
||||
pub(crate) use unicode_data::cc::lookup as Cc;
|
||||
pub(crate) use unicode_data::grapheme_extend::lookup as Grapheme_Extend;
|
||||
pub(crate) use unicode_data::lowercase::lookup as Lowercase;
|
||||
pub(crate) use unicode_data::n::lookup as N;
|
||||
|
@ -16,9 +16,11 @@
|
||||
#![deny(unsafe_op_in_unsafe_fn)]
|
||||
#![allow(unused_macros)]
|
||||
|
||||
#[rustfmt::skip]
|
||||
pub use crate::panicking::{begin_panic, panic_count};
|
||||
pub use core::panicking::{panic_display, panic_fmt};
|
||||
|
||||
#[rustfmt::skip]
|
||||
use crate::sync::Once;
|
||||
use crate::sys;
|
||||
use crate::thread::{self, Thread};
|
||||
|
@ -416,8 +416,8 @@ impl File {
|
||||
dwHighDateTime: (info.LastWriteTime >> 32) as u32,
|
||||
},
|
||||
change_time: Some(c::FILETIME {
|
||||
dhLowDateTime: info.ChangeTime as c::DWORD,
|
||||
dhHighDateTime: (info.ChangeTime >> 32) as c::DWORD,
|
||||
dwLowDateTime: info.ChangeTime as u32,
|
||||
dwHighDateTime: (info.ChangeTime >> 32) as u32,
|
||||
}),
|
||||
file_size: 0,
|
||||
reparse_tag: 0,
|
||||
|
@ -1,10 +1,23 @@
|
||||
//@compile-flags: -Zmiri-strict-provenance
|
||||
#![feature(portable_simd, adt_const_params, core_intrinsics, repr_simd)]
|
||||
#![feature(
|
||||
portable_simd,
|
||||
unsized_const_params,
|
||||
adt_const_params,
|
||||
rustc_attrs,
|
||||
intrinsics,
|
||||
core_intrinsics,
|
||||
repr_simd
|
||||
)]
|
||||
#![allow(incomplete_features, internal_features)]
|
||||
use std::intrinsics::simd as intrinsics;
|
||||
use std::ptr;
|
||||
use std::simd::{prelude::*, StdFloat};
|
||||
|
||||
extern "rust-intrinsic" {
|
||||
#[rustc_nounwind]
|
||||
pub fn simd_shuffle_generic<T, U, const IDX: &'static [u32]>(x: T, y: T) -> U;
|
||||
}
|
||||
|
||||
fn simd_ops_f32() {
|
||||
let a = f32x4::splat(10.0);
|
||||
let b = f32x4::from_array([1.0, 2.0, 3.0, -4.0]);
|
||||
|
11
tests/ui/dropck/const_drop_is_valid.rs
Normal file
11
tests/ui/dropck/const_drop_is_valid.rs
Normal file
@ -0,0 +1,11 @@
|
||||
#![feature(effects)]
|
||||
//~^ WARN: the feature `effects` is incomplete
|
||||
|
||||
struct A();
|
||||
|
||||
impl const Drop for A {}
|
||||
//~^ ERROR: const trait impls are experimental
|
||||
//~| const `impl` for trait `Drop` which is not marked with `#[const_trait]`
|
||||
//~| not all trait items implemented, missing: `drop`
|
||||
|
||||
fn main() {}
|
45
tests/ui/dropck/const_drop_is_valid.stderr
Normal file
45
tests/ui/dropck/const_drop_is_valid.stderr
Normal file
@ -0,0 +1,45 @@
|
||||
error[E0658]: const trait impls are experimental
|
||||
--> $DIR/const_drop_is_valid.rs:6:6
|
||||
|
|
||||
LL | impl const Drop for A {}
|
||||
| ^^^^^
|
||||
|
|
||||
= note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information
|
||||
= help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||
--> $DIR/const_drop_is_valid.rs:1:12
|
||||
|
|
||||
LL | #![feature(effects)]
|
||||
| ^^^^^^^
|
||||
|
|
||||
= note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
|
||||
= note: `#[warn(incomplete_features)]` on by default
|
||||
|
||||
error: using `#![feature(effects)]` without enabling next trait solver globally
|
||||
|
|
||||
= note: the next trait solver must be enabled globally for the effects feature to work correctly
|
||||
= help: use `-Znext-solver` to enable
|
||||
|
||||
error: const `impl` for trait `Drop` which is not marked with `#[const_trait]`
|
||||
--> $DIR/const_drop_is_valid.rs:6:12
|
||||
|
|
||||
LL | impl const Drop for A {}
|
||||
| ^^^^
|
||||
|
|
||||
= note: marking a trait with `#[const_trait]` ensures all default method bodies are `const`
|
||||
= note: adding a non-const method body in the future would be a breaking change
|
||||
|
||||
error[E0046]: not all trait items implemented, missing: `drop`
|
||||
--> $DIR/const_drop_is_valid.rs:6:1
|
||||
|
|
||||
LL | impl const Drop for A {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ missing `drop` in implementation
|
||||
|
|
||||
= help: implement the missing item: `fn drop(&mut self) { todo!() }`
|
||||
|
||||
error: aborting due to 4 previous errors; 1 warning emitted
|
||||
|
||||
Some errors have detailed explanations: E0046, E0658.
|
||||
For more information about an error, try `rustc --explain E0046`.
|
13
tests/ui/dropck/constrained_by_assoc_type_equality.rs
Normal file
13
tests/ui/dropck/constrained_by_assoc_type_equality.rs
Normal file
@ -0,0 +1,13 @@
|
||||
//@ check-pass
|
||||
|
||||
struct Foo<T: Trait>(T);
|
||||
|
||||
trait Trait {
|
||||
type Assoc;
|
||||
}
|
||||
|
||||
impl<T: Trait<Assoc = U>, U: ?Sized> Drop for Foo<T> {
|
||||
fn drop(&mut self) {}
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,12 @@
|
||||
trait Trait {
|
||||
type Assoc;
|
||||
}
|
||||
|
||||
struct Foo<T: Trait, U: ?Sized>(T, U);
|
||||
|
||||
impl<T: Trait<Assoc = U>, U: ?Sized> Drop for Foo<T, U> {
|
||||
//~^ ERROR: `Drop` impl requires `<T as Trait>::Assoc == U`
|
||||
fn drop(&mut self) {}
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,15 @@
|
||||
error[E0367]: `Drop` impl requires `<T as Trait>::Assoc == U` but the struct it is implemented for does not
|
||||
--> $DIR/constrained_by_assoc_type_equality_and_self_ty.rs:7:15
|
||||
|
|
||||
LL | impl<T: Trait<Assoc = U>, U: ?Sized> Drop for Foo<T, U> {
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
note: the implementor must specify the same requirement
|
||||
--> $DIR/constrained_by_assoc_type_equality_and_self_ty.rs:5:1
|
||||
|
|
||||
LL | struct Foo<T: Trait, U: ?Sized>(T, U);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0367`.
|
@ -1,75 +1,145 @@
|
||||
// Issue 8142: Test that Drop impls cannot be specialized beyond the
|
||||
// predicates attached to the type definition itself.
|
||||
trait Bound { fn foo(&self) { } }
|
||||
struct K<'l1,'l2> { x: &'l1 i8, y: &'l2 u8 }
|
||||
struct L<'l1,'l2> { x: &'l1 i8, y: &'l2 u8 }
|
||||
struct M<'m> { x: &'m i8 }
|
||||
struct N<'n> { x: &'n i8 }
|
||||
struct O<To> { x: *const To }
|
||||
struct P<Tp> { x: *const Tp }
|
||||
struct Q<Tq> { x: *const Tq }
|
||||
struct R<Tr> { x: *const Tr }
|
||||
struct S<Ts:Bound> { x: *const Ts }
|
||||
struct T<'t,Ts:'t> { x: &'t Ts }
|
||||
trait Bound {
|
||||
fn foo(&self) {}
|
||||
}
|
||||
struct K<'l1, 'l2> {
|
||||
x: &'l1 i8,
|
||||
y: &'l2 u8,
|
||||
}
|
||||
struct L<'l1, 'l2> {
|
||||
x: &'l1 i8,
|
||||
y: &'l2 u8,
|
||||
}
|
||||
struct M<'m> {
|
||||
x: &'m i8,
|
||||
}
|
||||
struct N<'n> {
|
||||
x: &'n i8,
|
||||
}
|
||||
struct O<To> {
|
||||
x: *const To,
|
||||
}
|
||||
struct P<Tp> {
|
||||
x: *const Tp,
|
||||
}
|
||||
struct Q<Tq> {
|
||||
x: *const Tq,
|
||||
}
|
||||
struct R<Tr> {
|
||||
x: *const Tr,
|
||||
}
|
||||
struct S<Ts: Bound> {
|
||||
x: *const Ts,
|
||||
}
|
||||
struct T<'t, Ts: 't> {
|
||||
x: &'t Ts,
|
||||
}
|
||||
struct U;
|
||||
struct V<Tva, Tvb> { x: *const Tva, y: *const Tvb }
|
||||
struct W<'l1, 'l2> { x: &'l1 i8, y: &'l2 u8 }
|
||||
struct V<Tva, Tvb> {
|
||||
x: *const Tva,
|
||||
y: *const Tvb,
|
||||
}
|
||||
struct W<'l1, 'l2> {
|
||||
x: &'l1 i8,
|
||||
y: &'l2 u8,
|
||||
}
|
||||
struct X<const Ca: usize>;
|
||||
struct Y<const Ca: usize, const Cb: usize>;
|
||||
|
||||
enum Enum<T> { Variant(T) }
|
||||
enum Enum<T> {
|
||||
Variant(T),
|
||||
}
|
||||
struct TupleStruct<T>(T);
|
||||
union Union<T: Copy> { f: T }
|
||||
union Union<T: Copy> {
|
||||
f: T,
|
||||
}
|
||||
|
||||
impl<'al,'adds_bnd:'al> Drop for K<'al,'adds_bnd> { // REJECT
|
||||
impl<'al, 'adds_bnd: 'al> Drop for K<'al, 'adds_bnd> {
|
||||
//~^ ERROR `Drop` impl requires `'adds_bnd: 'al`
|
||||
fn drop(&mut self) { } }
|
||||
fn drop(&mut self) {}
|
||||
}
|
||||
|
||||
impl<'al,'adds_bnd> Drop for L<'al,'adds_bnd> where 'adds_bnd:'al { // REJECT
|
||||
//~^ ERROR `Drop` impl requires `'adds_bnd: 'al`
|
||||
fn drop(&mut self) { } }
|
||||
impl<'al, 'adds_bnd> Drop for L<'al, 'adds_bnd>
|
||||
//~^ ERROR `Drop` impl requires `'adds_bnd: 'al`
|
||||
where
|
||||
'adds_bnd: 'al,
|
||||
{
|
||||
fn drop(&mut self) {}
|
||||
}
|
||||
|
||||
impl<'ml> Drop for M<'ml> { fn drop(&mut self) { } } // ACCEPT
|
||||
impl<'ml> Drop for M<'ml> {
|
||||
fn drop(&mut self) {}
|
||||
}
|
||||
|
||||
impl Drop for N<'static> { fn drop(&mut self) { } } // REJECT
|
||||
//~^ ERROR `Drop` impls cannot be specialized
|
||||
impl Drop for N<'static> {
|
||||
//~^ ERROR `Drop` impls cannot be specialized
|
||||
fn drop(&mut self) {}
|
||||
}
|
||||
|
||||
impl<COkNoBound> Drop for O<COkNoBound> { fn drop(&mut self) { } } // ACCEPT
|
||||
impl<COkNoBound> Drop for O<COkNoBound> {
|
||||
fn drop(&mut self) {}
|
||||
}
|
||||
|
||||
impl Drop for P<i8> { fn drop(&mut self) { } } // REJECT
|
||||
//~^ ERROR `Drop` impls cannot be specialized
|
||||
impl Drop for P<i8> {
|
||||
//~^ ERROR `Drop` impls cannot be specialized
|
||||
fn drop(&mut self) {}
|
||||
}
|
||||
|
||||
impl<AddsBnd:Bound> Drop for Q<AddsBnd> { fn drop(&mut self) { } } // REJECT
|
||||
//~^ ERROR `Drop` impl requires `AddsBnd: Bound`
|
||||
impl<AddsBnd: Bound> Drop for Q<AddsBnd> {
|
||||
//~^ ERROR `Drop` impl requires `AddsBnd: Bound`
|
||||
fn drop(&mut self) {}
|
||||
}
|
||||
|
||||
impl<'rbnd,AddsRBnd:'rbnd> Drop for R<AddsRBnd> { fn drop(&mut self) { } } // REJECT
|
||||
//~^ ERROR `Drop` impl requires `AddsRBnd: 'rbnd`
|
||||
impl<'rbnd, AddsRBnd: 'rbnd> Drop for R<AddsRBnd> {
|
||||
fn drop(&mut self) {}
|
||||
}
|
||||
|
||||
impl<Bs:Bound> Drop for S<Bs> { fn drop(&mut self) { } } // ACCEPT
|
||||
impl<Bs: Bound> Drop for S<Bs> {
|
||||
fn drop(&mut self) {}
|
||||
}
|
||||
|
||||
impl<'t,Bt:'t> Drop for T<'t,Bt> { fn drop(&mut self) { } } // ACCEPT
|
||||
impl<'t, Bt: 't> Drop for T<'t, Bt> {
|
||||
fn drop(&mut self) {}
|
||||
}
|
||||
|
||||
impl Drop for U { fn drop(&mut self) { } } // ACCEPT
|
||||
impl Drop for U {
|
||||
fn drop(&mut self) {}
|
||||
}
|
||||
|
||||
impl<One> Drop for V<One,One> { fn drop(&mut self) { } } // REJECT
|
||||
//~^ ERROR `Drop` impls cannot be specialized
|
||||
impl<One> Drop for V<One, One> {
|
||||
//~^ ERROR `Drop` impls cannot be specialized
|
||||
fn drop(&mut self) {}
|
||||
}
|
||||
|
||||
impl<'lw> Drop for W<'lw,'lw> { fn drop(&mut self) { } } // REJECT
|
||||
//~^ ERROR `Drop` impls cannot be specialized
|
||||
impl<'lw> Drop for W<'lw, 'lw> {
|
||||
//~^ ERROR `Drop` impls cannot be specialized
|
||||
fn drop(&mut self) {}
|
||||
}
|
||||
|
||||
impl Drop for X<3> { fn drop(&mut self) { } } // REJECT
|
||||
//~^ ERROR `Drop` impls cannot be specialized
|
||||
impl Drop for X<3> {
|
||||
//~^ ERROR `Drop` impls cannot be specialized
|
||||
fn drop(&mut self) {}
|
||||
}
|
||||
|
||||
impl<const Ca: usize> Drop for Y<Ca, Ca> { fn drop(&mut self) { } } // REJECT
|
||||
//~^ ERROR `Drop` impls cannot be specialized
|
||||
impl<const Ca: usize> Drop for Y<Ca, Ca> {
|
||||
//~^ ERROR `Drop` impls cannot be specialized
|
||||
fn drop(&mut self) {}
|
||||
}
|
||||
|
||||
impl<AddsBnd:Bound> Drop for Enum<AddsBnd> { fn drop(&mut self) { } } // REJECT
|
||||
//~^ ERROR `Drop` impl requires `AddsBnd: Bound`
|
||||
impl<AddsBnd: Bound> Drop for Enum<AddsBnd> {
|
||||
//~^ ERROR `Drop` impl requires `AddsBnd: Bound`
|
||||
fn drop(&mut self) {}
|
||||
}
|
||||
|
||||
impl<AddsBnd:Bound> Drop for TupleStruct<AddsBnd> { fn drop(&mut self) { } } // REJECT
|
||||
//~^ ERROR `Drop` impl requires `AddsBnd: Bound`
|
||||
impl<AddsBnd: Bound> Drop for TupleStruct<AddsBnd> {
|
||||
//~^ ERROR `Drop` impl requires `AddsBnd: Bound`
|
||||
fn drop(&mut self) {}
|
||||
}
|
||||
|
||||
impl<AddsBnd:Copy + Bound> Drop for Union<AddsBnd> { fn drop(&mut self) { } } // REJECT
|
||||
//~^ ERROR `Drop` impl requires `AddsBnd: Bound`
|
||||
impl<AddsBnd: Copy + Bound> Drop for Union<AddsBnd> {
|
||||
//~^ ERROR `Drop` impl requires `AddsBnd: Bound`
|
||||
fn drop(&mut self) {}
|
||||
}
|
||||
|
||||
pub fn main() { }
|
||||
pub fn main() {}
|
||||
|
@ -1,166 +1,157 @@
|
||||
error[E0367]: `Drop` impl requires `'adds_bnd: 'al` but the struct it is implemented for does not
|
||||
--> $DIR/reject-specialized-drops-8142.rs:24:20
|
||||
--> $DIR/reject-specialized-drops-8142.rs:58:1
|
||||
|
|
||||
LL | impl<'al,'adds_bnd:'al> Drop for K<'al,'adds_bnd> { // REJECT
|
||||
| ^^^
|
||||
LL | impl<'al, 'adds_bnd: 'al> Drop for K<'al, 'adds_bnd> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: the implementor must specify the same requirement
|
||||
--> $DIR/reject-specialized-drops-8142.rs:4:1
|
||||
--> $DIR/reject-specialized-drops-8142.rs:6:1
|
||||
|
|
||||
LL | struct K<'l1,'l2> { x: &'l1 i8, y: &'l2 u8 }
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
LL | struct K<'l1, 'l2> {
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0367]: `Drop` impl requires `'adds_bnd: 'al` but the struct it is implemented for does not
|
||||
--> $DIR/reject-specialized-drops-8142.rs:28:67
|
||||
--> $DIR/reject-specialized-drops-8142.rs:63:1
|
||||
|
|
||||
LL | impl<'al,'adds_bnd> Drop for L<'al,'adds_bnd> where 'adds_bnd:'al { // REJECT
|
||||
| ^^^
|
||||
|
|
||||
note: the implementor must specify the same requirement
|
||||
--> $DIR/reject-specialized-drops-8142.rs:5:1
|
||||
|
|
||||
LL | struct L<'l1,'l2> { x: &'l1 i8, y: &'l2 u8 }
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0366]: `Drop` impls cannot be specialized
|
||||
--> $DIR/reject-specialized-drops-8142.rs:34:1
|
||||
|
|
||||
LL | impl Drop for N<'static> { fn drop(&mut self) { } } // REJECT
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `'static` is not a generic parameter
|
||||
note: use the same sequence of generic lifetime, type and const parameters as the struct definition
|
||||
--> $DIR/reject-specialized-drops-8142.rs:7:1
|
||||
|
|
||||
LL | struct N<'n> { x: &'n i8 }
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
error[E0366]: `Drop` impls cannot be specialized
|
||||
--> $DIR/reject-specialized-drops-8142.rs:39:1
|
||||
|
|
||||
LL | impl Drop for P<i8> { fn drop(&mut self) { } } // REJECT
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `i8` is not a generic parameter
|
||||
note: use the same sequence of generic lifetime, type and const parameters as the struct definition
|
||||
--> $DIR/reject-specialized-drops-8142.rs:9:1
|
||||
|
|
||||
LL | struct P<Tp> { x: *const Tp }
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
error[E0367]: `Drop` impl requires `AddsBnd: Bound` but the struct it is implemented for does not
|
||||
--> $DIR/reject-specialized-drops-8142.rs:42:14
|
||||
|
|
||||
LL | impl<AddsBnd:Bound> Drop for Q<AddsBnd> { fn drop(&mut self) { } } // REJECT
|
||||
| ^^^^^
|
||||
LL | / impl<'al, 'adds_bnd> Drop for L<'al, 'adds_bnd>
|
||||
LL | |
|
||||
LL | | where
|
||||
LL | | 'adds_bnd: 'al,
|
||||
| |___________________^
|
||||
|
|
||||
note: the implementor must specify the same requirement
|
||||
--> $DIR/reject-specialized-drops-8142.rs:10:1
|
||||
|
|
||||
LL | struct Q<Tq> { x: *const Tq }
|
||||
| ^^^^^^^^^^^^
|
||||
LL | struct L<'l1, 'l2> {
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0367]: `Drop` impl requires `AddsRBnd: 'rbnd` but the struct it is implemented for does not
|
||||
--> $DIR/reject-specialized-drops-8142.rs:45:21
|
||||
error[E0366]: `Drop` impls cannot be specialized
|
||||
--> $DIR/reject-specialized-drops-8142.rs:75:1
|
||||
|
|
||||
LL | impl<'rbnd,AddsRBnd:'rbnd> Drop for R<AddsRBnd> { fn drop(&mut self) { } } // REJECT
|
||||
| ^^^^^
|
||||
LL | impl Drop for N<'static> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: the implementor must specify the same requirement
|
||||
--> $DIR/reject-specialized-drops-8142.rs:11:1
|
||||
= note: `'static` is not a generic parameter
|
||||
note: use the same sequence of generic lifetime, type and const parameters as the struct definition
|
||||
--> $DIR/reject-specialized-drops-8142.rs:17:1
|
||||
|
|
||||
LL | struct R<Tr> { x: *const Tr }
|
||||
LL | struct N<'n> {
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
error[E0366]: `Drop` impls cannot be specialized
|
||||
--> $DIR/reject-specialized-drops-8142.rs:54:1
|
||||
--> $DIR/reject-specialized-drops-8142.rs:84:1
|
||||
|
|
||||
LL | impl<One> Drop for V<One,One> { fn drop(&mut self) { } } // REJECT
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | impl Drop for P<i8> {
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `i8` is not a generic parameter
|
||||
note: use the same sequence of generic lifetime, type and const parameters as the struct definition
|
||||
--> $DIR/reject-specialized-drops-8142.rs:23:1
|
||||
|
|
||||
LL | struct P<Tp> {
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
error[E0367]: `Drop` impl requires `AddsBnd: Bound` but the struct it is implemented for does not
|
||||
--> $DIR/reject-specialized-drops-8142.rs:89:15
|
||||
|
|
||||
LL | impl<AddsBnd: Bound> Drop for Q<AddsBnd> {
|
||||
| ^^^^^
|
||||
|
|
||||
note: the implementor must specify the same requirement
|
||||
--> $DIR/reject-specialized-drops-8142.rs:26:1
|
||||
|
|
||||
LL | struct Q<Tq> {
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
error[E0366]: `Drop` impls cannot be specialized
|
||||
--> $DIR/reject-specialized-drops-8142.rs:110:1
|
||||
|
|
||||
LL | impl<One> Drop for V<One, One> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `One` is mentioned multiple times
|
||||
note: use the same sequence of generic lifetime, type and const parameters as the struct definition
|
||||
--> $DIR/reject-specialized-drops-8142.rs:15:1
|
||||
--> $DIR/reject-specialized-drops-8142.rs:39:1
|
||||
|
|
||||
LL | struct V<Tva, Tvb> { x: *const Tva, y: *const Tvb }
|
||||
LL | struct V<Tva, Tvb> {
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0366]: `Drop` impls cannot be specialized
|
||||
--> $DIR/reject-specialized-drops-8142.rs:57:1
|
||||
--> $DIR/reject-specialized-drops-8142.rs:115:1
|
||||
|
|
||||
LL | impl<'lw> Drop for W<'lw,'lw> { fn drop(&mut self) { } } // REJECT
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | impl<'lw> Drop for W<'lw, 'lw> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `'lw` is mentioned multiple times
|
||||
note: use the same sequence of generic lifetime, type and const parameters as the struct definition
|
||||
--> $DIR/reject-specialized-drops-8142.rs:16:1
|
||||
--> $DIR/reject-specialized-drops-8142.rs:43:1
|
||||
|
|
||||
LL | struct W<'l1, 'l2> { x: &'l1 i8, y: &'l2 u8 }
|
||||
LL | struct W<'l1, 'l2> {
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0366]: `Drop` impls cannot be specialized
|
||||
--> $DIR/reject-specialized-drops-8142.rs:60:1
|
||||
--> $DIR/reject-specialized-drops-8142.rs:120:1
|
||||
|
|
||||
LL | impl Drop for X<3> { fn drop(&mut self) { } } // REJECT
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | impl Drop for X<3> {
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `3` is not a generic parameter
|
||||
note: use the same sequence of generic lifetime, type and const parameters as the struct definition
|
||||
--> $DIR/reject-specialized-drops-8142.rs:17:1
|
||||
--> $DIR/reject-specialized-drops-8142.rs:47:1
|
||||
|
|
||||
LL | struct X<const Ca: usize>;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0366]: `Drop` impls cannot be specialized
|
||||
--> $DIR/reject-specialized-drops-8142.rs:63:1
|
||||
--> $DIR/reject-specialized-drops-8142.rs:125:1
|
||||
|
|
||||
LL | impl<const Ca: usize> Drop for Y<Ca, Ca> { fn drop(&mut self) { } } // REJECT
|
||||
LL | impl<const Ca: usize> Drop for Y<Ca, Ca> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `Ca` is mentioned multiple times
|
||||
note: use the same sequence of generic lifetime, type and const parameters as the struct definition
|
||||
--> $DIR/reject-specialized-drops-8142.rs:18:1
|
||||
--> $DIR/reject-specialized-drops-8142.rs:48:1
|
||||
|
|
||||
LL | struct Y<const Ca: usize, const Cb: usize>;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0367]: `Drop` impl requires `AddsBnd: Bound` but the enum it is implemented for does not
|
||||
--> $DIR/reject-specialized-drops-8142.rs:66:14
|
||||
--> $DIR/reject-specialized-drops-8142.rs:130:15
|
||||
|
|
||||
LL | impl<AddsBnd:Bound> Drop for Enum<AddsBnd> { fn drop(&mut self) { } } // REJECT
|
||||
| ^^^^^
|
||||
LL | impl<AddsBnd: Bound> Drop for Enum<AddsBnd> {
|
||||
| ^^^^^
|
||||
|
|
||||
note: the implementor must specify the same requirement
|
||||
--> $DIR/reject-specialized-drops-8142.rs:20:1
|
||||
--> $DIR/reject-specialized-drops-8142.rs:50:1
|
||||
|
|
||||
LL | enum Enum<T> { Variant(T) }
|
||||
LL | enum Enum<T> {
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
error[E0367]: `Drop` impl requires `AddsBnd: Bound` but the struct it is implemented for does not
|
||||
--> $DIR/reject-specialized-drops-8142.rs:69:14
|
||||
--> $DIR/reject-specialized-drops-8142.rs:135:15
|
||||
|
|
||||
LL | impl<AddsBnd:Bound> Drop for TupleStruct<AddsBnd> { fn drop(&mut self) { } } // REJECT
|
||||
| ^^^^^
|
||||
LL | impl<AddsBnd: Bound> Drop for TupleStruct<AddsBnd> {
|
||||
| ^^^^^
|
||||
|
|
||||
note: the implementor must specify the same requirement
|
||||
--> $DIR/reject-specialized-drops-8142.rs:21:1
|
||||
--> $DIR/reject-specialized-drops-8142.rs:53:1
|
||||
|
|
||||
LL | struct TupleStruct<T>(T);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0367]: `Drop` impl requires `AddsBnd: Bound` but the union it is implemented for does not
|
||||
--> $DIR/reject-specialized-drops-8142.rs:72:21
|
||||
--> $DIR/reject-specialized-drops-8142.rs:140:22
|
||||
|
|
||||
LL | impl<AddsBnd:Copy + Bound> Drop for Union<AddsBnd> { fn drop(&mut self) { } } // REJECT
|
||||
| ^^^^^
|
||||
LL | impl<AddsBnd: Copy + Bound> Drop for Union<AddsBnd> {
|
||||
| ^^^^^
|
||||
|
|
||||
note: the implementor must specify the same requirement
|
||||
--> $DIR/reject-specialized-drops-8142.rs:22:1
|
||||
--> $DIR/reject-specialized-drops-8142.rs:54:1
|
||||
|
|
||||
LL | union Union<T: Copy> { f: T }
|
||||
LL | union Union<T: Copy> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 13 previous errors
|
||||
error: aborting due to 12 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0366, E0367.
|
||||
For more information about an error, try `rustc --explain E0366`.
|
||||
|
@ -1,8 +1,11 @@
|
||||
error[E0367]: `Drop` impl requires `'a: 'c` but the struct it is implemented for does not
|
||||
--> $DIR/transitive-outlives.rs:20:9
|
||||
--> $DIR/transitive-outlives.rs:18:1
|
||||
|
|
||||
LL | 'a: 'c,
|
||||
| ^^
|
||||
LL | / impl<'a, 'b, 'c> Drop for DropMe<'a, 'b, 'c>
|
||||
LL | |
|
||||
LL | | where
|
||||
LL | | 'a: 'c,
|
||||
| |___________^
|
||||
|
|
||||
note: the implementor must specify the same requirement
|
||||
--> $DIR/transitive-outlives.rs:7:1
|
||||
|
@ -16,9 +16,9 @@ where
|
||||
|
||||
#[cfg(bad)]
|
||||
impl<'a, 'b, 'c> Drop for DropMe<'a, 'b, 'c>
|
||||
//[bad]~^ ERROR `Drop` impl requires `'a: 'c`
|
||||
where
|
||||
'a: 'c,
|
||||
//[bad]~^ ERROR `Drop` impl requires `'a: 'c`
|
||||
{
|
||||
fn drop(&mut self) {}
|
||||
}
|
||||
|
7
tests/ui/dropck/unconstrained_const_param_on_drop.rs
Normal file
7
tests/ui/dropck/unconstrained_const_param_on_drop.rs
Normal file
@ -0,0 +1,7 @@
|
||||
struct Foo {}
|
||||
|
||||
impl<const UNUSED: usize> Drop for Foo {}
|
||||
//~^ ERROR: `Drop` impl requires `the constant `_` has type `usize``
|
||||
//~| ERROR: the const parameter `UNUSED` is not constrained by the impl trait, self type, or predicates
|
||||
|
||||
fn main() {}
|
25
tests/ui/dropck/unconstrained_const_param_on_drop.stderr
Normal file
25
tests/ui/dropck/unconstrained_const_param_on_drop.stderr
Normal file
@ -0,0 +1,25 @@
|
||||
error[E0367]: `Drop` impl requires `the constant `_` has type `usize`` but the struct it is implemented for does not
|
||||
--> $DIR/unconstrained_const_param_on_drop.rs:3:6
|
||||
|
|
||||
LL | impl<const UNUSED: usize> Drop for Foo {}
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: the implementor must specify the same requirement
|
||||
--> $DIR/unconstrained_const_param_on_drop.rs:1:1
|
||||
|
|
||||
LL | struct Foo {}
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error[E0207]: the const parameter `UNUSED` is not constrained by the impl trait, self type, or predicates
|
||||
--> $DIR/unconstrained_const_param_on_drop.rs:3:6
|
||||
|
|
||||
LL | impl<const UNUSED: usize> Drop for Foo {}
|
||||
| ^^^^^^^^^^^^^^^^^^^ unconstrained const parameter
|
||||
|
|
||||
= note: expressions using a const parameter must map each value to a distinct output value
|
||||
= note: proving the result of expressions other than the parameter are unique is not supported
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0207, E0367.
|
||||
For more information about an error, try `rustc --explain E0207`.
|
60
tests/ui/object-safety/almost-supertrait-associated-type.rs
Normal file
60
tests/ui/object-safety/almost-supertrait-associated-type.rs
Normal file
@ -0,0 +1,60 @@
|
||||
// Test for fixed unsoundness in #126079.
|
||||
// Enforces that the associated types that are object safe
|
||||
|
||||
use std::marker::PhantomData;
|
||||
|
||||
fn transmute<T, U>(t: T) -> U {
|
||||
(&PhantomData::<T> as &dyn Foo<T, U>).transmute(t)
|
||||
//~^ ERROR the trait `Foo` cannot be made into an object
|
||||
//~| ERROR the trait `Foo` cannot be made into an object
|
||||
}
|
||||
|
||||
struct ActuallySuper;
|
||||
struct NotActuallySuper;
|
||||
trait Super<Q> {
|
||||
type Assoc;
|
||||
}
|
||||
|
||||
trait Dyn {
|
||||
type Out;
|
||||
}
|
||||
impl<T, U> Dyn for dyn Foo<T, U> + '_ {
|
||||
//~^ ERROR the trait `Foo` cannot be made into an object
|
||||
type Out = U;
|
||||
}
|
||||
impl<S: Dyn<Out = U> + ?Sized, U> Super<NotActuallySuper> for S {
|
||||
type Assoc = U;
|
||||
}
|
||||
|
||||
trait Foo<T, U>: Super<ActuallySuper, Assoc = T>
|
||||
where
|
||||
<Self as Mirror>::Assoc: Super<NotActuallySuper>
|
||||
{
|
||||
fn transmute(&self, t: T) -> <Self as Super<NotActuallySuper>>::Assoc;
|
||||
}
|
||||
|
||||
trait Mirror {
|
||||
type Assoc: ?Sized;
|
||||
}
|
||||
impl<T: ?Sized> Mirror for T {
|
||||
type Assoc = T;
|
||||
}
|
||||
|
||||
impl<T, U> Foo<T, U> for PhantomData<T> {
|
||||
fn transmute(&self, t: T) -> T {
|
||||
t
|
||||
}
|
||||
}
|
||||
impl<T> Super<ActuallySuper> for PhantomData<T> {
|
||||
type Assoc = T;
|
||||
}
|
||||
impl<T> Super<NotActuallySuper> for PhantomData<T> {
|
||||
type Assoc = T;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = String::from("hello, world");
|
||||
let s = transmute::<&str, &'static str>(x.as_str());
|
||||
drop(x);
|
||||
println!("> {s}");
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
error[E0038]: the trait `Foo` cannot be made into an object
|
||||
--> $DIR/almost-supertrait-associated-type.rs:21:20
|
||||
|
|
||||
LL | impl<T, U> Dyn for dyn Foo<T, U> + '_ {
|
||||
| ^^^^^^^^^^^^^^^^^^ `Foo` cannot be made into an object
|
||||
|
|
||||
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
|
||||
--> $DIR/almost-supertrait-associated-type.rs:33:34
|
||||
|
|
||||
LL | trait Foo<T, U>: Super<ActuallySuper, Assoc = T>
|
||||
| --- this trait cannot be made into an object...
|
||||
...
|
||||
LL | fn transmute(&self, t: T) -> <Self as Super<NotActuallySuper>>::Assoc;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...because method `transmute` references the `Self` type in its return type
|
||||
= help: consider moving `transmute` to another trait
|
||||
= help: only type `std::marker::PhantomData<T>` implements the trait, consider using it directly instead
|
||||
|
||||
error[E0038]: the trait `Foo` cannot be made into an object
|
||||
--> $DIR/almost-supertrait-associated-type.rs:7:27
|
||||
|
|
||||
LL | (&PhantomData::<T> as &dyn Foo<T, U>).transmute(t)
|
||||
| ^^^^^^^^^^^^^^ `Foo` cannot be made into an object
|
||||
|
|
||||
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
|
||||
--> $DIR/almost-supertrait-associated-type.rs:33:34
|
||||
|
|
||||
LL | trait Foo<T, U>: Super<ActuallySuper, Assoc = T>
|
||||
| --- this trait cannot be made into an object...
|
||||
...
|
||||
LL | fn transmute(&self, t: T) -> <Self as Super<NotActuallySuper>>::Assoc;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...because method `transmute` references the `Self` type in its return type
|
||||
= help: consider moving `transmute` to another trait
|
||||
= help: only type `std::marker::PhantomData<T>` implements the trait, consider using it directly instead
|
||||
|
||||
error[E0038]: the trait `Foo` cannot be made into an object
|
||||
--> $DIR/almost-supertrait-associated-type.rs:7:6
|
||||
|
|
||||
LL | (&PhantomData::<T> as &dyn Foo<T, U>).transmute(t)
|
||||
| ^^^^^^^^^^^^^^^^^ `Foo` cannot be made into an object
|
||||
|
|
||||
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
|
||||
--> $DIR/almost-supertrait-associated-type.rs:33:34
|
||||
|
|
||||
LL | trait Foo<T, U>: Super<ActuallySuper, Assoc = T>
|
||||
| --- this trait cannot be made into an object...
|
||||
...
|
||||
LL | fn transmute(&self, t: T) -> <Self as Super<NotActuallySuper>>::Assoc;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...because method `transmute` references the `Self` type in its return type
|
||||
= help: consider moving `transmute` to another trait
|
||||
= help: only type `std::marker::PhantomData<T>` implements the trait, consider using it directly instead
|
||||
= note: required for the cast from `&PhantomData<T>` to `&dyn Foo<T, U>`
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0038`.
|
11
tests/ui/object-safety/item-bounds-can-reference-self.rs
Normal file
11
tests/ui/object-safety/item-bounds-can-reference-self.rs
Normal file
@ -0,0 +1,11 @@
|
||||
//@ check-pass
|
||||
|
||||
pub trait Foo {
|
||||
type X: PartialEq;
|
||||
type Y: PartialEq<Self::Y>;
|
||||
type Z: PartialEq<Self::Y>;
|
||||
}
|
||||
|
||||
fn uwu(x: &dyn Foo<X = i32, Y = i32, Z = i32>) {}
|
||||
|
||||
fn main() {}
|
Loading…
Reference in New Issue
Block a user