Auto merge of #124527 - jieyouxu:rollup-eslzncy, r=jieyouxu
Rollup of 7 pull requests Successful merges: - #124269 (Pretty-print parenthesis around binary in postfix match) - #124415 (Use probes more aggressively in new solver) - #124475 (Remove direct dependencies on lazy_static, once_cell and byteorder) - #124484 (Fix #124478 - offset_of! returns a temporary) - #124504 (Mark unions non-const-propagatable in `KnownPanicsLint` without calling layout) - #124508 (coverage: Avoid hard-coded values when visiting logical ops) - #124522 ([Refactor] Rename `Lint` and `LintGroup`'s `is_loaded` to `is_externally_loaded` ) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
a8a1d3a771
@ -2113,7 +2113,6 @@ dependencies = [
|
||||
"fs-err",
|
||||
"getopts",
|
||||
"jsonpath_lib",
|
||||
"once_cell",
|
||||
"regex",
|
||||
"serde_json",
|
||||
"shlex",
|
||||
@ -2232,7 +2231,6 @@ name = "linkchecker"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"html5ever",
|
||||
"once_cell",
|
||||
"regex",
|
||||
]
|
||||
|
||||
@ -2491,7 +2489,6 @@ dependencies = [
|
||||
"directories",
|
||||
"getrandom",
|
||||
"jemalloc-sys",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"libffi",
|
||||
"libloading",
|
||||
@ -4791,12 +4788,10 @@ dependencies = [
|
||||
"arrayvec",
|
||||
"askama",
|
||||
"base64",
|
||||
"byteorder",
|
||||
"expect-test",
|
||||
"indexmap",
|
||||
"itertools 0.12.1",
|
||||
"minifier",
|
||||
"once_cell",
|
||||
"regex",
|
||||
"rustdoc-json-types",
|
||||
"serde",
|
||||
@ -5351,7 +5346,6 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"build_helper",
|
||||
"glob",
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -5596,7 +5590,6 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"cargo_metadata 0.15.4",
|
||||
"ignore",
|
||||
"lazy_static",
|
||||
"miropt-test-tools",
|
||||
"regex",
|
||||
"rustc-hash",
|
||||
|
@ -488,7 +488,7 @@ impl<'a> State<'a> {
|
||||
self.space();
|
||||
}
|
||||
MatchKind::Postfix => {
|
||||
self.print_expr_as_cond(expr);
|
||||
self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX, fixup);
|
||||
self.word_nbsp(".match");
|
||||
}
|
||||
}
|
||||
|
@ -971,7 +971,7 @@ Available lint options:
|
||||
|
||||
let lint_store = unerased_lint_store(sess);
|
||||
let (loaded, builtin): (Vec<_>, _) =
|
||||
lint_store.get_lints().iter().cloned().partition(|&lint| lint.is_loaded);
|
||||
lint_store.get_lints().iter().cloned().partition(|&lint| lint.is_externally_loaded);
|
||||
let loaded = sort_lints(sess, loaded);
|
||||
let builtin = sort_lints(sess, builtin);
|
||||
|
||||
|
@ -110,7 +110,7 @@ struct LintAlias {
|
||||
|
||||
struct LintGroup {
|
||||
lint_ids: Vec<LintId>,
|
||||
is_loaded: bool,
|
||||
is_externally_loaded: bool,
|
||||
depr: Option<LintAlias>,
|
||||
}
|
||||
|
||||
@ -159,7 +159,9 @@ impl LintStore {
|
||||
// Don't display deprecated lint groups.
|
||||
depr.is_none()
|
||||
})
|
||||
.map(|(k, LintGroup { lint_ids, is_loaded, .. })| (*k, lint_ids.clone(), *is_loaded))
|
||||
.map(|(k, LintGroup { lint_ids, is_externally_loaded, .. })| {
|
||||
(*k, lint_ids.clone(), *is_externally_loaded)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn register_early_pass(
|
||||
@ -218,7 +220,7 @@ impl LintStore {
|
||||
.entry(edition.lint_name())
|
||||
.or_insert(LintGroup {
|
||||
lint_ids: vec![],
|
||||
is_loaded: lint.is_loaded,
|
||||
is_externally_loaded: lint.is_externally_loaded,
|
||||
depr: None,
|
||||
})
|
||||
.lint_ids
|
||||
@ -231,7 +233,7 @@ impl LintStore {
|
||||
.entry("future_incompatible")
|
||||
.or_insert(LintGroup {
|
||||
lint_ids: vec![],
|
||||
is_loaded: lint.is_loaded,
|
||||
is_externally_loaded: lint.is_externally_loaded,
|
||||
depr: None,
|
||||
})
|
||||
.lint_ids
|
||||
@ -246,7 +248,7 @@ impl LintStore {
|
||||
alias,
|
||||
LintGroup {
|
||||
lint_ids: vec![],
|
||||
is_loaded: false,
|
||||
is_externally_loaded: false,
|
||||
depr: Some(LintAlias { name: lint_name, silent: true }),
|
||||
},
|
||||
);
|
||||
@ -254,21 +256,21 @@ impl LintStore {
|
||||
|
||||
pub fn register_group(
|
||||
&mut self,
|
||||
is_loaded: bool,
|
||||
is_externally_loaded: bool,
|
||||
name: &'static str,
|
||||
deprecated_name: Option<&'static str>,
|
||||
to: Vec<LintId>,
|
||||
) {
|
||||
let new = self
|
||||
.lint_groups
|
||||
.insert(name, LintGroup { lint_ids: to, is_loaded, depr: None })
|
||||
.insert(name, LintGroup { lint_ids: to, is_externally_loaded, depr: None })
|
||||
.is_none();
|
||||
if let Some(deprecated) = deprecated_name {
|
||||
self.lint_groups.insert(
|
||||
deprecated,
|
||||
LintGroup {
|
||||
lint_ids: vec![],
|
||||
is_loaded,
|
||||
is_externally_loaded,
|
||||
depr: Some(LintAlias { name, silent: false }),
|
||||
},
|
||||
);
|
||||
|
@ -176,6 +176,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
|
||||
| hir::BinOpKind::Shr => Some("bitwise operation"),
|
||||
},
|
||||
hir::ExprKind::AddrOf(..) => Some("borrow"),
|
||||
hir::ExprKind::OffsetOf(..) => Some("`offset_of` call"),
|
||||
hir::ExprKind::Unary(..) => Some("unary operation"),
|
||||
_ => None,
|
||||
};
|
||||
|
@ -323,7 +323,8 @@ pub struct Lint {
|
||||
|
||||
pub future_incompatible: Option<FutureIncompatibleInfo>,
|
||||
|
||||
pub is_loaded: bool,
|
||||
/// `true` if this lint is being loaded by another tool (e.g. Clippy).
|
||||
pub is_externally_loaded: bool,
|
||||
|
||||
/// `Some` if this lint is feature gated, otherwise `None`.
|
||||
pub feature_gate: Option<Symbol>,
|
||||
@ -468,7 +469,7 @@ impl Lint {
|
||||
default_level: Level::Forbid,
|
||||
desc: "",
|
||||
edition_lint_opts: None,
|
||||
is_loaded: false,
|
||||
is_externally_loaded: false,
|
||||
report_in_external_macro: false,
|
||||
future_incompatible: None,
|
||||
feature_gate: None,
|
||||
@ -817,7 +818,7 @@ macro_rules! declare_lint {
|
||||
name: stringify!($NAME),
|
||||
default_level: $crate::$Level,
|
||||
desc: $desc,
|
||||
is_loaded: false,
|
||||
is_externally_loaded: false,
|
||||
$($v: true,)*
|
||||
$(feature_gate: Some($gate),)?
|
||||
$(future_incompatible: Some($crate::FutureIncompatibleInfo {
|
||||
@ -859,7 +860,7 @@ macro_rules! declare_tool_lint {
|
||||
edition_lint_opts: None,
|
||||
report_in_external_macro: $external,
|
||||
future_incompatible: None,
|
||||
is_loaded: true,
|
||||
is_externally_loaded: true,
|
||||
$(feature_gate: Some($gate),)?
|
||||
crate_level_only: false,
|
||||
..$crate::Lint::default_fields_for_macro()
|
||||
|
@ -332,4 +332,9 @@ pub enum CandidateSource {
|
||||
/// }
|
||||
/// ```
|
||||
AliasBound,
|
||||
/// A candidate that is registered only during coherence to represent some
|
||||
/// yet-unknown impl that could be produced downstream without violating orphan
|
||||
/// rules.
|
||||
// FIXME: Merge this with the forced ambiguity candidates, so those don't use `Misc`.
|
||||
CoherenceUnknowable,
|
||||
}
|
||||
|
@ -141,10 +141,6 @@ pub enum ProbeKind<'tcx> {
|
||||
TryNormalizeNonRigid { result: QueryResult<'tcx> },
|
||||
/// Probe entered when normalizing the self ty during candidate assembly
|
||||
NormalizedSelfTyAssembly,
|
||||
/// Some candidate to prove the current goal.
|
||||
///
|
||||
/// FIXME: Remove this in favor of always using more strongly typed variants.
|
||||
MiscCandidate { name: &'static str, result: QueryResult<'tcx> },
|
||||
/// A candidate for proving a trait or alias-relate goal.
|
||||
TraitCandidate { source: CandidateSource, result: QueryResult<'tcx> },
|
||||
/// Used in the probe that wraps normalizing the non-self type for the unsize
|
||||
@ -154,4 +150,6 @@ pub enum ProbeKind<'tcx> {
|
||||
/// do a probe to find out what projection type(s) may be used to prove that
|
||||
/// the source type upholds all of the target type's object bounds.
|
||||
UpcastProjectionCompatibility,
|
||||
/// Try to unify an opaque type with an existing key in the storage.
|
||||
OpaqueTypeStorageLookup { result: QueryResult<'tcx> },
|
||||
}
|
||||
|
@ -112,8 +112,8 @@ impl<'a, 'b> ProofTreeFormatter<'a, 'b> {
|
||||
ProbeKind::UpcastProjectionCompatibility => {
|
||||
write!(self.f, "PROBING FOR PROJECTION COMPATIBILITY FOR UPCASTING:")
|
||||
}
|
||||
ProbeKind::MiscCandidate { name, result } => {
|
||||
write!(self.f, "CANDIDATE {name}: {result:?}")
|
||||
ProbeKind::OpaqueTypeStorageLookup { result } => {
|
||||
write!(self.f, "PROBING FOR AN EXISTING OPAQUE: {result:?}")
|
||||
}
|
||||
ProbeKind::TraitCandidate { source, result } => {
|
||||
write!(self.f, "CANDIDATE {source:?}: {result:?}")
|
||||
|
@ -73,14 +73,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
let expr_span = expr.span;
|
||||
|
||||
match expr.kind {
|
||||
ExprKind::LogicalOp { op: LogicalOp::And, lhs, rhs } => {
|
||||
this.visit_coverage_branch_operation(LogicalOp::And, expr_span);
|
||||
ExprKind::LogicalOp { op: op @ LogicalOp::And, lhs, rhs } => {
|
||||
this.visit_coverage_branch_operation(op, expr_span);
|
||||
let lhs_then_block = unpack!(this.then_else_break_inner(block, lhs, args));
|
||||
let rhs_then_block = unpack!(this.then_else_break_inner(lhs_then_block, rhs, args));
|
||||
rhs_then_block.unit()
|
||||
}
|
||||
ExprKind::LogicalOp { op: LogicalOp::Or, lhs, rhs } => {
|
||||
this.visit_coverage_branch_operation(LogicalOp::Or, expr_span);
|
||||
ExprKind::LogicalOp { op: op @ LogicalOp::Or, lhs, rhs } => {
|
||||
this.visit_coverage_branch_operation(op, expr_span);
|
||||
let local_scope = this.local_scope();
|
||||
let (lhs_success_block, failure_block) =
|
||||
this.in_if_then_scope(local_scope, expr_span, |this| {
|
||||
|
@ -896,13 +896,19 @@ impl CanConstProp {
|
||||
};
|
||||
for (local, val) in cpv.can_const_prop.iter_enumerated_mut() {
|
||||
let ty = body.local_decls[local].ty;
|
||||
match tcx.layout_of(param_env.and(ty)) {
|
||||
Ok(layout) if layout.size < Size::from_bytes(MAX_ALLOC_LIMIT) => {}
|
||||
// Either the layout fails to compute, then we can't use this local anyway
|
||||
// or the local is too large, then we don't want to.
|
||||
_ => {
|
||||
*val = ConstPropMode::NoPropagation;
|
||||
continue;
|
||||
if ty.is_union() {
|
||||
// Do not const prop unions as they can
|
||||
// ICE during layout calc
|
||||
*val = ConstPropMode::NoPropagation;
|
||||
} else {
|
||||
match tcx.layout_of(param_env.and(ty)) {
|
||||
Ok(layout) if layout.size < Size::from_bytes(MAX_ALLOC_LIMIT) => {}
|
||||
// Either the layout fails to compute, then we can't use this local anyway
|
||||
// or the local is too large, then we don't want to.
|
||||
_ => {
|
||||
*val = ConstPropMode::NoPropagation;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -48,21 +48,23 @@ pub(super) trait GoalKind<'tcx>:
|
||||
/// [`EvalCtxt::evaluate_added_goals_and_make_canonical_response`]).
|
||||
fn probe_and_match_goal_against_assumption(
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
source: CandidateSource,
|
||||
goal: Goal<'tcx, Self>,
|
||||
assumption: ty::Clause<'tcx>,
|
||||
then: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> QueryResult<'tcx>,
|
||||
) -> QueryResult<'tcx>;
|
||||
) -> Result<Candidate<'tcx>, NoSolution>;
|
||||
|
||||
/// Consider a clause, which consists of a "assumption" and some "requirements",
|
||||
/// to satisfy a goal. If the requirements hold, then attempt to satisfy our
|
||||
/// goal by equating it with the assumption.
|
||||
fn consider_implied_clause(
|
||||
fn probe_and_consider_implied_clause(
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
source: CandidateSource,
|
||||
goal: Goal<'tcx, Self>,
|
||||
assumption: ty::Clause<'tcx>,
|
||||
requirements: impl IntoIterator<Item = Goal<'tcx, ty::Predicate<'tcx>>>,
|
||||
) -> QueryResult<'tcx> {
|
||||
Self::probe_and_match_goal_against_assumption(ecx, goal, assumption, |ecx| {
|
||||
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||
Self::probe_and_match_goal_against_assumption(ecx, source, goal, assumption, |ecx| {
|
||||
// FIXME(-Znext-solver=coinductive): check whether this should be
|
||||
// `GoalSource::ImplWhereBound` for any caller.
|
||||
ecx.add_goals(GoalSource::Misc, requirements);
|
||||
@ -73,15 +75,16 @@ pub(super) trait GoalKind<'tcx>:
|
||||
/// Consider a clause specifically for a `dyn Trait` self type. This requires
|
||||
/// additionally checking all of the supertraits and object bounds to hold,
|
||||
/// since they're not implied by the well-formedness of the object type.
|
||||
fn consider_object_bound_candidate(
|
||||
fn probe_and_consider_object_bound_candidate(
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
source: CandidateSource,
|
||||
goal: Goal<'tcx, Self>,
|
||||
assumption: ty::Clause<'tcx>,
|
||||
) -> QueryResult<'tcx> {
|
||||
Self::probe_and_match_goal_against_assumption(ecx, goal, assumption, |ecx| {
|
||||
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||
Self::probe_and_match_goal_against_assumption(ecx, source, goal, assumption, |ecx| {
|
||||
let tcx = ecx.tcx();
|
||||
let ty::Dynamic(bounds, _, _) = *goal.predicate.self_ty().kind() else {
|
||||
bug!("expected object type in `consider_object_bound_candidate`");
|
||||
bug!("expected object type in `probe_and_consider_object_bound_candidate`");
|
||||
};
|
||||
// FIXME(-Znext-solver=coinductive): Should this be `GoalSource::ImplWhereBound`?
|
||||
ecx.add_goals(
|
||||
@ -112,7 +115,7 @@ pub(super) trait GoalKind<'tcx>:
|
||||
fn consider_error_guaranteed_candidate(
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
guar: ErrorGuaranteed,
|
||||
) -> QueryResult<'tcx>;
|
||||
) -> Result<Candidate<'tcx>, NoSolution>;
|
||||
|
||||
/// A type implements an `auto trait` if its components do as well.
|
||||
///
|
||||
@ -121,13 +124,13 @@ pub(super) trait GoalKind<'tcx>:
|
||||
fn consider_auto_trait_candidate(
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> QueryResult<'tcx>;
|
||||
) -> Result<Candidate<'tcx>, NoSolution>;
|
||||
|
||||
/// A trait alias holds if the RHS traits and `where` clauses hold.
|
||||
fn consider_trait_alias_candidate(
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> QueryResult<'tcx>;
|
||||
) -> Result<Candidate<'tcx>, NoSolution>;
|
||||
|
||||
/// A type is `Sized` if its tail component is `Sized`.
|
||||
///
|
||||
@ -136,7 +139,7 @@ pub(super) trait GoalKind<'tcx>:
|
||||
fn consider_builtin_sized_candidate(
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> QueryResult<'tcx>;
|
||||
) -> Result<Candidate<'tcx>, NoSolution>;
|
||||
|
||||
/// A type is `Copy` or `Clone` if its components are `Copy` or `Clone`.
|
||||
///
|
||||
@ -145,20 +148,20 @@ pub(super) trait GoalKind<'tcx>:
|
||||
fn consider_builtin_copy_clone_candidate(
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> QueryResult<'tcx>;
|
||||
) -> Result<Candidate<'tcx>, NoSolution>;
|
||||
|
||||
/// A type is `PointerLike` if we can compute its layout, and that layout
|
||||
/// matches the layout of `usize`.
|
||||
fn consider_builtin_pointer_like_candidate(
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> QueryResult<'tcx>;
|
||||
) -> Result<Candidate<'tcx>, NoSolution>;
|
||||
|
||||
/// A type is a `FnPtr` if it is of `FnPtr` type.
|
||||
fn consider_builtin_fn_ptr_trait_candidate(
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> QueryResult<'tcx>;
|
||||
) -> Result<Candidate<'tcx>, NoSolution>;
|
||||
|
||||
/// A callable type (a closure, fn def, or fn ptr) is known to implement the `Fn<A>`
|
||||
/// family of traits where `A` is given by the signature of the type.
|
||||
@ -166,7 +169,7 @@ pub(super) trait GoalKind<'tcx>:
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
kind: ty::ClosureKind,
|
||||
) -> QueryResult<'tcx>;
|
||||
) -> Result<Candidate<'tcx>, NoSolution>;
|
||||
|
||||
/// An async closure is known to implement the `AsyncFn<A>` family of traits
|
||||
/// where `A` is given by the signature of the type.
|
||||
@ -174,7 +177,7 @@ pub(super) trait GoalKind<'tcx>:
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
kind: ty::ClosureKind,
|
||||
) -> QueryResult<'tcx>;
|
||||
) -> Result<Candidate<'tcx>, NoSolution>;
|
||||
|
||||
/// Compute the built-in logic of the `AsyncFnKindHelper` helper trait, which
|
||||
/// is used internally to delay computation for async closures until after
|
||||
@ -182,13 +185,13 @@ pub(super) trait GoalKind<'tcx>:
|
||||
fn consider_builtin_async_fn_kind_helper_candidate(
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> QueryResult<'tcx>;
|
||||
) -> Result<Candidate<'tcx>, NoSolution>;
|
||||
|
||||
/// `Tuple` is implemented if the `Self` type is a tuple.
|
||||
fn consider_builtin_tuple_candidate(
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> QueryResult<'tcx>;
|
||||
) -> Result<Candidate<'tcx>, NoSolution>;
|
||||
|
||||
/// `Pointee` is always implemented.
|
||||
///
|
||||
@ -198,7 +201,7 @@ pub(super) trait GoalKind<'tcx>:
|
||||
fn consider_builtin_pointee_candidate(
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> QueryResult<'tcx>;
|
||||
) -> Result<Candidate<'tcx>, NoSolution>;
|
||||
|
||||
/// A coroutine (that comes from an `async` desugaring) is known to implement
|
||||
/// `Future<Output = O>`, where `O` is given by the coroutine's return type
|
||||
@ -206,7 +209,7 @@ pub(super) trait GoalKind<'tcx>:
|
||||
fn consider_builtin_future_candidate(
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> QueryResult<'tcx>;
|
||||
) -> Result<Candidate<'tcx>, NoSolution>;
|
||||
|
||||
/// A coroutine (that comes from a `gen` desugaring) is known to implement
|
||||
/// `Iterator<Item = O>`, where `O` is given by the generator's yield type
|
||||
@ -214,19 +217,19 @@ pub(super) trait GoalKind<'tcx>:
|
||||
fn consider_builtin_iterator_candidate(
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> QueryResult<'tcx>;
|
||||
) -> Result<Candidate<'tcx>, NoSolution>;
|
||||
|
||||
/// A coroutine (that comes from a `gen` desugaring) is known to implement
|
||||
/// `FusedIterator`
|
||||
fn consider_builtin_fused_iterator_candidate(
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> QueryResult<'tcx>;
|
||||
) -> Result<Candidate<'tcx>, NoSolution>;
|
||||
|
||||
fn consider_builtin_async_iterator_candidate(
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> QueryResult<'tcx>;
|
||||
) -> Result<Candidate<'tcx>, NoSolution>;
|
||||
|
||||
/// A coroutine (that doesn't come from an `async` or `gen` desugaring) is known to
|
||||
/// implement `Coroutine<R, Yield = Y, Return = O>`, given the resume, yield,
|
||||
@ -234,27 +237,27 @@ pub(super) trait GoalKind<'tcx>:
|
||||
fn consider_builtin_coroutine_candidate(
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> QueryResult<'tcx>;
|
||||
) -> Result<Candidate<'tcx>, NoSolution>;
|
||||
|
||||
fn consider_builtin_discriminant_kind_candidate(
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> QueryResult<'tcx>;
|
||||
) -> Result<Candidate<'tcx>, NoSolution>;
|
||||
|
||||
fn consider_builtin_async_destruct_candidate(
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> QueryResult<'tcx>;
|
||||
) -> Result<Candidate<'tcx>, NoSolution>;
|
||||
|
||||
fn consider_builtin_destruct_candidate(
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> QueryResult<'tcx>;
|
||||
) -> Result<Candidate<'tcx>, NoSolution>;
|
||||
|
||||
fn consider_builtin_transmute_candidate(
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> QueryResult<'tcx>;
|
||||
) -> Result<Candidate<'tcx>, NoSolution>;
|
||||
|
||||
/// Consider (possibly several) candidates to upcast or unsize a type to another
|
||||
/// type, excluding the coercion of a sized type into a `dyn Trait`.
|
||||
@ -266,7 +269,7 @@ pub(super) trait GoalKind<'tcx>:
|
||||
fn consider_structural_builtin_unsize_candidates(
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> Vec<(CanonicalResponse<'tcx>, BuiltinImplSource)>;
|
||||
) -> Vec<Candidate<'tcx>>;
|
||||
}
|
||||
|
||||
impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||
@ -282,7 +285,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||
|
||||
if normalized_self_ty.is_ty_var() {
|
||||
debug!("self type has been normalized to infer");
|
||||
return self.forced_ambiguity(MaybeCause::Ambiguity);
|
||||
return self.forced_ambiguity(MaybeCause::Ambiguity).into_iter().collect();
|
||||
}
|
||||
|
||||
let goal =
|
||||
@ -315,7 +318,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||
candidates
|
||||
}
|
||||
|
||||
fn forced_ambiguity(&mut self, cause: MaybeCause) -> Vec<Candidate<'tcx>> {
|
||||
pub(super) fn forced_ambiguity(
|
||||
&mut self,
|
||||
cause: MaybeCause,
|
||||
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||
// This may fail if `try_evaluate_added_goals` overflows because it
|
||||
// fails to reach a fixpoint but ends up getting an error after
|
||||
// running for some additional step.
|
||||
@ -323,10 +329,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||
// cc trait-system-refactor-initiative#105
|
||||
let source = CandidateSource::BuiltinImpl(BuiltinImplSource::Misc);
|
||||
let certainty = Certainty::Maybe(cause);
|
||||
let result = self
|
||||
.probe_trait_candidate(source)
|
||||
.enter(|this| this.evaluate_added_goals_and_make_canonical_response(certainty));
|
||||
if let Ok(cand) = result { vec![cand] } else { vec![] }
|
||||
self.probe_trait_candidate(source)
|
||||
.enter(|this| this.evaluate_added_goals_and_make_canonical_response(certainty))
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip_all)]
|
||||
@ -533,20 +537,12 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||
Err(NoSolution)
|
||||
};
|
||||
|
||||
match result {
|
||||
Ok(result) => candidates.push(Candidate {
|
||||
source: CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
|
||||
result,
|
||||
}),
|
||||
Err(NoSolution) => (),
|
||||
}
|
||||
candidates.extend(result);
|
||||
|
||||
// There may be multiple unsize candidates for a trait with several supertraits:
|
||||
// `trait Foo: Bar<A> + Bar<B>` and `dyn Foo: Unsize<dyn Bar<_>>`
|
||||
if lang_items.unsize_trait() == Some(trait_def_id) {
|
||||
for (result, source) in G::consider_structural_builtin_unsize_candidates(self, goal) {
|
||||
candidates.push(Candidate { source: CandidateSource::BuiltinImpl(source), result });
|
||||
}
|
||||
candidates.extend(G::consider_structural_builtin_unsize_candidates(self, goal));
|
||||
}
|
||||
}
|
||||
|
||||
@ -557,12 +553,13 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||
candidates: &mut Vec<Candidate<'tcx>>,
|
||||
) {
|
||||
for (i, assumption) in goal.param_env.caller_bounds().iter().enumerate() {
|
||||
match G::consider_implied_clause(self, goal, assumption, []) {
|
||||
Ok(result) => {
|
||||
candidates.push(Candidate { source: CandidateSource::ParamEnv(i), result })
|
||||
}
|
||||
Err(NoSolution) => (),
|
||||
}
|
||||
candidates.extend(G::probe_and_consider_implied_clause(
|
||||
self,
|
||||
CandidateSource::ParamEnv(i),
|
||||
goal,
|
||||
assumption,
|
||||
[],
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@ -648,12 +645,13 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||
for assumption in
|
||||
self.tcx().item_bounds(alias_ty.def_id).instantiate(self.tcx(), alias_ty.args)
|
||||
{
|
||||
match G::consider_implied_clause(self, goal, assumption, []) {
|
||||
Ok(result) => {
|
||||
candidates.push(Candidate { source: CandidateSource::AliasBound, result });
|
||||
}
|
||||
Err(NoSolution) => {}
|
||||
}
|
||||
candidates.extend(G::probe_and_consider_implied_clause(
|
||||
self,
|
||||
CandidateSource::AliasBound,
|
||||
goal,
|
||||
assumption,
|
||||
[],
|
||||
));
|
||||
}
|
||||
|
||||
if kind != ty::Projection {
|
||||
@ -728,17 +726,12 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||
}
|
||||
ty::ExistentialPredicate::Projection(_)
|
||||
| ty::ExistentialPredicate::AutoTrait(_) => {
|
||||
match G::consider_object_bound_candidate(
|
||||
candidates.extend(G::probe_and_consider_object_bound_candidate(
|
||||
self,
|
||||
CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
|
||||
goal,
|
||||
bound.with_self_ty(tcx, self_ty),
|
||||
) {
|
||||
Ok(result) => candidates.push(Candidate {
|
||||
source: CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
|
||||
result,
|
||||
}),
|
||||
Err(NoSolution) => (),
|
||||
}
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -749,15 +742,12 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||
if let Some(principal) = bounds.principal() {
|
||||
let principal_trait_ref = principal.with_self_ty(tcx, self_ty);
|
||||
self.walk_vtable(principal_trait_ref, |ecx, assumption, vtable_base, _| {
|
||||
match G::consider_object_bound_candidate(ecx, goal, assumption.to_predicate(tcx)) {
|
||||
Ok(result) => candidates.push(Candidate {
|
||||
source: CandidateSource::BuiltinImpl(BuiltinImplSource::Object {
|
||||
vtable_base,
|
||||
}),
|
||||
result,
|
||||
}),
|
||||
Err(NoSolution) => (),
|
||||
}
|
||||
candidates.extend(G::probe_and_consider_object_bound_candidate(
|
||||
ecx,
|
||||
CandidateSource::BuiltinImpl(BuiltinImplSource::Object { vtable_base }),
|
||||
goal,
|
||||
assumption.to_predicate(tcx),
|
||||
));
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -775,25 +765,20 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||
candidates: &mut Vec<Candidate<'tcx>>,
|
||||
) {
|
||||
let tcx = self.tcx();
|
||||
let result = self.probe_misc_candidate("coherence unknowable").enter(|ecx| {
|
||||
let trait_ref = goal.predicate.trait_ref(tcx);
|
||||
let lazily_normalize_ty = |ty| ecx.structurally_normalize_ty(goal.param_env, ty);
|
||||
|
||||
match coherence::trait_ref_is_knowable(tcx, trait_ref, lazily_normalize_ty)? {
|
||||
Ok(()) => Err(NoSolution),
|
||||
Err(_) => {
|
||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
|
||||
candidates.extend(self.probe_trait_candidate(CandidateSource::CoherenceUnknowable).enter(
|
||||
|ecx| {
|
||||
let trait_ref = goal.predicate.trait_ref(tcx);
|
||||
let lazily_normalize_ty = |ty| ecx.structurally_normalize_ty(goal.param_env, ty);
|
||||
|
||||
match coherence::trait_ref_is_knowable(tcx, trait_ref, lazily_normalize_ty)? {
|
||||
Ok(()) => Err(NoSolution),
|
||||
Err(_) => {
|
||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
match result {
|
||||
Ok(result) => candidates.push(Candidate {
|
||||
source: CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
|
||||
result,
|
||||
}),
|
||||
Err(NoSolution) => {}
|
||||
}
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
/// If there's a where-bound for the current goal, do not use any impl candidates
|
||||
@ -838,6 +823,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||
false
|
||||
}
|
||||
CandidateSource::ParamEnv(_) | CandidateSource::AliasBound => true,
|
||||
CandidateSource::CoherenceUnknowable => bug!("uh oh"),
|
||||
});
|
||||
}
|
||||
// If it is still ambiguous we instead just force the whole goal
|
||||
@ -845,7 +831,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||
// tests/ui/traits/next-solver/env-shadows-impls/ambig-env-no-shadow.rs
|
||||
Certainty::Maybe(cause) => {
|
||||
debug!(?cause, "force ambiguity");
|
||||
*candidates = self.forced_ambiguity(cause);
|
||||
*candidates = self.forced_ambiguity(cause).into_iter().collect();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -998,19 +998,24 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||
if candidate_key.def_id != key.def_id {
|
||||
continue;
|
||||
}
|
||||
values.extend(self.probe_misc_candidate("opaque type storage").enter(|ecx| {
|
||||
for (a, b) in std::iter::zip(candidate_key.args, key.args) {
|
||||
ecx.eq(param_env, a, b)?;
|
||||
}
|
||||
ecx.eq(param_env, candidate_ty, ty)?;
|
||||
ecx.add_item_bounds_for_hidden_type(
|
||||
candidate_key.def_id.to_def_id(),
|
||||
candidate_key.args,
|
||||
param_env,
|
||||
candidate_ty,
|
||||
);
|
||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
}));
|
||||
values.extend(
|
||||
self.probe(|result| inspect::ProbeKind::OpaqueTypeStorageLookup {
|
||||
result: *result,
|
||||
})
|
||||
.enter(|ecx| {
|
||||
for (a, b) in std::iter::zip(candidate_key.args, key.args) {
|
||||
ecx.eq(param_env, a, b)?;
|
||||
}
|
||||
ecx.eq(param_env, candidate_ty, ty)?;
|
||||
ecx.add_item_bounds_for_hidden_type(
|
||||
candidate_key.def_id.to_def_id(),
|
||||
candidate_key.args,
|
||||
param_env,
|
||||
candidate_ty,
|
||||
);
|
||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
}),
|
||||
);
|
||||
}
|
||||
values
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
use crate::solve::assembly::Candidate;
|
||||
|
||||
use super::EvalCtxt;
|
||||
use rustc_infer::traits::BuiltinImplSource;
|
||||
use rustc_middle::traits::{
|
||||
query::NoSolution,
|
||||
solve::{inspect, CandidateSource, QueryResult},
|
||||
@ -75,24 +76,12 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
|
||||
ProbeCtxt { ecx: self, probe_kind, _result: PhantomData }
|
||||
}
|
||||
|
||||
pub(in crate::solve) fn probe_misc_candidate(
|
||||
pub(in crate::solve) fn probe_builtin_trait_candidate(
|
||||
&mut self,
|
||||
name: &'static str,
|
||||
) -> ProbeCtxt<
|
||||
'_,
|
||||
'a,
|
||||
'tcx,
|
||||
impl FnOnce(&QueryResult<'tcx>) -> inspect::ProbeKind<'tcx>,
|
||||
QueryResult<'tcx>,
|
||||
> {
|
||||
ProbeCtxt {
|
||||
ecx: self,
|
||||
probe_kind: move |result: &QueryResult<'tcx>| inspect::ProbeKind::MiscCandidate {
|
||||
name,
|
||||
result: *result,
|
||||
},
|
||||
_result: PhantomData,
|
||||
}
|
||||
source: BuiltinImplSource,
|
||||
) -> TraitProbeCtxt<'_, 'a, 'tcx, impl FnOnce(&QueryResult<'tcx>) -> inspect::ProbeKind<'tcx>>
|
||||
{
|
||||
self.probe_trait_candidate(CandidateSource::BuiltinImpl(source))
|
||||
}
|
||||
|
||||
pub(in crate::solve) fn probe_trait_candidate(
|
||||
|
@ -107,6 +107,8 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
Ok(Some(ImplSource::Param(vec![])))
|
||||
}
|
||||
|
||||
(_, CandidateSource::CoherenceUnknowable) => bug!(),
|
||||
|
||||
(Certainty::Maybe(_), _) => Ok(None),
|
||||
}
|
||||
})
|
||||
|
@ -45,7 +45,7 @@ pub struct InspectCandidate<'a, 'tcx> {
|
||||
nested_goals: Vec<inspect::CanonicalState<'tcx, Goal<'tcx, ty::Predicate<'tcx>>>>,
|
||||
final_state: inspect::CanonicalState<'tcx, ()>,
|
||||
result: QueryResult<'tcx>,
|
||||
candidate_certainty: Option<Certainty>,
|
||||
shallow_certainty: Certainty,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> InspectCandidate<'a, 'tcx> {
|
||||
@ -59,15 +59,14 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> {
|
||||
|
||||
/// Certainty passed into `evaluate_added_goals_and_make_canonical_response`.
|
||||
///
|
||||
/// If this certainty is `Some(Yes)`, then we must be confident that the candidate
|
||||
/// If this certainty is `Yes`, then we must be confident that the candidate
|
||||
/// must hold iff it's nested goals hold. This is not true if the certainty is
|
||||
/// `Some(Maybe)`, which suggests we forced ambiguity instead, or if it is `None`,
|
||||
/// which suggests we may have not assembled any candidates at all.
|
||||
/// `Maybe(..)`, which suggests we forced ambiguity instead.
|
||||
///
|
||||
/// This is *not* the certainty of the candidate's nested evaluation, which can be
|
||||
/// accessed with [`Self::result`] instead.
|
||||
pub fn candidate_certainty(&self) -> Option<Certainty> {
|
||||
self.candidate_certainty
|
||||
/// This is *not* the certainty of the candidate's full nested evaluation, which
|
||||
/// can be accessed with [`Self::result`] instead.
|
||||
pub fn shallow_certainty(&self) -> Certainty {
|
||||
self.shallow_certainty
|
||||
}
|
||||
|
||||
/// Visit all nested goals of this candidate without rolling
|
||||
@ -174,9 +173,7 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
|
||||
nested_goals: &mut Vec<inspect::CanonicalState<'tcx, Goal<'tcx, ty::Predicate<'tcx>>>>,
|
||||
probe: &inspect::Probe<'tcx>,
|
||||
) {
|
||||
let mut candidate_certainty = None;
|
||||
let num_candidates = candidates.len();
|
||||
|
||||
let mut shallow_certainty = None;
|
||||
for step in &probe.steps {
|
||||
match step {
|
||||
&inspect::ProbeStep::AddGoal(_source, goal) => nested_goals.push(goal),
|
||||
@ -188,8 +185,8 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
|
||||
self.candidates_recur(candidates, nested_goals, probe);
|
||||
nested_goals.truncate(num_goals);
|
||||
}
|
||||
inspect::ProbeStep::MakeCanonicalResponse { shallow_certainty } => {
|
||||
assert_eq!(candidate_certainty.replace(*shallow_certainty), None);
|
||||
inspect::ProbeStep::MakeCanonicalResponse { shallow_certainty: c } => {
|
||||
assert_eq!(shallow_certainty.replace(*c), None);
|
||||
}
|
||||
inspect::ProbeStep::EvaluateGoals(_) => (),
|
||||
}
|
||||
@ -199,36 +196,26 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
|
||||
inspect::ProbeKind::NormalizedSelfTyAssembly
|
||||
| inspect::ProbeKind::UnsizeAssembly
|
||||
| inspect::ProbeKind::UpcastProjectionCompatibility => (),
|
||||
// We add a candidate for the root evaluation if there
|
||||
|
||||
// We add a candidate even for the root evaluation if there
|
||||
// is only one way to prove a given goal, e.g. for `WellFormed`.
|
||||
//
|
||||
// FIXME: This is currently wrong if we don't even try any
|
||||
// candidates, e.g. for a trait goal, as in this case `candidates` is
|
||||
// actually supposed to be empty.
|
||||
inspect::ProbeKind::Root { result }
|
||||
| inspect::ProbeKind::TryNormalizeNonRigid { result } => {
|
||||
if candidates.len() == num_candidates {
|
||||
| inspect::ProbeKind::TryNormalizeNonRigid { result }
|
||||
| inspect::ProbeKind::TraitCandidate { source: _, result }
|
||||
| inspect::ProbeKind::OpaqueTypeStorageLookup { result } => {
|
||||
// We only add a candidate if `shallow_certainty` was set, which means
|
||||
// that we ended up calling `evaluate_added_goals_and_make_canonical_response`.
|
||||
if let Some(shallow_certainty) = shallow_certainty {
|
||||
candidates.push(InspectCandidate {
|
||||
goal: self,
|
||||
kind: probe.kind,
|
||||
nested_goals: nested_goals.clone(),
|
||||
final_state: probe.final_state,
|
||||
result,
|
||||
candidate_certainty,
|
||||
})
|
||||
shallow_certainty,
|
||||
});
|
||||
}
|
||||
}
|
||||
inspect::ProbeKind::MiscCandidate { name: _, result }
|
||||
| inspect::ProbeKind::TraitCandidate { source: _, result } => {
|
||||
candidates.push(InspectCandidate {
|
||||
goal: self,
|
||||
kind: probe.kind,
|
||||
nested_goals: nested_goals.clone(),
|
||||
final_state: probe.final_state,
|
||||
result,
|
||||
candidate_certainty,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8,11 +8,10 @@ use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::LangItem;
|
||||
use rustc_infer::traits::query::NoSolution;
|
||||
use rustc_infer::traits::solve::inspect::ProbeKind;
|
||||
use rustc_infer::traits::solve::MaybeCause;
|
||||
use rustc_infer::traits::specialization_graph::LeafDef;
|
||||
use rustc_infer::traits::Reveal;
|
||||
use rustc_middle::traits::solve::{
|
||||
CandidateSource, CanonicalResponse, Certainty, Goal, QueryResult,
|
||||
};
|
||||
use rustc_middle::traits::solve::{CandidateSource, Certainty, Goal, QueryResult};
|
||||
use rustc_middle::traits::BuiltinImplSource;
|
||||
use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
|
||||
use rustc_middle::ty::NormalizesTo;
|
||||
@ -119,14 +118,15 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
||||
|
||||
fn probe_and_match_goal_against_assumption(
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
source: CandidateSource,
|
||||
goal: Goal<'tcx, Self>,
|
||||
assumption: ty::Clause<'tcx>,
|
||||
then: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> QueryResult<'tcx>,
|
||||
) -> QueryResult<'tcx> {
|
||||
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||
if let Some(projection_pred) = assumption.as_projection_clause() {
|
||||
if projection_pred.projection_def_id() == goal.predicate.def_id() {
|
||||
let tcx = ecx.tcx();
|
||||
ecx.probe_misc_candidate("assumption").enter(|ecx| {
|
||||
ecx.probe_trait_candidate(source).enter(|ecx| {
|
||||
let assumption_projection_pred =
|
||||
ecx.instantiate_binder_with_infer(projection_pred);
|
||||
ecx.eq(
|
||||
@ -300,14 +300,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
||||
fn consider_error_guaranteed_candidate(
|
||||
_ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
_guar: ErrorGuaranteed,
|
||||
) -> QueryResult<'tcx> {
|
||||
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||
Err(NoSolution)
|
||||
}
|
||||
|
||||
fn consider_auto_trait_candidate(
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> QueryResult<'tcx> {
|
||||
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||
ecx.tcx().dcx().span_delayed_bug(
|
||||
ecx.tcx().def_span(goal.predicate.def_id()),
|
||||
"associated types not allowed on auto traits",
|
||||
@ -318,35 +318,35 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
||||
fn consider_trait_alias_candidate(
|
||||
_ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> QueryResult<'tcx> {
|
||||
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||
bug!("trait aliases do not have associated types: {:?}", goal);
|
||||
}
|
||||
|
||||
fn consider_builtin_sized_candidate(
|
||||
_ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> QueryResult<'tcx> {
|
||||
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||
bug!("`Sized` does not have an associated type: {:?}", goal);
|
||||
}
|
||||
|
||||
fn consider_builtin_copy_clone_candidate(
|
||||
_ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> QueryResult<'tcx> {
|
||||
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||
bug!("`Copy`/`Clone` does not have an associated type: {:?}", goal);
|
||||
}
|
||||
|
||||
fn consider_builtin_pointer_like_candidate(
|
||||
_ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> QueryResult<'tcx> {
|
||||
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||
bug!("`PointerLike` does not have an associated type: {:?}", goal);
|
||||
}
|
||||
|
||||
fn consider_builtin_fn_ptr_trait_candidate(
|
||||
_ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> QueryResult<'tcx> {
|
||||
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||
bug!("`FnPtr` does not have an associated type: {:?}", goal);
|
||||
}
|
||||
|
||||
@ -354,7 +354,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
goal_kind: ty::ClosureKind,
|
||||
) -> QueryResult<'tcx> {
|
||||
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||
let tcx = ecx.tcx();
|
||||
let tupled_inputs_and_output =
|
||||
match structural_traits::extract_tupled_inputs_and_output_from_callable(
|
||||
@ -364,8 +364,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
||||
)? {
|
||||
Some(tupled_inputs_and_output) => tupled_inputs_and_output,
|
||||
None => {
|
||||
return ecx
|
||||
.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS);
|
||||
return ecx.forced_ambiguity(MaybeCause::Ambiguity);
|
||||
}
|
||||
};
|
||||
let output_is_sized_pred = tupled_inputs_and_output.map_bound(|(_, output)| {
|
||||
@ -385,14 +384,20 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
||||
|
||||
// A built-in `Fn` impl only holds if the output is sized.
|
||||
// (FIXME: technically we only need to check this if the type is a fn ptr...)
|
||||
Self::consider_implied_clause(ecx, goal, pred, [goal.with(tcx, output_is_sized_pred)])
|
||||
Self::probe_and_consider_implied_clause(
|
||||
ecx,
|
||||
CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
|
||||
goal,
|
||||
pred,
|
||||
[goal.with(tcx, output_is_sized_pred)],
|
||||
)
|
||||
}
|
||||
|
||||
fn consider_builtin_async_fn_trait_candidates(
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
goal_kind: ty::ClosureKind,
|
||||
) -> QueryResult<'tcx> {
|
||||
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||
let tcx = ecx.tcx();
|
||||
|
||||
let env_region = match goal_kind {
|
||||
@ -461,8 +466,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
||||
|
||||
// A built-in `AsyncFn` impl only holds if the output is sized.
|
||||
// (FIXME: technically we only need to check this if the type is a fn ptr...)
|
||||
Self::consider_implied_clause(
|
||||
Self::probe_and_consider_implied_clause(
|
||||
ecx,
|
||||
CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
|
||||
goal,
|
||||
pred,
|
||||
[goal.with(tcx, output_is_sized_pred)]
|
||||
@ -474,7 +480,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
||||
fn consider_builtin_async_fn_kind_helper_candidate(
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> QueryResult<'tcx> {
|
||||
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||
let [
|
||||
closure_fn_kind_ty,
|
||||
goal_kind_ty,
|
||||
@ -489,7 +495,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
||||
|
||||
// Bail if the upvars haven't been constrained.
|
||||
if tupled_upvars_ty.expect_ty().is_ty_var() {
|
||||
return ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS);
|
||||
return ecx.forced_ambiguity(MaybeCause::Ambiguity);
|
||||
}
|
||||
|
||||
let Some(closure_kind) = closure_fn_kind_ty.expect_ty().to_opt_closure_kind() else {
|
||||
@ -512,25 +518,27 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
||||
borrow_region.expect_region(),
|
||||
);
|
||||
|
||||
ecx.instantiate_normalizes_to_term(goal, upvars_ty.into());
|
||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
|
||||
ecx.instantiate_normalizes_to_term(goal, upvars_ty.into());
|
||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
})
|
||||
}
|
||||
|
||||
fn consider_builtin_tuple_candidate(
|
||||
_ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> QueryResult<'tcx> {
|
||||
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||
bug!("`Tuple` does not have an associated type: {:?}", goal);
|
||||
}
|
||||
|
||||
fn consider_builtin_pointee_candidate(
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> QueryResult<'tcx> {
|
||||
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||
let tcx = ecx.tcx();
|
||||
let metadata_def_id = tcx.require_lang_item(LangItem::Metadata, None);
|
||||
assert_eq!(metadata_def_id, goal.predicate.def_id());
|
||||
ecx.probe_misc_candidate("builtin pointee").enter(|ecx| {
|
||||
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
|
||||
let metadata_ty = match goal.predicate.self_ty().kind() {
|
||||
ty::Bool
|
||||
| ty::Char
|
||||
@ -609,7 +617,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
||||
fn consider_builtin_future_candidate(
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> QueryResult<'tcx> {
|
||||
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||
let self_ty = goal.predicate.self_ty();
|
||||
let ty::Coroutine(def_id, args) = *self_ty.kind() else {
|
||||
return Err(NoSolution);
|
||||
@ -623,8 +631,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
||||
|
||||
let term = args.as_coroutine().return_ty().into();
|
||||
|
||||
Self::consider_implied_clause(
|
||||
Self::probe_and_consider_implied_clause(
|
||||
ecx,
|
||||
CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
|
||||
goal,
|
||||
ty::ProjectionPredicate {
|
||||
projection_ty: ty::AliasTy::new(ecx.tcx(), goal.predicate.def_id(), [self_ty]),
|
||||
@ -640,7 +649,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
||||
fn consider_builtin_iterator_candidate(
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> QueryResult<'tcx> {
|
||||
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||
let self_ty = goal.predicate.self_ty();
|
||||
let ty::Coroutine(def_id, args) = *self_ty.kind() else {
|
||||
return Err(NoSolution);
|
||||
@ -654,8 +663,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
||||
|
||||
let term = args.as_coroutine().yield_ty().into();
|
||||
|
||||
Self::consider_implied_clause(
|
||||
Self::probe_and_consider_implied_clause(
|
||||
ecx,
|
||||
CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
|
||||
goal,
|
||||
ty::ProjectionPredicate {
|
||||
projection_ty: ty::AliasTy::new(ecx.tcx(), goal.predicate.def_id(), [self_ty]),
|
||||
@ -671,14 +681,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
||||
fn consider_builtin_fused_iterator_candidate(
|
||||
_ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> QueryResult<'tcx> {
|
||||
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||
bug!("`FusedIterator` does not have an associated type: {:?}", goal);
|
||||
}
|
||||
|
||||
fn consider_builtin_async_iterator_candidate(
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> QueryResult<'tcx> {
|
||||
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||
let self_ty = goal.predicate.self_ty();
|
||||
let ty::Coroutine(def_id, args) = *self_ty.kind() else {
|
||||
return Err(NoSolution);
|
||||
@ -690,7 +700,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
||||
return Err(NoSolution);
|
||||
}
|
||||
|
||||
ecx.probe_misc_candidate("builtin AsyncIterator kind").enter(|ecx| {
|
||||
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
|
||||
let expected_ty = ecx.next_ty_infer();
|
||||
// Take `AsyncIterator<Item = I>` and turn it into the corresponding
|
||||
// coroutine yield ty `Poll<Option<I>>`.
|
||||
@ -714,7 +724,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
||||
fn consider_builtin_coroutine_candidate(
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> QueryResult<'tcx> {
|
||||
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||
let self_ty = goal.predicate.self_ty();
|
||||
let ty::Coroutine(def_id, args) = *self_ty.kind() else {
|
||||
return Err(NoSolution);
|
||||
@ -737,8 +747,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
||||
bug!("unexpected associated item `<{self_ty} as Coroutine>::{name}`")
|
||||
};
|
||||
|
||||
Self::consider_implied_clause(
|
||||
Self::probe_and_consider_implied_clause(
|
||||
ecx,
|
||||
CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
|
||||
goal,
|
||||
ty::ProjectionPredicate {
|
||||
projection_ty: ty::AliasTy::new(
|
||||
@ -758,14 +769,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
||||
fn consider_structural_builtin_unsize_candidates(
|
||||
_ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> Vec<(CanonicalResponse<'tcx>, BuiltinImplSource)> {
|
||||
) -> Vec<Candidate<'tcx>> {
|
||||
bug!("`Unsize` does not have an associated type: {:?}", goal);
|
||||
}
|
||||
|
||||
fn consider_builtin_discriminant_kind_candidate(
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> QueryResult<'tcx> {
|
||||
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||
let self_ty = goal.predicate.self_ty();
|
||||
let discriminant_ty = match *self_ty.kind() {
|
||||
ty::Bool
|
||||
@ -808,7 +819,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
||||
),
|
||||
};
|
||||
|
||||
ecx.probe_misc_candidate("builtin discriminant kind").enter(|ecx| {
|
||||
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
|
||||
ecx.instantiate_normalizes_to_term(goal, discriminant_ty.into());
|
||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
})
|
||||
@ -817,7 +828,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
||||
fn consider_builtin_async_destruct_candidate(
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> QueryResult<'tcx> {
|
||||
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||
let self_ty = goal.predicate.self_ty();
|
||||
let async_destructor_ty = match *self_ty.kind() {
|
||||
ty::Bool
|
||||
@ -860,7 +871,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
||||
),
|
||||
};
|
||||
|
||||
ecx.probe_misc_candidate("builtin async destruct").enter(|ecx| {
|
||||
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
|
||||
ecx.eq(goal.param_env, goal.predicate.term, async_destructor_ty.into())
|
||||
.expect("expected goal term to be fully unconstrained");
|
||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
@ -870,14 +881,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
||||
fn consider_builtin_destruct_candidate(
|
||||
_ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> QueryResult<'tcx> {
|
||||
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||
bug!("`Destruct` does not have an associated type: {:?}", goal);
|
||||
}
|
||||
|
||||
fn consider_builtin_transmute_candidate(
|
||||
_ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> QueryResult<'tcx> {
|
||||
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||
bug!("`BikeshedIntrinsicFrom` does not have an associated type: {:?}", goal)
|
||||
}
|
||||
}
|
||||
|
@ -9,10 +9,9 @@ use rustc_data_structures::fx::FxIndexSet;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::{LangItem, Movability};
|
||||
use rustc_infer::traits::query::NoSolution;
|
||||
use rustc_infer::traits::solve::MaybeCause;
|
||||
use rustc_middle::traits::solve::inspect::ProbeKind;
|
||||
use rustc_middle::traits::solve::{
|
||||
CandidateSource, CanonicalResponse, Certainty, Goal, QueryResult,
|
||||
};
|
||||
use rustc_middle::traits::solve::{CandidateSource, Certainty, Goal, QueryResult};
|
||||
use rustc_middle::traits::{BuiltinImplSource, Reveal};
|
||||
use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
|
||||
use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt};
|
||||
@ -94,21 +93,24 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||
fn consider_error_guaranteed_candidate(
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
_guar: ErrorGuaranteed,
|
||||
) -> QueryResult<'tcx> {
|
||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||
// FIXME: don't need to enter a probe here.
|
||||
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
|
||||
.enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
|
||||
}
|
||||
|
||||
fn probe_and_match_goal_against_assumption(
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
source: CandidateSource,
|
||||
goal: Goal<'tcx, Self>,
|
||||
assumption: ty::Clause<'tcx>,
|
||||
then: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> QueryResult<'tcx>,
|
||||
) -> QueryResult<'tcx> {
|
||||
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||
if let Some(trait_clause) = assumption.as_trait_clause() {
|
||||
if trait_clause.def_id() == goal.predicate.def_id()
|
||||
&& trait_clause.polarity() == goal.predicate.polarity
|
||||
{
|
||||
ecx.probe_misc_candidate("assumption").enter(|ecx| {
|
||||
ecx.probe_trait_candidate(source).enter(|ecx| {
|
||||
let assumption_trait_pred = ecx.instantiate_binder_with_infer(trait_clause);
|
||||
ecx.eq(
|
||||
goal.param_env,
|
||||
@ -128,7 +130,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||
fn consider_auto_trait_candidate(
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> QueryResult<'tcx> {
|
||||
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
|
||||
return Err(NoSolution);
|
||||
}
|
||||
@ -162,6 +164,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||
}
|
||||
|
||||
ecx.probe_and_evaluate_goal_for_constituent_tys(
|
||||
CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
|
||||
goal,
|
||||
structural_traits::instantiate_constituent_tys_for_auto_trait,
|
||||
)
|
||||
@ -170,14 +173,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||
fn consider_trait_alias_candidate(
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> QueryResult<'tcx> {
|
||||
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
|
||||
return Err(NoSolution);
|
||||
}
|
||||
|
||||
let tcx = ecx.tcx();
|
||||
|
||||
ecx.probe_misc_candidate("trait alias").enter(|ecx| {
|
||||
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
|
||||
let nested_obligations = tcx
|
||||
.predicates_of(goal.predicate.def_id())
|
||||
.instantiate(tcx, goal.predicate.trait_ref.args);
|
||||
@ -193,12 +196,13 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||
fn consider_builtin_sized_candidate(
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> QueryResult<'tcx> {
|
||||
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
|
||||
return Err(NoSolution);
|
||||
}
|
||||
|
||||
ecx.probe_and_evaluate_goal_for_constituent_tys(
|
||||
CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
|
||||
goal,
|
||||
structural_traits::instantiate_constituent_tys_for_sized_trait,
|
||||
)
|
||||
@ -207,12 +211,13 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||
fn consider_builtin_copy_clone_candidate(
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> QueryResult<'tcx> {
|
||||
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
|
||||
return Err(NoSolution);
|
||||
}
|
||||
|
||||
ecx.probe_and_evaluate_goal_for_constituent_tys(
|
||||
CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
|
||||
goal,
|
||||
structural_traits::instantiate_constituent_tys_for_copy_clone_trait,
|
||||
)
|
||||
@ -221,7 +226,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||
fn consider_builtin_pointer_like_candidate(
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> QueryResult<'tcx> {
|
||||
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
|
||||
return Err(NoSolution);
|
||||
}
|
||||
@ -234,14 +239,15 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||
let key = tcx.erase_regions(goal.param_env.and(goal.predicate.self_ty()));
|
||||
// But if there are inference variables, we have to wait until it's resolved.
|
||||
if key.has_non_region_infer() {
|
||||
return ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS);
|
||||
return ecx.forced_ambiguity(MaybeCause::Ambiguity);
|
||||
}
|
||||
|
||||
if let Ok(layout) = tcx.layout_of(key)
|
||||
&& layout.layout.is_pointer_like(&tcx.data_layout)
|
||||
{
|
||||
// FIXME: We could make this faster by making a no-constraints response
|
||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
|
||||
.enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
|
||||
} else {
|
||||
Err(NoSolution)
|
||||
}
|
||||
@ -250,13 +256,15 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||
fn consider_builtin_fn_ptr_trait_candidate(
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> QueryResult<'tcx> {
|
||||
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||
let self_ty = goal.predicate.self_ty();
|
||||
match goal.predicate.polarity {
|
||||
// impl FnPtr for FnPtr {}
|
||||
ty::PredicatePolarity::Positive => {
|
||||
if self_ty.is_fn_ptr() {
|
||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
|
||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
})
|
||||
} else {
|
||||
Err(NoSolution)
|
||||
}
|
||||
@ -266,7 +274,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||
// If a type is rigid and not a fn ptr, then we know for certain
|
||||
// that it does *not* implement `FnPtr`.
|
||||
if !self_ty.is_fn_ptr() && self_ty.is_known_rigid() {
|
||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
|
||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
})
|
||||
} else {
|
||||
Err(NoSolution)
|
||||
}
|
||||
@ -278,7 +288,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
goal_kind: ty::ClosureKind,
|
||||
) -> QueryResult<'tcx> {
|
||||
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
|
||||
return Err(NoSolution);
|
||||
}
|
||||
@ -292,8 +302,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||
)? {
|
||||
Some(a) => a,
|
||||
None => {
|
||||
return ecx
|
||||
.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS);
|
||||
return ecx.forced_ambiguity(MaybeCause::Ambiguity);
|
||||
}
|
||||
};
|
||||
let output_is_sized_pred = tupled_inputs_and_output.map_bound(|(_, output)| {
|
||||
@ -307,14 +316,20 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||
.to_predicate(tcx);
|
||||
// A built-in `Fn` impl only holds if the output is sized.
|
||||
// (FIXME: technically we only need to check this if the type is a fn ptr...)
|
||||
Self::consider_implied_clause(ecx, goal, pred, [goal.with(tcx, output_is_sized_pred)])
|
||||
Self::probe_and_consider_implied_clause(
|
||||
ecx,
|
||||
CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
|
||||
goal,
|
||||
pred,
|
||||
[goal.with(tcx, output_is_sized_pred)],
|
||||
)
|
||||
}
|
||||
|
||||
fn consider_builtin_async_fn_trait_candidates(
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
goal_kind: ty::ClosureKind,
|
||||
) -> QueryResult<'tcx> {
|
||||
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
|
||||
return Err(NoSolution);
|
||||
}
|
||||
@ -345,8 +360,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||
.to_predicate(tcx);
|
||||
// A built-in `AsyncFn` impl only holds if the output is sized.
|
||||
// (FIXME: technically we only need to check this if the type is a fn ptr...)
|
||||
Self::consider_implied_clause(
|
||||
Self::probe_and_consider_implied_clause(
|
||||
ecx,
|
||||
CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
|
||||
goal,
|
||||
pred,
|
||||
[goal.with(tcx, output_is_sized_pred)]
|
||||
@ -358,7 +374,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||
fn consider_builtin_async_fn_kind_helper_candidate(
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> QueryResult<'tcx> {
|
||||
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||
let [closure_fn_kind_ty, goal_kind_ty] = **goal.predicate.trait_ref.args else {
|
||||
bug!();
|
||||
};
|
||||
@ -369,7 +385,8 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||
};
|
||||
let goal_kind = goal_kind_ty.expect_ty().to_opt_closure_kind().unwrap();
|
||||
if closure_kind.extends(goal_kind) {
|
||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
|
||||
.enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
|
||||
} else {
|
||||
Err(NoSolution)
|
||||
}
|
||||
@ -384,13 +401,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||
fn consider_builtin_tuple_candidate(
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> QueryResult<'tcx> {
|
||||
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
|
||||
return Err(NoSolution);
|
||||
}
|
||||
|
||||
if let ty::Tuple(..) = goal.predicate.self_ty().kind() {
|
||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
|
||||
.enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
|
||||
} else {
|
||||
Err(NoSolution)
|
||||
}
|
||||
@ -399,18 +417,19 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||
fn consider_builtin_pointee_candidate(
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> QueryResult<'tcx> {
|
||||
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
|
||||
return Err(NoSolution);
|
||||
}
|
||||
|
||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
|
||||
.enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
|
||||
}
|
||||
|
||||
fn consider_builtin_future_candidate(
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> QueryResult<'tcx> {
|
||||
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
|
||||
return Err(NoSolution);
|
||||
}
|
||||
@ -428,13 +447,15 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||
// Async coroutine unconditionally implement `Future`
|
||||
// Technically, we need to check that the future output type is Sized,
|
||||
// but that's already proven by the coroutine being WF.
|
||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
// FIXME: use `consider_implied`
|
||||
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
|
||||
.enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
|
||||
}
|
||||
|
||||
fn consider_builtin_iterator_candidate(
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> QueryResult<'tcx> {
|
||||
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
|
||||
return Err(NoSolution);
|
||||
}
|
||||
@ -452,13 +473,15 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||
// Gen coroutines unconditionally implement `Iterator`
|
||||
// Technically, we need to check that the iterator output type is Sized,
|
||||
// but that's already proven by the coroutines being WF.
|
||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
// FIXME: use `consider_implied`
|
||||
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
|
||||
.enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
|
||||
}
|
||||
|
||||
fn consider_builtin_fused_iterator_candidate(
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> QueryResult<'tcx> {
|
||||
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
|
||||
return Err(NoSolution);
|
||||
}
|
||||
@ -474,13 +497,15 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||
}
|
||||
|
||||
// Gen coroutines unconditionally implement `FusedIterator`
|
||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
// FIXME: use `consider_implied`
|
||||
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
|
||||
.enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
|
||||
}
|
||||
|
||||
fn consider_builtin_async_iterator_candidate(
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> QueryResult<'tcx> {
|
||||
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
|
||||
return Err(NoSolution);
|
||||
}
|
||||
@ -498,13 +523,15 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||
// Gen coroutines unconditionally implement `Iterator`
|
||||
// Technically, we need to check that the iterator output type is Sized,
|
||||
// but that's already proven by the coroutines being WF.
|
||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
// FIXME: use `consider_implied`
|
||||
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
|
||||
.enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
|
||||
}
|
||||
|
||||
fn consider_builtin_coroutine_candidate(
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> QueryResult<'tcx> {
|
||||
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
|
||||
return Err(NoSolution);
|
||||
}
|
||||
@ -521,8 +548,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||
}
|
||||
|
||||
let coroutine = args.as_coroutine();
|
||||
Self::consider_implied_clause(
|
||||
Self::probe_and_consider_implied_clause(
|
||||
ecx,
|
||||
CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
|
||||
goal,
|
||||
ty::TraitRef::new(tcx, goal.predicate.def_id(), [self_ty, coroutine.resume_ty()])
|
||||
.to_predicate(tcx),
|
||||
@ -535,31 +563,33 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||
fn consider_builtin_discriminant_kind_candidate(
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> QueryResult<'tcx> {
|
||||
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
|
||||
return Err(NoSolution);
|
||||
}
|
||||
|
||||
// `DiscriminantKind` is automatically implemented for every type.
|
||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
|
||||
.enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
|
||||
}
|
||||
|
||||
fn consider_builtin_async_destruct_candidate(
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> QueryResult<'tcx> {
|
||||
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
|
||||
return Err(NoSolution);
|
||||
}
|
||||
|
||||
// `AsyncDestruct` is automatically implemented for every type.
|
||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
|
||||
.enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
|
||||
}
|
||||
|
||||
fn consider_builtin_destruct_candidate(
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> QueryResult<'tcx> {
|
||||
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
|
||||
return Err(NoSolution);
|
||||
}
|
||||
@ -568,13 +598,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||
|
||||
// `Destruct` is automatically implemented for every type in
|
||||
// non-const environments.
|
||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
|
||||
.enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
|
||||
}
|
||||
|
||||
fn consider_builtin_transmute_candidate(
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> QueryResult<'tcx> {
|
||||
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
|
||||
return Err(NoSolution);
|
||||
}
|
||||
@ -594,11 +625,15 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||
return Err(NoSolution);
|
||||
};
|
||||
|
||||
let certainty = ecx.is_transmutable(
|
||||
rustc_transmute::Types { dst: args.type_at(0), src: args.type_at(1) },
|
||||
assume,
|
||||
)?;
|
||||
ecx.evaluate_added_goals_and_make_canonical_response(certainty)
|
||||
// FIXME: This actually should destructure the `Result` we get from transmutability and
|
||||
// register candiates. We probably need to register >1 since we may have an OR of ANDs.
|
||||
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
|
||||
let certainty = ecx.is_transmutable(
|
||||
rustc_transmute::Types { dst: args.type_at(0), src: args.type_at(1) },
|
||||
assume,
|
||||
)?;
|
||||
ecx.evaluate_added_goals_and_make_canonical_response(certainty)
|
||||
})
|
||||
}
|
||||
|
||||
/// ```ignore (builtin impl example)
|
||||
@ -611,20 +646,13 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||
fn consider_structural_builtin_unsize_candidates(
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> Vec<(CanonicalResponse<'tcx>, BuiltinImplSource)> {
|
||||
) -> Vec<Candidate<'tcx>> {
|
||||
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
|
||||
return vec![];
|
||||
}
|
||||
|
||||
let misc_candidate = |ecx: &mut EvalCtxt<'_, 'tcx>, certainty| {
|
||||
(
|
||||
ecx.evaluate_added_goals_and_make_canonical_response(certainty).unwrap(),
|
||||
BuiltinImplSource::Misc,
|
||||
)
|
||||
};
|
||||
|
||||
let result_to_single = |result, source| match result {
|
||||
Ok(resp) => vec![(resp, source)],
|
||||
let result_to_single = |result| match result {
|
||||
Ok(resp) => vec![resp],
|
||||
Err(NoSolution) => vec![],
|
||||
};
|
||||
|
||||
@ -642,7 +670,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||
let goal = goal.with(ecx.tcx(), (a_ty, b_ty));
|
||||
match (a_ty.kind(), b_ty.kind()) {
|
||||
(ty::Infer(ty::TyVar(..)), ..) => bug!("unexpected infer {a_ty:?} {b_ty:?}"),
|
||||
(_, ty::Infer(ty::TyVar(..))) => vec![misc_candidate(ecx, Certainty::AMBIGUOUS)],
|
||||
|
||||
(_, ty::Infer(ty::TyVar(..))) => {
|
||||
result_to_single(ecx.forced_ambiguity(MaybeCause::Ambiguity))
|
||||
}
|
||||
|
||||
// Trait upcasting, or `dyn Trait + Auto + 'a` -> `dyn Trait + 'b`.
|
||||
(
|
||||
@ -655,14 +686,12 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||
// `T` -> `dyn Trait` unsizing.
|
||||
(_, &ty::Dynamic(b_region, b_data, ty::Dyn)) => result_to_single(
|
||||
ecx.consider_builtin_unsize_to_dyn_candidate(goal, b_region, b_data),
|
||||
BuiltinImplSource::Misc,
|
||||
),
|
||||
|
||||
// `[T; N]` -> `[T]` unsizing
|
||||
(&ty::Array(a_elem_ty, ..), &ty::Slice(b_elem_ty)) => result_to_single(
|
||||
ecx.consider_builtin_array_unsize(goal, a_elem_ty, b_elem_ty),
|
||||
BuiltinImplSource::Misc,
|
||||
),
|
||||
(&ty::Array(a_elem_ty, ..), &ty::Slice(b_elem_ty)) => {
|
||||
result_to_single(ecx.consider_builtin_array_unsize(goal, a_elem_ty, b_elem_ty))
|
||||
}
|
||||
|
||||
// `Struct<T>` -> `Struct<U>` where `T: Unsize<U>`
|
||||
(&ty::Adt(a_def, a_args), &ty::Adt(b_def, b_args))
|
||||
@ -670,7 +699,6 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||
{
|
||||
result_to_single(
|
||||
ecx.consider_builtin_struct_unsize(goal, a_def, a_args, b_args),
|
||||
BuiltinImplSource::Misc,
|
||||
)
|
||||
}
|
||||
|
||||
@ -678,10 +706,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||
(&ty::Tuple(a_tys), &ty::Tuple(b_tys))
|
||||
if a_tys.len() == b_tys.len() && !a_tys.is_empty() =>
|
||||
{
|
||||
result_to_single(
|
||||
ecx.consider_builtin_tuple_unsize(goal, a_tys, b_tys),
|
||||
BuiltinImplSource::TupleUnsizing,
|
||||
)
|
||||
result_to_single(ecx.consider_builtin_tuple_unsize(goal, a_tys, b_tys))
|
||||
}
|
||||
|
||||
_ => vec![],
|
||||
@ -707,7 +732,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||
a_region: ty::Region<'tcx>,
|
||||
b_data: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
|
||||
b_region: ty::Region<'tcx>,
|
||||
) -> Vec<(CanonicalResponse<'tcx>, BuiltinImplSource)> {
|
||||
) -> Vec<Candidate<'tcx>> {
|
||||
let tcx = self.tcx();
|
||||
let Goal { predicate: (a_ty, _b_ty), .. } = goal;
|
||||
|
||||
@ -715,35 +740,32 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||
// If the principal def ids match (or are both none), then we're not doing
|
||||
// trait upcasting. We're just removing auto traits (or shortening the lifetime).
|
||||
if a_data.principal_def_id() == b_data.principal_def_id() {
|
||||
if let Ok(resp) = self.consider_builtin_upcast_to_principal(
|
||||
responses.extend(self.consider_builtin_upcast_to_principal(
|
||||
goal,
|
||||
CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
|
||||
a_data,
|
||||
a_region,
|
||||
b_data,
|
||||
b_region,
|
||||
a_data.principal(),
|
||||
) {
|
||||
responses.push((resp, BuiltinImplSource::Misc));
|
||||
}
|
||||
));
|
||||
} else if let Some(a_principal) = a_data.principal() {
|
||||
self.walk_vtable(
|
||||
a_principal.with_self_ty(tcx, a_ty),
|
||||
|ecx, new_a_principal, _, vtable_vptr_slot| {
|
||||
if let Ok(resp) = ecx.probe_misc_candidate("dyn upcast").enter(|ecx| {
|
||||
ecx.consider_builtin_upcast_to_principal(
|
||||
goal,
|
||||
a_data,
|
||||
a_region,
|
||||
b_data,
|
||||
b_region,
|
||||
Some(new_a_principal.map_bound(|trait_ref| {
|
||||
ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)
|
||||
})),
|
||||
)
|
||||
}) {
|
||||
responses
|
||||
.push((resp, BuiltinImplSource::TraitUpcasting { vtable_vptr_slot }));
|
||||
}
|
||||
responses.extend(ecx.consider_builtin_upcast_to_principal(
|
||||
goal,
|
||||
CandidateSource::BuiltinImpl(BuiltinImplSource::TraitUpcasting {
|
||||
vtable_vptr_slot,
|
||||
}),
|
||||
a_data,
|
||||
a_region,
|
||||
b_data,
|
||||
b_region,
|
||||
Some(new_a_principal.map_bound(|trait_ref| {
|
||||
ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)
|
||||
})),
|
||||
));
|
||||
},
|
||||
);
|
||||
}
|
||||
@ -756,7 +778,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||
goal: Goal<'tcx, (Ty<'tcx>, Ty<'tcx>)>,
|
||||
b_data: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
|
||||
b_region: ty::Region<'tcx>,
|
||||
) -> QueryResult<'tcx> {
|
||||
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||
let tcx = self.tcx();
|
||||
let Goal { predicate: (a_ty, _), .. } = goal;
|
||||
|
||||
@ -765,37 +787,40 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||
return Err(NoSolution);
|
||||
}
|
||||
|
||||
// Check that the type implements all of the predicates of the trait object.
|
||||
// (i.e. the principal, all of the associated types match, and any auto traits)
|
||||
self.add_goals(
|
||||
GoalSource::ImplWhereBound,
|
||||
b_data.iter().map(|pred| goal.with(tcx, pred.with_self_ty(tcx, a_ty))),
|
||||
);
|
||||
|
||||
// The type must be `Sized` to be unsized.
|
||||
if let Some(sized_def_id) = tcx.lang_items().sized_trait() {
|
||||
self.add_goal(
|
||||
self.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
|
||||
// Check that the type implements all of the predicates of the trait object.
|
||||
// (i.e. the principal, all of the associated types match, and any auto traits)
|
||||
ecx.add_goals(
|
||||
GoalSource::ImplWhereBound,
|
||||
goal.with(tcx, ty::TraitRef::new(tcx, sized_def_id, [a_ty])),
|
||||
b_data.iter().map(|pred| goal.with(tcx, pred.with_self_ty(tcx, a_ty))),
|
||||
);
|
||||
} else {
|
||||
return Err(NoSolution);
|
||||
}
|
||||
|
||||
// The type must outlive the lifetime of the `dyn` we're unsizing into.
|
||||
self.add_goal(GoalSource::Misc, goal.with(tcx, ty::OutlivesPredicate(a_ty, b_region)));
|
||||
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
// The type must be `Sized` to be unsized.
|
||||
if let Some(sized_def_id) = tcx.lang_items().sized_trait() {
|
||||
ecx.add_goal(
|
||||
GoalSource::ImplWhereBound,
|
||||
goal.with(tcx, ty::TraitRef::new(tcx, sized_def_id, [a_ty])),
|
||||
);
|
||||
} else {
|
||||
return Err(NoSolution);
|
||||
}
|
||||
|
||||
// The type must outlive the lifetime of the `dyn` we're unsizing into.
|
||||
ecx.add_goal(GoalSource::Misc, goal.with(tcx, ty::OutlivesPredicate(a_ty, b_region)));
|
||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
})
|
||||
}
|
||||
|
||||
fn consider_builtin_upcast_to_principal(
|
||||
&mut self,
|
||||
goal: Goal<'tcx, (Ty<'tcx>, Ty<'tcx>)>,
|
||||
source: CandidateSource,
|
||||
a_data: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
|
||||
a_region: ty::Region<'tcx>,
|
||||
b_data: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
|
||||
b_region: ty::Region<'tcx>,
|
||||
upcast_principal: Option<ty::PolyExistentialTraitRef<'tcx>>,
|
||||
) -> QueryResult<'tcx> {
|
||||
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||
let param_env = goal.param_env;
|
||||
|
||||
// We may upcast to auto traits that are either explicitly listed in
|
||||
@ -814,7 +839,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||
// having any inference side-effects. We process obligations because
|
||||
// unification may initially succeed due to deferred projection equality.
|
||||
let projection_may_match =
|
||||
|ecx: &mut Self,
|
||||
|ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
source_projection: ty::PolyExistentialProjection<'tcx>,
|
||||
target_projection: ty::PolyExistentialProjection<'tcx>| {
|
||||
source_projection.item_def_id() == target_projection.item_def_id()
|
||||
@ -828,54 +853,60 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||
.is_ok()
|
||||
};
|
||||
|
||||
for bound in b_data {
|
||||
match bound.skip_binder() {
|
||||
// Check that a's supertrait (upcast_principal) is compatible
|
||||
// with the target (b_ty).
|
||||
ty::ExistentialPredicate::Trait(target_principal) => {
|
||||
self.eq(param_env, upcast_principal.unwrap(), bound.rebind(target_principal))?;
|
||||
}
|
||||
// Check that b_ty's projection is satisfied by exactly one of
|
||||
// a_ty's projections. First, we look through the list to see if
|
||||
// any match. If not, error. Then, if *more* than one matches, we
|
||||
// return ambiguity. Otherwise, if exactly one matches, equate
|
||||
// it with b_ty's projection.
|
||||
ty::ExistentialPredicate::Projection(target_projection) => {
|
||||
let target_projection = bound.rebind(target_projection);
|
||||
let mut matching_projections =
|
||||
a_data.projection_bounds().filter(|source_projection| {
|
||||
projection_may_match(self, *source_projection, target_projection)
|
||||
});
|
||||
let Some(source_projection) = matching_projections.next() else {
|
||||
return Err(NoSolution);
|
||||
};
|
||||
if matching_projections.next().is_some() {
|
||||
return self.evaluate_added_goals_and_make_canonical_response(
|
||||
Certainty::AMBIGUOUS,
|
||||
);
|
||||
self.probe_trait_candidate(source).enter(|ecx| {
|
||||
for bound in b_data {
|
||||
match bound.skip_binder() {
|
||||
// Check that a's supertrait (upcast_principal) is compatible
|
||||
// with the target (b_ty).
|
||||
ty::ExistentialPredicate::Trait(target_principal) => {
|
||||
ecx.eq(
|
||||
param_env,
|
||||
upcast_principal.unwrap(),
|
||||
bound.rebind(target_principal),
|
||||
)?;
|
||||
}
|
||||
self.eq(param_env, source_projection, target_projection)?;
|
||||
}
|
||||
// Check that b_ty's auto traits are present in a_ty's bounds.
|
||||
ty::ExistentialPredicate::AutoTrait(def_id) => {
|
||||
if !a_auto_traits.contains(&def_id) {
|
||||
return Err(NoSolution);
|
||||
// Check that b_ty's projection is satisfied by exactly one of
|
||||
// a_ty's projections. First, we look through the list to see if
|
||||
// any match. If not, error. Then, if *more* than one matches, we
|
||||
// return ambiguity. Otherwise, if exactly one matches, equate
|
||||
// it with b_ty's projection.
|
||||
ty::ExistentialPredicate::Projection(target_projection) => {
|
||||
let target_projection = bound.rebind(target_projection);
|
||||
let mut matching_projections =
|
||||
a_data.projection_bounds().filter(|source_projection| {
|
||||
projection_may_match(ecx, *source_projection, target_projection)
|
||||
});
|
||||
let Some(source_projection) = matching_projections.next() else {
|
||||
return Err(NoSolution);
|
||||
};
|
||||
if matching_projections.next().is_some() {
|
||||
return ecx.evaluate_added_goals_and_make_canonical_response(
|
||||
Certainty::AMBIGUOUS,
|
||||
);
|
||||
}
|
||||
ecx.eq(param_env, source_projection, target_projection)?;
|
||||
}
|
||||
// Check that b_ty's auto traits are present in a_ty's bounds.
|
||||
ty::ExistentialPredicate::AutoTrait(def_id) => {
|
||||
if !a_auto_traits.contains(&def_id) {
|
||||
return Err(NoSolution);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Also require that a_ty's lifetime outlives b_ty's lifetime.
|
||||
self.add_goal(
|
||||
GoalSource::ImplWhereBound,
|
||||
Goal::new(
|
||||
self.tcx(),
|
||||
param_env,
|
||||
ty::Binder::dummy(ty::OutlivesPredicate(a_region, b_region)),
|
||||
),
|
||||
);
|
||||
// Also require that a_ty's lifetime outlives b_ty's lifetime.
|
||||
ecx.add_goal(
|
||||
GoalSource::ImplWhereBound,
|
||||
Goal::new(
|
||||
ecx.tcx(),
|
||||
param_env,
|
||||
ty::Binder::dummy(ty::OutlivesPredicate(a_region, b_region)),
|
||||
),
|
||||
);
|
||||
|
||||
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
})
|
||||
}
|
||||
|
||||
/// We have the following builtin impls for arrays:
|
||||
@ -891,9 +922,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||
goal: Goal<'tcx, (Ty<'tcx>, Ty<'tcx>)>,
|
||||
a_elem_ty: Ty<'tcx>,
|
||||
b_elem_ty: Ty<'tcx>,
|
||||
) -> QueryResult<'tcx> {
|
||||
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||
self.eq(goal.param_env, a_elem_ty, b_elem_ty)?;
|
||||
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
self.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
|
||||
.enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
|
||||
}
|
||||
|
||||
/// We generate a builtin `Unsize` impls for structs with generic parameters only
|
||||
@ -915,7 +947,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||
def: ty::AdtDef<'tcx>,
|
||||
a_args: ty::GenericArgsRef<'tcx>,
|
||||
b_args: ty::GenericArgsRef<'tcx>,
|
||||
) -> QueryResult<'tcx> {
|
||||
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||
let tcx = self.tcx();
|
||||
let Goal { predicate: (_a_ty, b_ty), .. } = goal;
|
||||
|
||||
@ -957,7 +989,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||
),
|
||||
),
|
||||
);
|
||||
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
self.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
|
||||
.enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
|
||||
}
|
||||
|
||||
/// We generate the following builtin impl for tuples of all sizes.
|
||||
@ -975,7 +1008,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||
goal: Goal<'tcx, (Ty<'tcx>, Ty<'tcx>)>,
|
||||
a_tys: &'tcx ty::List<Ty<'tcx>>,
|
||||
b_tys: &'tcx ty::List<Ty<'tcx>>,
|
||||
) -> QueryResult<'tcx> {
|
||||
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||
let tcx = self.tcx();
|
||||
let Goal { predicate: (_a_ty, b_ty), .. } = goal;
|
||||
|
||||
@ -999,7 +1032,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||
),
|
||||
),
|
||||
);
|
||||
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
self.probe_builtin_trait_candidate(BuiltinImplSource::TupleUnsizing)
|
||||
.enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
|
||||
}
|
||||
|
||||
// Return `Some` if there is an impl (built-in or user provided) that may
|
||||
@ -1009,7 +1043,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||
fn disqualify_auto_trait_candidate_due_to_possible_impl(
|
||||
&mut self,
|
||||
goal: Goal<'tcx, TraitPredicate<'tcx>>,
|
||||
) -> Option<QueryResult<'tcx>> {
|
||||
) -> Option<Result<Candidate<'tcx>, NoSolution>> {
|
||||
let self_ty = goal.predicate.self_ty();
|
||||
match *self_ty.kind() {
|
||||
// Stall int and float vars until they are resolved to a concrete
|
||||
@ -1018,7 +1052,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||
// we probably don't want to treat an `impl !AutoTrait for i32` as
|
||||
// disqualifying the built-in auto impl for `i64: AutoTrait` either.
|
||||
ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) => {
|
||||
Some(self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS))
|
||||
Some(self.forced_ambiguity(MaybeCause::Ambiguity))
|
||||
}
|
||||
|
||||
// These types cannot be structurally decomposed into constituent
|
||||
@ -1039,9 +1073,11 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||
{
|
||||
match self.tcx().coroutine_movability(def_id) {
|
||||
Movability::Static => Some(Err(NoSolution)),
|
||||
Movability::Movable => {
|
||||
Some(self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
|
||||
}
|
||||
Movability::Movable => Some(
|
||||
self.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
|
||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
}),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
@ -1106,13 +1142,14 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||
/// wrapped in one.
|
||||
fn probe_and_evaluate_goal_for_constituent_tys(
|
||||
&mut self,
|
||||
source: CandidateSource,
|
||||
goal: Goal<'tcx, TraitPredicate<'tcx>>,
|
||||
constituent_tys: impl Fn(
|
||||
&EvalCtxt<'_, 'tcx>,
|
||||
Ty<'tcx>,
|
||||
) -> Result<Vec<ty::Binder<'tcx, Ty<'tcx>>>, NoSolution>,
|
||||
) -> QueryResult<'tcx> {
|
||||
self.probe_misc_candidate("constituent tys").enter(|ecx| {
|
||||
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||
self.probe_trait_candidate(source).enter(|ecx| {
|
||||
ecx.add_goals(
|
||||
GoalSource::ImplWhereBound,
|
||||
constituent_tys(ecx, goal.predicate.self_ty())?
|
||||
|
@ -1078,9 +1078,8 @@ impl<'a, 'tcx> ProofTreeVisitor<'tcx> for AmbiguityCausesVisitor<'a, 'tcx> {
|
||||
// Add ambiguity causes for unknowable goals.
|
||||
let mut ambiguity_cause = None;
|
||||
for cand in goal.candidates() {
|
||||
// FIXME: boiiii, using string comparisions here sure is scuffed.
|
||||
if let inspect::ProbeKind::MiscCandidate {
|
||||
name: "coherence unknowable",
|
||||
if let inspect::ProbeKind::TraitCandidate {
|
||||
source: CandidateSource::CoherenceUnknowable,
|
||||
result: Ok(_),
|
||||
} = cand.kind()
|
||||
{
|
||||
|
@ -1340,8 +1340,8 @@ impl<T> SizedTypeProperties for T {}
|
||||
/// assert_eq!(mem::offset_of!(Option<&u8>, Some.0), 0);
|
||||
/// ```
|
||||
#[stable(feature = "offset_of", since = "1.77.0")]
|
||||
#[allow_internal_unstable(builtin_syntax, hint_must_use)]
|
||||
#[allow_internal_unstable(builtin_syntax)]
|
||||
pub macro offset_of($Container:ty, $($fields:expr)+ $(,)?) {
|
||||
// The `{}` is for better error messages
|
||||
crate::hint::must_use({builtin # offset_of($Container, $($fields)+)})
|
||||
{builtin # offset_of($Container, $($fields)+)}
|
||||
}
|
||||
|
@ -10,11 +10,9 @@ path = "lib.rs"
|
||||
arrayvec = { version = "0.7", default-features = false }
|
||||
askama = { version = "0.12", default-features = false, features = ["config"] }
|
||||
base64 = "0.21.7"
|
||||
byteorder = "1.5"
|
||||
itertools = "0.12"
|
||||
indexmap = "2"
|
||||
minifier = "0.3.0"
|
||||
once_cell = "1.10.0"
|
||||
regex = "1"
|
||||
rustdoc-json-types = { path = "../rustdoc-json-types" }
|
||||
serde_json = "1.0"
|
||||
|
@ -35,13 +35,13 @@ use rustc_resolve::rustdoc::may_be_doc_link;
|
||||
use rustc_span::edition::Edition;
|
||||
use rustc_span::{Span, Symbol};
|
||||
|
||||
use once_cell::sync::Lazy;
|
||||
use std::borrow::Cow;
|
||||
use std::collections::VecDeque;
|
||||
use std::fmt::Write;
|
||||
use std::iter::Peekable;
|
||||
use std::ops::{ControlFlow, Range};
|
||||
use std::str::{self, CharIndices};
|
||||
use std::sync::OnceLock;
|
||||
|
||||
use crate::clean::RenderedLink;
|
||||
use crate::doctest;
|
||||
@ -1994,7 +1994,7 @@ pub struct IdMap {
|
||||
}
|
||||
|
||||
// The map is pre-initialized and cloned each time to avoid reinitializing it repeatedly.
|
||||
static DEFAULT_ID_MAP: Lazy<FxHashMap<Cow<'static, str>, usize>> = Lazy::new(|| init_id_map());
|
||||
static DEFAULT_ID_MAP: OnceLock<FxHashMap<Cow<'static, str>, usize>> = OnceLock::new();
|
||||
|
||||
fn init_id_map() -> FxHashMap<Cow<'static, str>, usize> {
|
||||
let mut map = FxHashMap::default();
|
||||
@ -2051,7 +2051,7 @@ fn init_id_map() -> FxHashMap<Cow<'static, str>, usize> {
|
||||
|
||||
impl IdMap {
|
||||
pub fn new() -> Self {
|
||||
IdMap { map: DEFAULT_ID_MAP.clone() }
|
||||
IdMap { map: DEFAULT_ID_MAP.get_or_init(init_id_map).clone() }
|
||||
}
|
||||
|
||||
pub(crate) fn derive<S: AsRef<str> + ToString>(&mut self, candidate: S) -> String {
|
||||
|
@ -166,13 +166,12 @@ pub(crate) fn write_bitmap_to_bytes(
|
||||
containers.push(container);
|
||||
}
|
||||
// https://github.com/RoaringBitmap/RoaringFormatSpec
|
||||
use byteorder::{WriteBytesExt, LE};
|
||||
const SERIAL_COOKIE_NO_RUNCONTAINER: u32 = 12346;
|
||||
const SERIAL_COOKIE: u32 = 12347;
|
||||
const NO_OFFSET_THRESHOLD: u32 = 4;
|
||||
let size: u32 = containers.len().try_into().unwrap();
|
||||
let start_offset = if has_run {
|
||||
out.write_u32::<LE>(SERIAL_COOKIE | ((size - 1) << 16))?;
|
||||
out.write_all(&u32::to_le_bytes(SERIAL_COOKIE | ((size - 1) << 16)))?;
|
||||
for set in containers.chunks(8) {
|
||||
let mut b = 0;
|
||||
for (i, container) in set.iter().enumerate() {
|
||||
@ -180,7 +179,7 @@ pub(crate) fn write_bitmap_to_bytes(
|
||||
b |= 1 << i;
|
||||
}
|
||||
}
|
||||
out.write_u8(b)?;
|
||||
out.write_all(&[b])?;
|
||||
}
|
||||
if size < NO_OFFSET_THRESHOLD {
|
||||
4 + 4 * size + ((size + 7) / 8)
|
||||
@ -188,21 +187,21 @@ pub(crate) fn write_bitmap_to_bytes(
|
||||
4 + 8 * size + ((size + 7) / 8)
|
||||
}
|
||||
} else {
|
||||
out.write_u32::<LE>(SERIAL_COOKIE_NO_RUNCONTAINER)?;
|
||||
out.write_u32::<LE>(containers.len().try_into().unwrap())?;
|
||||
out.write_all(&u32::to_le_bytes(SERIAL_COOKIE_NO_RUNCONTAINER))?;
|
||||
out.write_all(&u32::to_le_bytes(containers.len().try_into().unwrap()))?;
|
||||
4 + 4 + 4 * size + 4 * size
|
||||
};
|
||||
for (&key, container) in keys.iter().zip(&containers) {
|
||||
// descriptive header
|
||||
let key: u32 = key.into();
|
||||
let count: u32 = container.popcount() - 1;
|
||||
out.write_u32::<LE>((count << 16) | key)?;
|
||||
out.write_all(&u32::to_le_bytes((count << 16) | key))?;
|
||||
}
|
||||
if !has_run || size >= NO_OFFSET_THRESHOLD {
|
||||
// offset header
|
||||
let mut starting_offset = start_offset;
|
||||
for container in &containers {
|
||||
out.write_u32::<LE>(starting_offset)?;
|
||||
out.write_all(&u32::to_le_bytes(starting_offset))?;
|
||||
starting_offset += match container {
|
||||
Container::Bits(_) => 8192u32,
|
||||
Container::Array(array) => u32::try_from(array.len()).unwrap() * 2,
|
||||
@ -214,19 +213,19 @@ pub(crate) fn write_bitmap_to_bytes(
|
||||
match container {
|
||||
Container::Bits(bits) => {
|
||||
for chunk in bits.iter() {
|
||||
out.write_u64::<LE>(*chunk)?;
|
||||
out.write_all(&u64::to_le_bytes(*chunk))?;
|
||||
}
|
||||
}
|
||||
Container::Array(array) => {
|
||||
for value in array.iter() {
|
||||
out.write_u16::<LE>(*value)?;
|
||||
out.write_all(&u16::to_le_bytes(*value))?;
|
||||
}
|
||||
}
|
||||
Container::Run(runs) => {
|
||||
out.write_u16::<LE>((runs.len()).try_into().unwrap())?;
|
||||
out.write_all(&u16::to_le_bytes(runs.len().try_into().unwrap()))?;
|
||||
for (start, lenm1) in runs.iter().copied() {
|
||||
out.write_u16::<LE>(start)?;
|
||||
out.write_u16::<LE>(lenm1)?;
|
||||
out.write_all(&u16::to_le_bytes(start))?;
|
||||
out.write_all(&u16::to_le_bytes(lenm1))?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,4 +10,3 @@ regex = "1.4"
|
||||
shlex = "1.0"
|
||||
serde_json = "1.0"
|
||||
fs-err = "2.5.0"
|
||||
once_cell = "1.0"
|
||||
|
@ -1,8 +1,8 @@
|
||||
use jsonpath_lib::select;
|
||||
use once_cell::sync::Lazy;
|
||||
use regex::{Regex, RegexBuilder};
|
||||
use serde_json::Value;
|
||||
use std::borrow::Cow;
|
||||
use std::sync::OnceLock;
|
||||
use std::{env, fmt, fs};
|
||||
|
||||
mod cache;
|
||||
@ -95,7 +95,8 @@ impl fmt::Display for CommandKind {
|
||||
}
|
||||
}
|
||||
|
||||
static LINE_PATTERN: Lazy<Regex> = Lazy::new(|| {
|
||||
static LINE_PATTERN: OnceLock<Regex> = OnceLock::new();
|
||||
fn line_pattern() -> Regex {
|
||||
RegexBuilder::new(
|
||||
r#"
|
||||
\s(?P<invalid>!?)@(?P<negated>!?)
|
||||
@ -107,7 +108,7 @@ static LINE_PATTERN: Lazy<Regex> = Lazy::new(|| {
|
||||
.unicode(true)
|
||||
.build()
|
||||
.unwrap()
|
||||
});
|
||||
}
|
||||
|
||||
fn print_err(msg: &str, lineno: usize) {
|
||||
eprintln!("Invalid command: {} on line {}", msg, lineno)
|
||||
@ -123,7 +124,7 @@ fn get_commands(template: &str) -> Result<Vec<Command>, ()> {
|
||||
for (lineno, line) in file.split('\n').enumerate() {
|
||||
let lineno = lineno + 1;
|
||||
|
||||
let cap = match LINE_PATTERN.captures(line) {
|
||||
let cap = match LINE_PATTERN.get_or_init(line_pattern).captures(line) {
|
||||
Some(c) => c,
|
||||
None => continue,
|
||||
};
|
||||
|
@ -9,5 +9,4 @@ path = "main.rs"
|
||||
|
||||
[dependencies]
|
||||
regex = "1"
|
||||
once_cell = "1"
|
||||
html5ever = "0.26.0"
|
||||
|
@ -18,8 +18,6 @@ use html5ever::tendril::ByteTendril;
|
||||
use html5ever::tokenizer::{
|
||||
BufferQueue, TagToken, Token, TokenSink, TokenSinkResult, Tokenizer, TokenizerOpts,
|
||||
};
|
||||
use once_cell::sync::Lazy;
|
||||
use regex::Regex;
|
||||
use std::cell::RefCell;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::env;
|
||||
@ -69,8 +67,12 @@ const INTRA_DOC_LINK_EXCEPTIONS: &[(&str, &[&str])] = &[
|
||||
|
||||
];
|
||||
|
||||
static BROKEN_INTRA_DOC_LINK: Lazy<Regex> =
|
||||
Lazy::new(|| Regex::new(r#"\[<code>(.*)</code>\]"#).unwrap());
|
||||
macro_rules! static_regex {
|
||||
($re:literal) => {{
|
||||
static RE: ::std::sync::OnceLock<::regex::Regex> = ::std::sync::OnceLock::new();
|
||||
RE.get_or_init(|| ::regex::Regex::new($re).unwrap())
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! t {
|
||||
($e:expr) => {
|
||||
@ -373,7 +375,7 @@ impl Checker {
|
||||
// Search for intra-doc links that rustdoc didn't warn about
|
||||
// NOTE: only looks at one line at a time; in practice this should find most links
|
||||
for (i, line) in source.lines().enumerate() {
|
||||
for broken_link in BROKEN_INTRA_DOC_LINK.captures_iter(line) {
|
||||
for broken_link in static_regex!(r#"\[<code>(.*)</code>\]"#).captures_iter(line) {
|
||||
if is_intra_doc_exception(file, &broken_link[1]) {
|
||||
report.intra_doc_exceptions += 1;
|
||||
} else {
|
||||
|
@ -46,7 +46,6 @@ colored = "2"
|
||||
ui_test = "0.21.1"
|
||||
rustc_version = "0.4"
|
||||
regex = "1.5.5"
|
||||
lazy_static = "1.4.0"
|
||||
tempfile = "3"
|
||||
|
||||
[package.metadata.rust-analyzer]
|
||||
|
@ -1,6 +1,7 @@
|
||||
use std::ffi::OsString;
|
||||
use std::num::NonZeroUsize;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::OnceLock;
|
||||
use std::{env, process::Command};
|
||||
|
||||
use colored::*;
|
||||
@ -67,8 +68,8 @@ fn miri_config(target: &str, path: &str, mode: Mode, with_dependencies: bool) ->
|
||||
|
||||
let mut config = Config {
|
||||
target: Some(target.to_owned()),
|
||||
stderr_filters: STDERR.clone(),
|
||||
stdout_filters: STDOUT.clone(),
|
||||
stderr_filters: stderr_filters().into(),
|
||||
stdout_filters: stdout_filters().into(),
|
||||
mode,
|
||||
program,
|
||||
out_dir: PathBuf::from(std::env::var_os("CARGO_TARGET_DIR").unwrap()).join("ui"),
|
||||
@ -174,15 +175,18 @@ fn run_tests(
|
||||
}
|
||||
|
||||
macro_rules! regexes {
|
||||
($name:ident: $($regex:expr => $replacement:expr,)*) => {lazy_static::lazy_static! {
|
||||
static ref $name: Vec<(Match, &'static [u8])> = vec![
|
||||
$((Regex::new($regex).unwrap().into(), $replacement.as_bytes()),)*
|
||||
];
|
||||
}};
|
||||
($name:ident: $($regex:expr => $replacement:expr,)*) => {
|
||||
fn $name() -> &'static [(Match, &'static [u8])] {
|
||||
static S: OnceLock<Vec<(Match, &'static [u8])>> = OnceLock::new();
|
||||
S.get_or_init(|| vec![
|
||||
$((Regex::new($regex).unwrap().into(), $replacement.as_bytes()),)*
|
||||
])
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
regexes! {
|
||||
STDOUT:
|
||||
stdout_filters:
|
||||
// Windows file paths
|
||||
r"\\" => "/",
|
||||
// erase borrow tags
|
||||
@ -191,7 +195,7 @@ regexes! {
|
||||
}
|
||||
|
||||
regexes! {
|
||||
STDERR:
|
||||
stderr_filters:
|
||||
// erase line and column info
|
||||
r"\.rs:[0-9]+:[0-9]+(: [0-9]+:[0-9]+)?" => ".rs:LL:CC",
|
||||
// erase alloc ids
|
||||
|
@ -6,4 +6,3 @@ edition = "2021"
|
||||
[dependencies]
|
||||
glob = "0.3.0"
|
||||
build_helper = { version = "0.1.0", path = "../build_helper" }
|
||||
once_cell = "1.17.1"
|
||||
|
@ -5,7 +5,7 @@ use std::{
|
||||
|
||||
use dynamic_suggestions::DYNAMIC_SUGGESTIONS;
|
||||
use glob::Pattern;
|
||||
use static_suggestions::STATIC_SUGGESTIONS;
|
||||
use static_suggestions::static_suggestions;
|
||||
|
||||
mod dynamic_suggestions;
|
||||
mod static_suggestions;
|
||||
@ -33,7 +33,7 @@ pub fn get_suggestions<T: AsRef<str>>(modified_files: &[T]) -> Vec<Suggestion> {
|
||||
let mut suggestions = Vec::new();
|
||||
|
||||
// static suggestions
|
||||
for (globs, sugs) in STATIC_SUGGESTIONS.iter() {
|
||||
for (globs, sugs) in static_suggestions().iter() {
|
||||
let globs = globs
|
||||
.iter()
|
||||
.map(|glob| Pattern::new(glob).expect("Found invalid glob pattern!"))
|
||||
|
@ -1,10 +1,14 @@
|
||||
use crate::{sug, Suggestion};
|
||||
use std::sync::OnceLock;
|
||||
|
||||
// FIXME: perhaps this could use `std::lazy` when it is stablizied
|
||||
macro_rules! static_suggestions {
|
||||
($( [ $( $glob:expr ),* $(,)? ] => [ $( $suggestion:expr ),* $(,)? ] ),* $(,)? ) => {
|
||||
pub(crate) const STATIC_SUGGESTIONS: ::once_cell::unsync::Lazy<Vec<(Vec<&'static str>, Vec<Suggestion>)>>
|
||||
= ::once_cell::unsync::Lazy::new(|| vec![ $( (vec![ $($glob),* ], vec![ $($suggestion),* ]) ),*]);
|
||||
pub(crate) fn static_suggestions() -> &'static [(Vec<&'static str>, Vec<Suggestion>)]
|
||||
{
|
||||
static S: OnceLock<Vec<(Vec<&'static str>, Vec<Suggestion>)>> = OnceLock::new();
|
||||
S.get_or_init(|| vec![ $( (vec![ $($glob),* ], vec![ $($suggestion),* ]) ),*])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,6 @@ autobins = false
|
||||
cargo_metadata = "0.15"
|
||||
regex = "1"
|
||||
miropt-test-tools = { path = "../miropt-test-tools" }
|
||||
lazy_static = "1"
|
||||
walkdir = "2"
|
||||
ignore = "0.4.18"
|
||||
semver = "1.0"
|
||||
|
@ -17,8 +17,6 @@ use std::fs;
|
||||
use std::num::NonZeroU32;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use regex::Regex;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
@ -251,16 +249,10 @@ fn format_features<'a>(
|
||||
}
|
||||
|
||||
fn find_attr_val<'a>(line: &'a str, attr: &str) -> Option<&'a str> {
|
||||
lazy_static::lazy_static! {
|
||||
static ref ISSUE: Regex = Regex::new(r#"issue\s*=\s*"([^"]*)""#).unwrap();
|
||||
static ref FEATURE: Regex = Regex::new(r#"feature\s*=\s*"([^"]*)""#).unwrap();
|
||||
static ref SINCE: Regex = Regex::new(r#"since\s*=\s*"([^"]*)""#).unwrap();
|
||||
}
|
||||
|
||||
let r = match attr {
|
||||
"issue" => &*ISSUE,
|
||||
"feature" => &*FEATURE,
|
||||
"since" => &*SINCE,
|
||||
"issue" => static_regex!(r#"issue\s*=\s*"([^"]*)""#),
|
||||
"feature" => static_regex!(r#"feature\s*=\s*"([^"]*)""#),
|
||||
"since" => static_regex!(r#"since\s*=\s*"([^"]*)""#),
|
||||
_ => unimplemented!("{attr} not handled"),
|
||||
};
|
||||
|
||||
@ -528,11 +520,8 @@ fn map_lib_features(
|
||||
}};
|
||||
}
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
static ref COMMENT_LINE: Regex = Regex::new(r"^\s*//").unwrap();
|
||||
}
|
||||
// exclude commented out lines
|
||||
if COMMENT_LINE.is_match(line) {
|
||||
if static_regex!(r"^\s*//").is_match(line) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -6,8 +6,8 @@ use std::{fs::OpenOptions, io::Write, path::Path};
|
||||
|
||||
use regex::Regex;
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
static ref MESSAGE: Regex = Regex::new(r#"(?m)^([a-zA-Z0-9_]+)\s*=\s*"#).unwrap();
|
||||
fn message() -> &'static Regex {
|
||||
static_regex!(r#"(?m)^([a-zA-Z0-9_]+)\s*=\s*"#)
|
||||
}
|
||||
|
||||
fn filter_fluent(path: &Path) -> bool {
|
||||
@ -20,7 +20,7 @@ fn check_alphabetic(
|
||||
bad: &mut bool,
|
||||
all_defined_msgs: &mut HashMap<String, String>,
|
||||
) {
|
||||
let mut matches = MESSAGE.captures_iter(fluent).peekable();
|
||||
let mut matches = message().captures_iter(fluent).peekable();
|
||||
while let Some(m) = matches.next() {
|
||||
let name = m.get(1).unwrap();
|
||||
if let Some(defined_filename) = all_defined_msgs.get(name.as_str()) {
|
||||
@ -60,7 +60,7 @@ fn sort_messages(
|
||||
let mut chunks = vec![];
|
||||
let mut cur = String::new();
|
||||
for line in fluent.lines() {
|
||||
if let Some(name) = MESSAGE.find(line) {
|
||||
if let Some(name) = message().find(line) {
|
||||
if let Some(defined_filename) = all_defined_msgs.get(name.as_str()) {
|
||||
tidy_error!(
|
||||
bad,
|
||||
|
@ -1,14 +1,9 @@
|
||||
//! Checks that all Fluent messages appear at least twice
|
||||
|
||||
use crate::walk::{filter_dirs, walk};
|
||||
use regex::Regex;
|
||||
use std::collections::HashMap;
|
||||
use std::path::Path;
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
static ref WORD: Regex = Regex::new(r"\w+").unwrap();
|
||||
}
|
||||
|
||||
fn filter_used_messages(
|
||||
contents: &str,
|
||||
msgs_not_appeared_yet: &mut HashMap<String, String>,
|
||||
@ -17,7 +12,7 @@ fn filter_used_messages(
|
||||
// we don't just check messages never appear in Rust files,
|
||||
// because messages can be used as parts of other fluent messages in Fluent files,
|
||||
// so we do checking messages appear only once in all Rust and Fluent files.
|
||||
let mut matches = WORD.find_iter(contents);
|
||||
let mut matches = static_regex!(r"\w+").find_iter(contents);
|
||||
while let Some(name) = matches.next() {
|
||||
if let Some((name, filename)) = msgs_not_appeared_yet.remove_entry(name.as_str()) {
|
||||
// if one msg appears for the first time,
|
||||
|
@ -5,6 +5,13 @@
|
||||
|
||||
use termcolor::WriteColor;
|
||||
|
||||
macro_rules! static_regex {
|
||||
($re:literal) => {{
|
||||
static RE: ::std::sync::OnceLock<::regex::Regex> = ::std::sync::OnceLock::new();
|
||||
RE.get_or_init(|| ::regex::Regex::new($re).unwrap())
|
||||
}};
|
||||
}
|
||||
|
||||
/// A helper macro to `unwrap` a result except also print out details like:
|
||||
///
|
||||
/// * The expression that failed
|
||||
|
@ -18,7 +18,7 @@
|
||||
// ignore-tidy-dbg
|
||||
|
||||
use crate::walk::{filter_dirs, walk};
|
||||
use regex::{Regex, RegexSet};
|
||||
use regex::RegexSet;
|
||||
use rustc_hash::FxHashMap;
|
||||
use std::{ffi::OsStr, path::Path};
|
||||
|
||||
@ -178,20 +178,14 @@ fn should_ignore(line: &str) -> bool {
|
||||
// Matches test annotations like `//~ ERROR text`.
|
||||
// This mirrors the regex in src/tools/compiletest/src/runtest.rs, please
|
||||
// update both if either are changed.
|
||||
lazy_static::lazy_static! {
|
||||
static ref ANNOTATION_RE: Regex = Regex::new("\\s*//(\\[.*\\])?~.*").unwrap();
|
||||
}
|
||||
static_regex!("\\s*//(\\[.*\\])?~.*").is_match(line)
|
||||
|| ANNOTATIONS_TO_IGNORE.iter().any(|a| line.contains(a))
|
||||
|
||||
// For `ui_test`-style UI test directives, also ignore
|
||||
// - `//@[rev] compile-flags`
|
||||
// - `//@[rev] normalize-stderr-test`
|
||||
lazy_static::lazy_static! {
|
||||
static ref UI_TEST_LONG_DIRECTIVES_RE: Regex =
|
||||
Regex::new("\\s*//@(\\[.*\\]) (compile-flags|normalize-stderr-test|error-pattern).*")
|
||||
.unwrap();
|
||||
}
|
||||
ANNOTATION_RE.is_match(line)
|
||||
|| ANNOTATIONS_TO_IGNORE.iter().any(|a| line.contains(a))
|
||||
|| UI_TEST_LONG_DIRECTIVES_RE.is_match(line)
|
||||
|| static_regex!("\\s*//@(\\[.*\\]) (compile-flags|normalize-stderr-test|error-pattern).*")
|
||||
.is_match(line)
|
||||
}
|
||||
|
||||
/// Returns `true` if `line` is allowed to be longer than the normal limit.
|
||||
|
@ -2,8 +2,6 @@
|
||||
//! - the number of entries in each directory must be less than `ENTRY_LIMIT`
|
||||
//! - there are no stray `.stderr` files
|
||||
use ignore::Walk;
|
||||
use lazy_static::lazy_static;
|
||||
use regex::Regex;
|
||||
use std::collections::{BTreeSet, HashMap};
|
||||
use std::ffi::OsStr;
|
||||
use std::fs;
|
||||
@ -182,12 +180,8 @@ pub fn check(root_path: &Path, bless: bool, bad: &mut bool) {
|
||||
}
|
||||
|
||||
if ext == "rs" {
|
||||
lazy_static! {
|
||||
static ref ISSUE_NAME_REGEX: Regex =
|
||||
Regex::new(r"^issues?[-_]?(\d{3,})").unwrap();
|
||||
}
|
||||
|
||||
if let Some(test_name) = ISSUE_NAME_REGEX.captures(testname) {
|
||||
if let Some(test_name) = static_regex!(r"^issues?[-_]?(\d{3,})").captures(testname)
|
||||
{
|
||||
// these paths are always relative to the passed `path` and always UTF8
|
||||
let stripped_path = file_path
|
||||
.strip_prefix(path)
|
||||
|
@ -1,17 +0,0 @@
|
||||
//@ known-bug: #123710
|
||||
|
||||
#[repr(packed)]
|
||||
#[repr(u32)]
|
||||
enum E {
|
||||
A,
|
||||
B,
|
||||
C,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
union InvalidTag {
|
||||
int: u32,
|
||||
e: E,
|
||||
}
|
||||
let _invalid_tag = InvalidTag { int: 4 };
|
||||
}
|
@ -4,33 +4,26 @@
|
||||
fn concrete() -> () {
|
||||
let mut _0: ();
|
||||
let _1: usize;
|
||||
let mut _2: usize;
|
||||
let mut _4: usize;
|
||||
let mut _6: usize;
|
||||
let mut _8: usize;
|
||||
let mut _10: usize;
|
||||
let mut _12: usize;
|
||||
let mut _14: usize;
|
||||
scope 1 {
|
||||
debug x => _1;
|
||||
let _3: usize;
|
||||
let _2: usize;
|
||||
scope 2 {
|
||||
debug y => _3;
|
||||
let _5: usize;
|
||||
debug y => _2;
|
||||
let _3: usize;
|
||||
scope 3 {
|
||||
debug z0 => _5;
|
||||
let _7: usize;
|
||||
debug z0 => _3;
|
||||
let _4: usize;
|
||||
scope 4 {
|
||||
debug z1 => _7;
|
||||
let _9: usize;
|
||||
debug z1 => _4;
|
||||
let _5: usize;
|
||||
scope 5 {
|
||||
debug eA0 => _9;
|
||||
let _11: usize;
|
||||
debug eA0 => _5;
|
||||
let _6: usize;
|
||||
scope 6 {
|
||||
debug eA1 => _11;
|
||||
let _13: usize;
|
||||
debug eA1 => _6;
|
||||
let _7: usize;
|
||||
scope 7 {
|
||||
debug eC => _13;
|
||||
debug eC => _7;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -41,82 +34,33 @@
|
||||
|
||||
bb0: {
|
||||
StorageLive(_1);
|
||||
- _1 = OffsetOf(Alpha, [(0, 0)]);
|
||||
+ _1 = const 4_usize;
|
||||
StorageLive(_2);
|
||||
- _2 = OffsetOf(Alpha, [(0, 0)]);
|
||||
- _1 = must_use::<usize>(move _2) -> [return: bb1, unwind unreachable];
|
||||
+ _2 = const 4_usize;
|
||||
+ _1 = must_use::<usize>(const 4_usize) -> [return: bb1, unwind unreachable];
|
||||
}
|
||||
|
||||
bb1: {
|
||||
StorageDead(_2);
|
||||
- _2 = OffsetOf(Alpha, [(0, 1)]);
|
||||
+ _2 = const 0_usize;
|
||||
StorageLive(_3);
|
||||
- _3 = OffsetOf(Alpha, [(0, 2), (0, 0)]);
|
||||
+ _3 = const 2_usize;
|
||||
StorageLive(_4);
|
||||
- _4 = OffsetOf(Alpha, [(0, 1)]);
|
||||
- _3 = must_use::<usize>(move _4) -> [return: bb2, unwind unreachable];
|
||||
+ _4 = const 0_usize;
|
||||
+ _3 = must_use::<usize>(const 0_usize) -> [return: bb2, unwind unreachable];
|
||||
}
|
||||
|
||||
bb2: {
|
||||
StorageDead(_4);
|
||||
- _4 = OffsetOf(Alpha, [(0, 2), (0, 1)]);
|
||||
+ _4 = const 3_usize;
|
||||
StorageLive(_5);
|
||||
- _5 = OffsetOf(Epsilon, [(0, 0)]);
|
||||
+ _5 = const 1_usize;
|
||||
StorageLive(_6);
|
||||
- _6 = OffsetOf(Alpha, [(0, 2), (0, 0)]);
|
||||
- _5 = must_use::<usize>(move _6) -> [return: bb3, unwind unreachable];
|
||||
- _6 = OffsetOf(Epsilon, [(0, 1)]);
|
||||
+ _6 = const 2_usize;
|
||||
+ _5 = must_use::<usize>(const 2_usize) -> [return: bb3, unwind unreachable];
|
||||
}
|
||||
|
||||
bb3: {
|
||||
StorageDead(_6);
|
||||
StorageLive(_7);
|
||||
StorageLive(_8);
|
||||
- _8 = OffsetOf(Alpha, [(0, 2), (0, 1)]);
|
||||
- _7 = must_use::<usize>(move _8) -> [return: bb4, unwind unreachable];
|
||||
+ _8 = const 3_usize;
|
||||
+ _7 = must_use::<usize>(const 3_usize) -> [return: bb4, unwind unreachable];
|
||||
}
|
||||
|
||||
bb4: {
|
||||
StorageDead(_8);
|
||||
StorageLive(_9);
|
||||
StorageLive(_10);
|
||||
- _10 = OffsetOf(Epsilon, [(0, 0)]);
|
||||
- _9 = must_use::<usize>(move _10) -> [return: bb5, unwind unreachable];
|
||||
+ _10 = const 1_usize;
|
||||
+ _9 = must_use::<usize>(const 1_usize) -> [return: bb5, unwind unreachable];
|
||||
}
|
||||
|
||||
bb5: {
|
||||
StorageDead(_10);
|
||||
StorageLive(_11);
|
||||
StorageLive(_12);
|
||||
- _12 = OffsetOf(Epsilon, [(0, 1)]);
|
||||
- _11 = must_use::<usize>(move _12) -> [return: bb6, unwind unreachable];
|
||||
+ _12 = const 2_usize;
|
||||
+ _11 = must_use::<usize>(const 2_usize) -> [return: bb6, unwind unreachable];
|
||||
}
|
||||
|
||||
bb6: {
|
||||
StorageDead(_12);
|
||||
StorageLive(_13);
|
||||
StorageLive(_14);
|
||||
- _14 = OffsetOf(Epsilon, [(2, 0)]);
|
||||
- _13 = must_use::<usize>(move _14) -> [return: bb7, unwind unreachable];
|
||||
+ _14 = const 4_usize;
|
||||
+ _13 = must_use::<usize>(const 4_usize) -> [return: bb7, unwind unreachable];
|
||||
}
|
||||
|
||||
bb7: {
|
||||
StorageDead(_14);
|
||||
- _7 = OffsetOf(Epsilon, [(2, 0)]);
|
||||
+ _7 = const 4_usize;
|
||||
_0 = const ();
|
||||
StorageDead(_13);
|
||||
StorageDead(_11);
|
||||
StorageDead(_9);
|
||||
StorageDead(_7);
|
||||
StorageDead(_6);
|
||||
StorageDead(_5);
|
||||
StorageDead(_4);
|
||||
StorageDead(_3);
|
||||
StorageDead(_2);
|
||||
StorageDead(_1);
|
||||
return;
|
||||
}
|
||||
|
@ -4,33 +4,26 @@
|
||||
fn concrete() -> () {
|
||||
let mut _0: ();
|
||||
let _1: usize;
|
||||
let mut _2: usize;
|
||||
let mut _4: usize;
|
||||
let mut _6: usize;
|
||||
let mut _8: usize;
|
||||
let mut _10: usize;
|
||||
let mut _12: usize;
|
||||
let mut _14: usize;
|
||||
scope 1 {
|
||||
debug x => _1;
|
||||
let _3: usize;
|
||||
let _2: usize;
|
||||
scope 2 {
|
||||
debug y => _3;
|
||||
let _5: usize;
|
||||
debug y => _2;
|
||||
let _3: usize;
|
||||
scope 3 {
|
||||
debug z0 => _5;
|
||||
let _7: usize;
|
||||
debug z0 => _3;
|
||||
let _4: usize;
|
||||
scope 4 {
|
||||
debug z1 => _7;
|
||||
let _9: usize;
|
||||
debug z1 => _4;
|
||||
let _5: usize;
|
||||
scope 5 {
|
||||
debug eA0 => _9;
|
||||
let _11: usize;
|
||||
debug eA0 => _5;
|
||||
let _6: usize;
|
||||
scope 6 {
|
||||
debug eA1 => _11;
|
||||
let _13: usize;
|
||||
debug eA1 => _6;
|
||||
let _7: usize;
|
||||
scope 7 {
|
||||
debug eC => _13;
|
||||
debug eC => _7;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -41,82 +34,33 @@
|
||||
|
||||
bb0: {
|
||||
StorageLive(_1);
|
||||
- _1 = OffsetOf(Alpha, [(0, 0)]);
|
||||
+ _1 = const 4_usize;
|
||||
StorageLive(_2);
|
||||
- _2 = OffsetOf(Alpha, [(0, 0)]);
|
||||
- _1 = must_use::<usize>(move _2) -> [return: bb1, unwind continue];
|
||||
+ _2 = const 4_usize;
|
||||
+ _1 = must_use::<usize>(const 4_usize) -> [return: bb1, unwind continue];
|
||||
}
|
||||
|
||||
bb1: {
|
||||
StorageDead(_2);
|
||||
- _2 = OffsetOf(Alpha, [(0, 1)]);
|
||||
+ _2 = const 0_usize;
|
||||
StorageLive(_3);
|
||||
- _3 = OffsetOf(Alpha, [(0, 2), (0, 0)]);
|
||||
+ _3 = const 2_usize;
|
||||
StorageLive(_4);
|
||||
- _4 = OffsetOf(Alpha, [(0, 1)]);
|
||||
- _3 = must_use::<usize>(move _4) -> [return: bb2, unwind continue];
|
||||
+ _4 = const 0_usize;
|
||||
+ _3 = must_use::<usize>(const 0_usize) -> [return: bb2, unwind continue];
|
||||
}
|
||||
|
||||
bb2: {
|
||||
StorageDead(_4);
|
||||
- _4 = OffsetOf(Alpha, [(0, 2), (0, 1)]);
|
||||
+ _4 = const 3_usize;
|
||||
StorageLive(_5);
|
||||
- _5 = OffsetOf(Epsilon, [(0, 0)]);
|
||||
+ _5 = const 1_usize;
|
||||
StorageLive(_6);
|
||||
- _6 = OffsetOf(Alpha, [(0, 2), (0, 0)]);
|
||||
- _5 = must_use::<usize>(move _6) -> [return: bb3, unwind continue];
|
||||
- _6 = OffsetOf(Epsilon, [(0, 1)]);
|
||||
+ _6 = const 2_usize;
|
||||
+ _5 = must_use::<usize>(const 2_usize) -> [return: bb3, unwind continue];
|
||||
}
|
||||
|
||||
bb3: {
|
||||
StorageDead(_6);
|
||||
StorageLive(_7);
|
||||
StorageLive(_8);
|
||||
- _8 = OffsetOf(Alpha, [(0, 2), (0, 1)]);
|
||||
- _7 = must_use::<usize>(move _8) -> [return: bb4, unwind continue];
|
||||
+ _8 = const 3_usize;
|
||||
+ _7 = must_use::<usize>(const 3_usize) -> [return: bb4, unwind continue];
|
||||
}
|
||||
|
||||
bb4: {
|
||||
StorageDead(_8);
|
||||
StorageLive(_9);
|
||||
StorageLive(_10);
|
||||
- _10 = OffsetOf(Epsilon, [(0, 0)]);
|
||||
- _9 = must_use::<usize>(move _10) -> [return: bb5, unwind continue];
|
||||
+ _10 = const 1_usize;
|
||||
+ _9 = must_use::<usize>(const 1_usize) -> [return: bb5, unwind continue];
|
||||
}
|
||||
|
||||
bb5: {
|
||||
StorageDead(_10);
|
||||
StorageLive(_11);
|
||||
StorageLive(_12);
|
||||
- _12 = OffsetOf(Epsilon, [(0, 1)]);
|
||||
- _11 = must_use::<usize>(move _12) -> [return: bb6, unwind continue];
|
||||
+ _12 = const 2_usize;
|
||||
+ _11 = must_use::<usize>(const 2_usize) -> [return: bb6, unwind continue];
|
||||
}
|
||||
|
||||
bb6: {
|
||||
StorageDead(_12);
|
||||
StorageLive(_13);
|
||||
StorageLive(_14);
|
||||
- _14 = OffsetOf(Epsilon, [(2, 0)]);
|
||||
- _13 = must_use::<usize>(move _14) -> [return: bb7, unwind continue];
|
||||
+ _14 = const 4_usize;
|
||||
+ _13 = must_use::<usize>(const 4_usize) -> [return: bb7, unwind continue];
|
||||
}
|
||||
|
||||
bb7: {
|
||||
StorageDead(_14);
|
||||
- _7 = OffsetOf(Epsilon, [(2, 0)]);
|
||||
+ _7 = const 4_usize;
|
||||
_0 = const ();
|
||||
StorageDead(_13);
|
||||
StorageDead(_11);
|
||||
StorageDead(_9);
|
||||
StorageDead(_7);
|
||||
StorageDead(_6);
|
||||
StorageDead(_5);
|
||||
StorageDead(_4);
|
||||
StorageDead(_3);
|
||||
StorageDead(_2);
|
||||
StorageDead(_1);
|
||||
return;
|
||||
}
|
||||
|
@ -4,33 +4,26 @@
|
||||
fn generic() -> () {
|
||||
let mut _0: ();
|
||||
let _1: usize;
|
||||
let mut _2: usize;
|
||||
let mut _4: usize;
|
||||
let mut _6: usize;
|
||||
let mut _8: usize;
|
||||
let mut _10: usize;
|
||||
let mut _12: usize;
|
||||
let mut _14: usize;
|
||||
scope 1 {
|
||||
debug gx => _1;
|
||||
let _3: usize;
|
||||
let _2: usize;
|
||||
scope 2 {
|
||||
debug gy => _3;
|
||||
let _5: usize;
|
||||
debug gy => _2;
|
||||
let _3: usize;
|
||||
scope 3 {
|
||||
debug dx => _5;
|
||||
let _7: usize;
|
||||
debug dx => _3;
|
||||
let _4: usize;
|
||||
scope 4 {
|
||||
debug dy => _7;
|
||||
let _9: usize;
|
||||
debug dy => _4;
|
||||
let _5: usize;
|
||||
scope 5 {
|
||||
debug zA0 => _9;
|
||||
let _11: usize;
|
||||
debug zA0 => _5;
|
||||
let _6: usize;
|
||||
scope 6 {
|
||||
debug zA1 => _11;
|
||||
let _13: usize;
|
||||
debug zA1 => _6;
|
||||
let _7: usize;
|
||||
scope 7 {
|
||||
debug zB => _13;
|
||||
debug zB => _7;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -41,72 +34,28 @@
|
||||
|
||||
bb0: {
|
||||
StorageLive(_1);
|
||||
_1 = OffsetOf(Gamma<T>, [(0, 0)]);
|
||||
StorageLive(_2);
|
||||
_2 = OffsetOf(Gamma<T>, [(0, 0)]);
|
||||
_1 = must_use::<usize>(move _2) -> [return: bb1, unwind unreachable];
|
||||
}
|
||||
|
||||
bb1: {
|
||||
StorageDead(_2);
|
||||
_2 = OffsetOf(Gamma<T>, [(0, 1)]);
|
||||
StorageLive(_3);
|
||||
- _3 = OffsetOf(Delta<T>, [(0, 1)]);
|
||||
+ _3 = const 0_usize;
|
||||
StorageLive(_4);
|
||||
_4 = OffsetOf(Gamma<T>, [(0, 1)]);
|
||||
_3 = must_use::<usize>(move _4) -> [return: bb2, unwind unreachable];
|
||||
}
|
||||
|
||||
bb2: {
|
||||
StorageDead(_4);
|
||||
- _4 = OffsetOf(Delta<T>, [(0, 2)]);
|
||||
+ _4 = const 2_usize;
|
||||
StorageLive(_5);
|
||||
_5 = OffsetOf(Zeta<T>, [(0, 0)]);
|
||||
StorageLive(_6);
|
||||
- _6 = OffsetOf(Delta<T>, [(0, 1)]);
|
||||
- _5 = must_use::<usize>(move _6) -> [return: bb3, unwind unreachable];
|
||||
+ _6 = const 0_usize;
|
||||
+ _5 = must_use::<usize>(const 0_usize) -> [return: bb3, unwind unreachable];
|
||||
}
|
||||
|
||||
bb3: {
|
||||
StorageDead(_6);
|
||||
_6 = OffsetOf(Zeta<T>, [(0, 1)]);
|
||||
StorageLive(_7);
|
||||
StorageLive(_8);
|
||||
- _8 = OffsetOf(Delta<T>, [(0, 2)]);
|
||||
- _7 = must_use::<usize>(move _8) -> [return: bb4, unwind unreachable];
|
||||
+ _8 = const 2_usize;
|
||||
+ _7 = must_use::<usize>(const 2_usize) -> [return: bb4, unwind unreachable];
|
||||
}
|
||||
|
||||
bb4: {
|
||||
StorageDead(_8);
|
||||
StorageLive(_9);
|
||||
StorageLive(_10);
|
||||
_10 = OffsetOf(Zeta<T>, [(0, 0)]);
|
||||
_9 = must_use::<usize>(move _10) -> [return: bb5, unwind unreachable];
|
||||
}
|
||||
|
||||
bb5: {
|
||||
StorageDead(_10);
|
||||
StorageLive(_11);
|
||||
StorageLive(_12);
|
||||
_12 = OffsetOf(Zeta<T>, [(0, 1)]);
|
||||
_11 = must_use::<usize>(move _12) -> [return: bb6, unwind unreachable];
|
||||
}
|
||||
|
||||
bb6: {
|
||||
StorageDead(_12);
|
||||
StorageLive(_13);
|
||||
StorageLive(_14);
|
||||
_14 = OffsetOf(Zeta<T>, [(1, 0)]);
|
||||
_13 = must_use::<usize>(move _14) -> [return: bb7, unwind unreachable];
|
||||
}
|
||||
|
||||
bb7: {
|
||||
StorageDead(_14);
|
||||
_7 = OffsetOf(Zeta<T>, [(1, 0)]);
|
||||
_0 = const ();
|
||||
StorageDead(_13);
|
||||
StorageDead(_11);
|
||||
StorageDead(_9);
|
||||
StorageDead(_7);
|
||||
StorageDead(_6);
|
||||
StorageDead(_5);
|
||||
StorageDead(_4);
|
||||
StorageDead(_3);
|
||||
StorageDead(_2);
|
||||
StorageDead(_1);
|
||||
return;
|
||||
}
|
||||
|
@ -4,33 +4,26 @@
|
||||
fn generic() -> () {
|
||||
let mut _0: ();
|
||||
let _1: usize;
|
||||
let mut _2: usize;
|
||||
let mut _4: usize;
|
||||
let mut _6: usize;
|
||||
let mut _8: usize;
|
||||
let mut _10: usize;
|
||||
let mut _12: usize;
|
||||
let mut _14: usize;
|
||||
scope 1 {
|
||||
debug gx => _1;
|
||||
let _3: usize;
|
||||
let _2: usize;
|
||||
scope 2 {
|
||||
debug gy => _3;
|
||||
let _5: usize;
|
||||
debug gy => _2;
|
||||
let _3: usize;
|
||||
scope 3 {
|
||||
debug dx => _5;
|
||||
let _7: usize;
|
||||
debug dx => _3;
|
||||
let _4: usize;
|
||||
scope 4 {
|
||||
debug dy => _7;
|
||||
let _9: usize;
|
||||
debug dy => _4;
|
||||
let _5: usize;
|
||||
scope 5 {
|
||||
debug zA0 => _9;
|
||||
let _11: usize;
|
||||
debug zA0 => _5;
|
||||
let _6: usize;
|
||||
scope 6 {
|
||||
debug zA1 => _11;
|
||||
let _13: usize;
|
||||
debug zA1 => _6;
|
||||
let _7: usize;
|
||||
scope 7 {
|
||||
debug zB => _13;
|
||||
debug zB => _7;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -41,72 +34,28 @@
|
||||
|
||||
bb0: {
|
||||
StorageLive(_1);
|
||||
_1 = OffsetOf(Gamma<T>, [(0, 0)]);
|
||||
StorageLive(_2);
|
||||
_2 = OffsetOf(Gamma<T>, [(0, 0)]);
|
||||
_1 = must_use::<usize>(move _2) -> [return: bb1, unwind continue];
|
||||
}
|
||||
|
||||
bb1: {
|
||||
StorageDead(_2);
|
||||
_2 = OffsetOf(Gamma<T>, [(0, 1)]);
|
||||
StorageLive(_3);
|
||||
- _3 = OffsetOf(Delta<T>, [(0, 1)]);
|
||||
+ _3 = const 0_usize;
|
||||
StorageLive(_4);
|
||||
_4 = OffsetOf(Gamma<T>, [(0, 1)]);
|
||||
_3 = must_use::<usize>(move _4) -> [return: bb2, unwind continue];
|
||||
}
|
||||
|
||||
bb2: {
|
||||
StorageDead(_4);
|
||||
- _4 = OffsetOf(Delta<T>, [(0, 2)]);
|
||||
+ _4 = const 2_usize;
|
||||
StorageLive(_5);
|
||||
_5 = OffsetOf(Zeta<T>, [(0, 0)]);
|
||||
StorageLive(_6);
|
||||
- _6 = OffsetOf(Delta<T>, [(0, 1)]);
|
||||
- _5 = must_use::<usize>(move _6) -> [return: bb3, unwind continue];
|
||||
+ _6 = const 0_usize;
|
||||
+ _5 = must_use::<usize>(const 0_usize) -> [return: bb3, unwind continue];
|
||||
}
|
||||
|
||||
bb3: {
|
||||
StorageDead(_6);
|
||||
_6 = OffsetOf(Zeta<T>, [(0, 1)]);
|
||||
StorageLive(_7);
|
||||
StorageLive(_8);
|
||||
- _8 = OffsetOf(Delta<T>, [(0, 2)]);
|
||||
- _7 = must_use::<usize>(move _8) -> [return: bb4, unwind continue];
|
||||
+ _8 = const 2_usize;
|
||||
+ _7 = must_use::<usize>(const 2_usize) -> [return: bb4, unwind continue];
|
||||
}
|
||||
|
||||
bb4: {
|
||||
StorageDead(_8);
|
||||
StorageLive(_9);
|
||||
StorageLive(_10);
|
||||
_10 = OffsetOf(Zeta<T>, [(0, 0)]);
|
||||
_9 = must_use::<usize>(move _10) -> [return: bb5, unwind continue];
|
||||
}
|
||||
|
||||
bb5: {
|
||||
StorageDead(_10);
|
||||
StorageLive(_11);
|
||||
StorageLive(_12);
|
||||
_12 = OffsetOf(Zeta<T>, [(0, 1)]);
|
||||
_11 = must_use::<usize>(move _12) -> [return: bb6, unwind continue];
|
||||
}
|
||||
|
||||
bb6: {
|
||||
StorageDead(_12);
|
||||
StorageLive(_13);
|
||||
StorageLive(_14);
|
||||
_14 = OffsetOf(Zeta<T>, [(1, 0)]);
|
||||
_13 = must_use::<usize>(move _14) -> [return: bb7, unwind continue];
|
||||
}
|
||||
|
||||
bb7: {
|
||||
StorageDead(_14);
|
||||
_7 = OffsetOf(Zeta<T>, [(1, 0)]);
|
||||
_0 = const ();
|
||||
StorageDead(_13);
|
||||
StorageDead(_11);
|
||||
StorageDead(_9);
|
||||
StorageDead(_7);
|
||||
StorageDead(_6);
|
||||
StorageDead(_5);
|
||||
StorageDead(_4);
|
||||
StorageDead(_3);
|
||||
StorageDead(_2);
|
||||
StorageDead(_1);
|
||||
return;
|
||||
}
|
||||
|
@ -4,21 +4,17 @@
|
||||
fn concrete() -> () {
|
||||
let mut _0: ();
|
||||
let _1: usize;
|
||||
let mut _2: usize;
|
||||
let mut _4: usize;
|
||||
let mut _6: usize;
|
||||
let mut _8: usize;
|
||||
scope 1 {
|
||||
debug x => _1;
|
||||
let _3: usize;
|
||||
let _2: usize;
|
||||
scope 2 {
|
||||
debug y => _3;
|
||||
let _5: usize;
|
||||
debug y => _2;
|
||||
let _3: usize;
|
||||
scope 3 {
|
||||
debug z0 => _5;
|
||||
let _7: usize;
|
||||
debug z0 => _3;
|
||||
let _4: usize;
|
||||
scope 4 {
|
||||
debug z1 => _7;
|
||||
debug z1 => _4;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -26,49 +22,21 @@
|
||||
|
||||
bb0: {
|
||||
StorageLive(_1);
|
||||
- _1 = OffsetOf(Alpha, [(0, 0)]);
|
||||
+ _1 = const 4_usize;
|
||||
StorageLive(_2);
|
||||
- _2 = OffsetOf(Alpha, [(0, 0)]);
|
||||
- _1 = must_use::<usize>(move _2) -> [return: bb1, unwind unreachable];
|
||||
+ _2 = const 4_usize;
|
||||
+ _1 = must_use::<usize>(const 4_usize) -> [return: bb1, unwind unreachable];
|
||||
}
|
||||
|
||||
bb1: {
|
||||
StorageDead(_2);
|
||||
- _2 = OffsetOf(Alpha, [(0, 1)]);
|
||||
+ _2 = const 0_usize;
|
||||
StorageLive(_3);
|
||||
- _3 = OffsetOf(Alpha, [(0, 2), (0, 0)]);
|
||||
+ _3 = const 2_usize;
|
||||
StorageLive(_4);
|
||||
- _4 = OffsetOf(Alpha, [(0, 1)]);
|
||||
- _3 = must_use::<usize>(move _4) -> [return: bb2, unwind unreachable];
|
||||
+ _4 = const 0_usize;
|
||||
+ _3 = must_use::<usize>(const 0_usize) -> [return: bb2, unwind unreachable];
|
||||
}
|
||||
|
||||
bb2: {
|
||||
StorageDead(_4);
|
||||
StorageLive(_5);
|
||||
StorageLive(_6);
|
||||
- _6 = OffsetOf(Alpha, [(0, 2), (0, 0)]);
|
||||
- _5 = must_use::<usize>(move _6) -> [return: bb3, unwind unreachable];
|
||||
+ _6 = const 2_usize;
|
||||
+ _5 = must_use::<usize>(const 2_usize) -> [return: bb3, unwind unreachable];
|
||||
}
|
||||
|
||||
bb3: {
|
||||
StorageDead(_6);
|
||||
StorageLive(_7);
|
||||
StorageLive(_8);
|
||||
- _8 = OffsetOf(Alpha, [(0, 2), (0, 1)]);
|
||||
- _7 = must_use::<usize>(move _8) -> [return: bb4, unwind unreachable];
|
||||
+ _8 = const 3_usize;
|
||||
+ _7 = must_use::<usize>(const 3_usize) -> [return: bb4, unwind unreachable];
|
||||
}
|
||||
|
||||
bb4: {
|
||||
StorageDead(_8);
|
||||
- _4 = OffsetOf(Alpha, [(0, 2), (0, 1)]);
|
||||
+ _4 = const 3_usize;
|
||||
_0 = const ();
|
||||
StorageDead(_7);
|
||||
StorageDead(_5);
|
||||
StorageDead(_4);
|
||||
StorageDead(_3);
|
||||
StorageDead(_2);
|
||||
StorageDead(_1);
|
||||
return;
|
||||
}
|
||||
|
@ -4,21 +4,17 @@
|
||||
fn concrete() -> () {
|
||||
let mut _0: ();
|
||||
let _1: usize;
|
||||
let mut _2: usize;
|
||||
let mut _4: usize;
|
||||
let mut _6: usize;
|
||||
let mut _8: usize;
|
||||
scope 1 {
|
||||
debug x => _1;
|
||||
let _3: usize;
|
||||
let _2: usize;
|
||||
scope 2 {
|
||||
debug y => _3;
|
||||
let _5: usize;
|
||||
debug y => _2;
|
||||
let _3: usize;
|
||||
scope 3 {
|
||||
debug z0 => _5;
|
||||
let _7: usize;
|
||||
debug z0 => _3;
|
||||
let _4: usize;
|
||||
scope 4 {
|
||||
debug z1 => _7;
|
||||
debug z1 => _4;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -26,49 +22,21 @@
|
||||
|
||||
bb0: {
|
||||
StorageLive(_1);
|
||||
- _1 = OffsetOf(Alpha, [(0, 0)]);
|
||||
+ _1 = const 4_usize;
|
||||
StorageLive(_2);
|
||||
- _2 = OffsetOf(Alpha, [(0, 0)]);
|
||||
- _1 = must_use::<usize>(move _2) -> [return: bb1, unwind continue];
|
||||
+ _2 = const 4_usize;
|
||||
+ _1 = must_use::<usize>(const 4_usize) -> [return: bb1, unwind continue];
|
||||
}
|
||||
|
||||
bb1: {
|
||||
StorageDead(_2);
|
||||
- _2 = OffsetOf(Alpha, [(0, 1)]);
|
||||
+ _2 = const 0_usize;
|
||||
StorageLive(_3);
|
||||
- _3 = OffsetOf(Alpha, [(0, 2), (0, 0)]);
|
||||
+ _3 = const 2_usize;
|
||||
StorageLive(_4);
|
||||
- _4 = OffsetOf(Alpha, [(0, 1)]);
|
||||
- _3 = must_use::<usize>(move _4) -> [return: bb2, unwind continue];
|
||||
+ _4 = const 0_usize;
|
||||
+ _3 = must_use::<usize>(const 0_usize) -> [return: bb2, unwind continue];
|
||||
}
|
||||
|
||||
bb2: {
|
||||
StorageDead(_4);
|
||||
StorageLive(_5);
|
||||
StorageLive(_6);
|
||||
- _6 = OffsetOf(Alpha, [(0, 2), (0, 0)]);
|
||||
- _5 = must_use::<usize>(move _6) -> [return: bb3, unwind continue];
|
||||
+ _6 = const 2_usize;
|
||||
+ _5 = must_use::<usize>(const 2_usize) -> [return: bb3, unwind continue];
|
||||
}
|
||||
|
||||
bb3: {
|
||||
StorageDead(_6);
|
||||
StorageLive(_7);
|
||||
StorageLive(_8);
|
||||
- _8 = OffsetOf(Alpha, [(0, 2), (0, 1)]);
|
||||
- _7 = must_use::<usize>(move _8) -> [return: bb4, unwind continue];
|
||||
+ _8 = const 3_usize;
|
||||
+ _7 = must_use::<usize>(const 3_usize) -> [return: bb4, unwind continue];
|
||||
}
|
||||
|
||||
bb4: {
|
||||
StorageDead(_8);
|
||||
- _4 = OffsetOf(Alpha, [(0, 2), (0, 1)]);
|
||||
+ _4 = const 3_usize;
|
||||
_0 = const ();
|
||||
StorageDead(_7);
|
||||
StorageDead(_5);
|
||||
StorageDead(_4);
|
||||
StorageDead(_3);
|
||||
StorageDead(_2);
|
||||
StorageDead(_1);
|
||||
return;
|
||||
}
|
||||
|
@ -4,21 +4,17 @@
|
||||
fn generic() -> () {
|
||||
let mut _0: ();
|
||||
let _1: usize;
|
||||
let mut _2: usize;
|
||||
let mut _4: usize;
|
||||
let mut _6: usize;
|
||||
let mut _8: usize;
|
||||
scope 1 {
|
||||
debug gx => _1;
|
||||
let _3: usize;
|
||||
let _2: usize;
|
||||
scope 2 {
|
||||
debug gy => _3;
|
||||
let _5: usize;
|
||||
debug gy => _2;
|
||||
let _3: usize;
|
||||
scope 3 {
|
||||
debug dx => _5;
|
||||
let _7: usize;
|
||||
debug dx => _3;
|
||||
let _4: usize;
|
||||
scope 4 {
|
||||
debug dy => _7;
|
||||
debug dy => _4;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -26,45 +22,19 @@
|
||||
|
||||
bb0: {
|
||||
StorageLive(_1);
|
||||
_1 = OffsetOf(Gamma<T>, [(0, 0)]);
|
||||
StorageLive(_2);
|
||||
_2 = OffsetOf(Gamma<T>, [(0, 0)]);
|
||||
_1 = must_use::<usize>(move _2) -> [return: bb1, unwind unreachable];
|
||||
}
|
||||
|
||||
bb1: {
|
||||
StorageDead(_2);
|
||||
_2 = OffsetOf(Gamma<T>, [(0, 1)]);
|
||||
StorageLive(_3);
|
||||
- _3 = OffsetOf(Delta<T>, [(0, 1)]);
|
||||
+ _3 = const 0_usize;
|
||||
StorageLive(_4);
|
||||
_4 = OffsetOf(Gamma<T>, [(0, 1)]);
|
||||
_3 = must_use::<usize>(move _4) -> [return: bb2, unwind unreachable];
|
||||
}
|
||||
|
||||
bb2: {
|
||||
StorageDead(_4);
|
||||
StorageLive(_5);
|
||||
StorageLive(_6);
|
||||
- _6 = OffsetOf(Delta<T>, [(0, 1)]);
|
||||
- _5 = must_use::<usize>(move _6) -> [return: bb3, unwind unreachable];
|
||||
+ _6 = const 0_usize;
|
||||
+ _5 = must_use::<usize>(const 0_usize) -> [return: bb3, unwind unreachable];
|
||||
}
|
||||
|
||||
bb3: {
|
||||
StorageDead(_6);
|
||||
StorageLive(_7);
|
||||
StorageLive(_8);
|
||||
- _8 = OffsetOf(Delta<T>, [(0, 2)]);
|
||||
- _7 = must_use::<usize>(move _8) -> [return: bb4, unwind unreachable];
|
||||
+ _8 = const 2_usize;
|
||||
+ _7 = must_use::<usize>(const 2_usize) -> [return: bb4, unwind unreachable];
|
||||
}
|
||||
|
||||
bb4: {
|
||||
StorageDead(_8);
|
||||
- _4 = OffsetOf(Delta<T>, [(0, 2)]);
|
||||
+ _4 = const 2_usize;
|
||||
_0 = const ();
|
||||
StorageDead(_7);
|
||||
StorageDead(_5);
|
||||
StorageDead(_4);
|
||||
StorageDead(_3);
|
||||
StorageDead(_2);
|
||||
StorageDead(_1);
|
||||
return;
|
||||
}
|
||||
|
@ -4,21 +4,17 @@
|
||||
fn generic() -> () {
|
||||
let mut _0: ();
|
||||
let _1: usize;
|
||||
let mut _2: usize;
|
||||
let mut _4: usize;
|
||||
let mut _6: usize;
|
||||
let mut _8: usize;
|
||||
scope 1 {
|
||||
debug gx => _1;
|
||||
let _3: usize;
|
||||
let _2: usize;
|
||||
scope 2 {
|
||||
debug gy => _3;
|
||||
let _5: usize;
|
||||
debug gy => _2;
|
||||
let _3: usize;
|
||||
scope 3 {
|
||||
debug dx => _5;
|
||||
let _7: usize;
|
||||
debug dx => _3;
|
||||
let _4: usize;
|
||||
scope 4 {
|
||||
debug dy => _7;
|
||||
debug dy => _4;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -26,45 +22,19 @@
|
||||
|
||||
bb0: {
|
||||
StorageLive(_1);
|
||||
_1 = OffsetOf(Gamma<T>, [(0, 0)]);
|
||||
StorageLive(_2);
|
||||
_2 = OffsetOf(Gamma<T>, [(0, 0)]);
|
||||
_1 = must_use::<usize>(move _2) -> [return: bb1, unwind continue];
|
||||
}
|
||||
|
||||
bb1: {
|
||||
StorageDead(_2);
|
||||
_2 = OffsetOf(Gamma<T>, [(0, 1)]);
|
||||
StorageLive(_3);
|
||||
- _3 = OffsetOf(Delta<T>, [(0, 1)]);
|
||||
+ _3 = const 0_usize;
|
||||
StorageLive(_4);
|
||||
_4 = OffsetOf(Gamma<T>, [(0, 1)]);
|
||||
_3 = must_use::<usize>(move _4) -> [return: bb2, unwind continue];
|
||||
}
|
||||
|
||||
bb2: {
|
||||
StorageDead(_4);
|
||||
StorageLive(_5);
|
||||
StorageLive(_6);
|
||||
- _6 = OffsetOf(Delta<T>, [(0, 1)]);
|
||||
- _5 = must_use::<usize>(move _6) -> [return: bb3, unwind continue];
|
||||
+ _6 = const 0_usize;
|
||||
+ _5 = must_use::<usize>(const 0_usize) -> [return: bb3, unwind continue];
|
||||
}
|
||||
|
||||
bb3: {
|
||||
StorageDead(_6);
|
||||
StorageLive(_7);
|
||||
StorageLive(_8);
|
||||
- _8 = OffsetOf(Delta<T>, [(0, 2)]);
|
||||
- _7 = must_use::<usize>(move _8) -> [return: bb4, unwind continue];
|
||||
+ _8 = const 2_usize;
|
||||
+ _7 = must_use::<usize>(const 2_usize) -> [return: bb4, unwind continue];
|
||||
}
|
||||
|
||||
bb4: {
|
||||
StorageDead(_8);
|
||||
- _4 = OffsetOf(Delta<T>, [(0, 2)]);
|
||||
+ _4 = const 2_usize;
|
||||
_0 = const ();
|
||||
StorageDead(_7);
|
||||
StorageDead(_5);
|
||||
StorageDead(_4);
|
||||
StorageDead(_3);
|
||||
StorageDead(_2);
|
||||
StorageDead(_1);
|
||||
return;
|
||||
}
|
||||
|
@ -36,16 +36,16 @@ fn concrete() {
|
||||
// CHECK: debug z0 => [[z0:_.*]];
|
||||
// CHECK: debug z1 => [[z1:_.*]];
|
||||
|
||||
// CHECK: [[x]] = must_use::<usize>(const 4_usize) -> {{.*}}
|
||||
// CHECK: [[x]] = const 4_usize
|
||||
let x = offset_of!(Alpha, x);
|
||||
|
||||
// CHECK: [[y]] = must_use::<usize>(const 0_usize) -> {{.*}}
|
||||
// CHECK: [[y]] = const 0_usize
|
||||
let y = offset_of!(Alpha, y);
|
||||
|
||||
// CHECK: [[z0]] = must_use::<usize>(const 2_usize) -> {{.*}}
|
||||
// CHECK: [[z0]] = const 2_usize
|
||||
let z0 = offset_of!(Alpha, z.0);
|
||||
|
||||
// CHECK: [[z1]] = must_use::<usize>(const 3_usize) -> {{.*}}
|
||||
// CHECK: [[z1]] = const 3_usize
|
||||
let z1 = offset_of!(Alpha, z.1);
|
||||
}
|
||||
|
||||
@ -58,16 +58,16 @@ fn generic<T>() {
|
||||
// CHECK: debug dx => [[dx:_.*]];
|
||||
// CHECK: debug dy => [[dy:_.*]];
|
||||
|
||||
// CHECK: [[gx]] = must_use::<usize>(move {{_.*}}) -> {{.*}}
|
||||
// CHECK: [[gx]] = OffsetOf(Gamma<T>, [(0, 0)]);
|
||||
let gx = offset_of!(Gamma<T>, x);
|
||||
|
||||
// CHECK: [[gy]] = must_use::<usize>(move {{_.*}}) -> {{.*}}
|
||||
// CHECK: [[gy]] = OffsetOf(Gamma<T>, [(0, 1)]);
|
||||
let gy = offset_of!(Gamma<T>, y);
|
||||
|
||||
// CHECK: [[dx]] = must_use::<usize>(const 0_usize) -> {{.*}}
|
||||
// CHECK: [[dx]] = const 0_usize
|
||||
let dx = offset_of!(Delta<T>, x);
|
||||
|
||||
// CHECK: [[dy]] = must_use::<usize>(const 2_usize) -> {{.*}}
|
||||
// CHECK: [[dy]] = const 2_usize
|
||||
let dy = offset_of!(Delta<T>, y);
|
||||
}
|
||||
|
||||
|
34
tests/pretty/postfix-match/precedence.pp
Normal file
34
tests/pretty/postfix-match/precedence.pp
Normal file
@ -0,0 +1,34 @@
|
||||
#![feature(prelude_import)]
|
||||
#![no_std]
|
||||
#![feature(postfix_match)]
|
||||
#[prelude_import]
|
||||
use ::std::prelude::rust_2015::*;
|
||||
#[macro_use]
|
||||
extern crate std;
|
||||
|
||||
use std::ops::Add;
|
||||
|
||||
//@ pretty-mode:expanded
|
||||
//@ pp-exact:precedence.pp
|
||||
|
||||
macro_rules! repro { ($e:expr) => { $e.match { _ => {} } }; }
|
||||
|
||||
struct Struct {}
|
||||
|
||||
impl Add<Struct> for usize {
|
||||
type Output = ();
|
||||
fn add(self, _: Struct) -> () { () }
|
||||
}
|
||||
pub fn main() {
|
||||
let a;
|
||||
(
|
||||
{ 1 } + 1).match {
|
||||
_ => {}
|
||||
};
|
||||
(4 as usize).match { _ => {} };
|
||||
(return).match { _ => {} };
|
||||
(a = 42).match { _ => {} };
|
||||
(|| {}).match { _ => {} };
|
||||
(42..101).match { _ => {} };
|
||||
(1 + Struct {}).match { _ => {} };
|
||||
}
|
34
tests/pretty/postfix-match/precedence.rs
Normal file
34
tests/pretty/postfix-match/precedence.rs
Normal file
@ -0,0 +1,34 @@
|
||||
#![feature(postfix_match)]
|
||||
|
||||
use std::ops::Add;
|
||||
|
||||
//@ pretty-mode:expanded
|
||||
//@ pp-exact:precedence.pp
|
||||
|
||||
macro_rules! repro {
|
||||
($e:expr) => {
|
||||
$e.match {
|
||||
_ => {}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
struct Struct {}
|
||||
|
||||
impl Add<Struct> for usize {
|
||||
type Output = ();
|
||||
fn add(self, _: Struct) -> () {
|
||||
()
|
||||
}
|
||||
}
|
||||
pub fn main() {
|
||||
let a;
|
||||
|
||||
repro!({ 1 } + 1);
|
||||
repro!(4 as usize);
|
||||
repro!(return);
|
||||
repro!(a = 42);
|
||||
repro!(|| {});
|
||||
repro!(42..101);
|
||||
repro!(1 + Struct {});
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
// Regression test for issue 123710.
|
||||
// Tests that the we do not ICE in KnownPanicsLint
|
||||
// when a union contains an enum with an repr(packed),
|
||||
// which is a repr not supported for enums
|
||||
|
||||
#[repr(packed)]
|
||||
//~^ ERROR attribute should be applied to a struct or union
|
||||
#[repr(u32)]
|
||||
enum E {
|
||||
A,
|
||||
B,
|
||||
C,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
union InvalidTag {
|
||||
int: u32,
|
||||
e: E,
|
||||
//~^ ERROR field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union
|
||||
}
|
||||
let _invalid_tag = InvalidTag { int: 4 };
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
error[E0517]: attribute should be applied to a struct or union
|
||||
--> $DIR/ice-const-prop-unions-known-panics-lint-123710.rs:6:8
|
||||
|
|
||||
LL | #[repr(packed)]
|
||||
| ^^^^^^
|
||||
...
|
||||
LL | / enum E {
|
||||
LL | | A,
|
||||
LL | | B,
|
||||
LL | | C,
|
||||
LL | | }
|
||||
| |_- not a struct or union
|
||||
|
||||
error[E0740]: field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union
|
||||
--> $DIR/ice-const-prop-unions-known-panics-lint-123710.rs:18:9
|
||||
|
|
||||
LL | e: E,
|
||||
| ^^^^
|
||||
|
|
||||
= note: union fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>`
|
||||
help: wrap the field type in `ManuallyDrop<...>`
|
||||
|
|
||||
LL | e: std::mem::ManuallyDrop<E>,
|
||||
| +++++++++++++++++++++++ +
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0517, E0740.
|
||||
For more information about an error, try `rustc --explain E0517`.
|
@ -34,20 +34,6 @@ LL | offset_of!((u8, dyn Trait), 1);
|
||||
= help: the trait `Sized` is not implemented for `dyn Trait`
|
||||
= note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
|
||||
--> $DIR/offset-of-dst-field.rs:44:5
|
||||
|
|
||||
LL | offset_of!(Delta<Alpha>, z);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
||||
|
|
||||
= help: within `Alpha`, the trait `Sized` is not implemented for `[u8]`, which is required by `Alpha: Sized`
|
||||
note: required because it appears within the type `Alpha`
|
||||
--> $DIR/offset-of-dst-field.rs:5:8
|
||||
|
|
||||
LL | struct Alpha {
|
||||
| ^^^^^
|
||||
= note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error[E0277]: the size for values of type `Extern` cannot be known at compilation time
|
||||
--> $DIR/offset-of-dst-field.rs:45:5
|
||||
|
|
||||
@ -66,6 +52,20 @@ LL | offset_of!(Delta<dyn Trait>, z);
|
||||
= help: the trait `Sized` is not implemented for `dyn Trait`
|
||||
= note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
|
||||
--> $DIR/offset-of-dst-field.rs:44:5
|
||||
|
|
||||
LL | offset_of!(Delta<Alpha>, z);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
||||
|
|
||||
= help: within `Alpha`, the trait `Sized` is not implemented for `[u8]`, which is required by `Alpha: Sized`
|
||||
note: required because it appears within the type `Alpha`
|
||||
--> $DIR/offset-of-dst-field.rs:5:8
|
||||
|
|
||||
LL | struct Alpha {
|
||||
| ^^^^^
|
||||
= note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error[E0277]: the size for values of type `T` cannot be known at compilation time
|
||||
--> $DIR/offset-of-dst-field.rs:50:5
|
||||
|
|
||||
|
@ -4,5 +4,5 @@
|
||||
|
||||
fn main() {
|
||||
core::mem::offset_of!((String,), 0);
|
||||
//~^ WARN unused return value of `must_use` that must be used
|
||||
//~^ WARN unused `offset_of` call that must be used
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
warning: unused return value of `must_use` that must be used
|
||||
warning: unused `offset_of` call that must be used
|
||||
--> $DIR/offset-of-must-use.rs:6:5
|
||||
|
|
||||
LL | core::mem::offset_of!((String,), 0);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the `offset_of` call produces a value
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/offset-of-must-use.rs:3:9
|
||||
|
23
tests/ui/offset-of/offset-of-temporaries.rs
Normal file
23
tests/ui/offset-of/offset-of-temporaries.rs
Normal file
@ -0,0 +1,23 @@
|
||||
//@ build-pass
|
||||
|
||||
//! Regression test #124478.
|
||||
|
||||
use std::mem::offset_of;
|
||||
|
||||
struct S {
|
||||
v: u8,
|
||||
w: u16,
|
||||
}
|
||||
|
||||
impl S {
|
||||
fn return_static_slice() -> &'static [usize] {
|
||||
&[offset_of!(Self, v), offset_of!(Self, w)]
|
||||
}
|
||||
fn use_reference() -> usize {
|
||||
let r = &offset_of!(Self, v);
|
||||
*r * 6
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
}
|
@ -9,7 +9,7 @@ pub struct Lint {
|
||||
pub name: &'static str,
|
||||
pub desc: &'static str,
|
||||
pub report_in_external_macro: bool,
|
||||
pub is_loaded: bool,
|
||||
pub is_externally_loaded: bool,
|
||||
pub crate_level_only: bool,
|
||||
}
|
||||
|
||||
@ -17,7 +17,7 @@ static FOO: &Lint = &Lint {
|
||||
name: &"foo",
|
||||
desc: "desc",
|
||||
report_in_external_macro: false,
|
||||
is_loaded: true,
|
||||
is_externally_loaded: true,
|
||||
crate_level_only: false,
|
||||
};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user