Auto merge of #127796 - tgross35:rollup-ubo5hzb, r=tgross35
Rollup of 6 pull requests Successful merges: - #120990 (Suggest a borrow when using dbg) - #127047 (fix least significant digits of f128 associated constants) - #127709 (match lowering: Move `MatchPair` tree creation to its own module) - #127770 (Update books) - #127780 (Make sure trait def ids match before zipping args in `note_function_argument_obligation`) - #127795 (Fix typos in RELEASES.md) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
5572759b8d
19 changed files with 635 additions and 280 deletions
|
@ -67,7 +67,7 @@ Stabilized APIs
|
|||
- [`NonNull::byte_add`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.byte_add)
|
||||
- [`NonNull::sub`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.sub)
|
||||
- [`NonNull::byte_sub`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.byte_sub)
|
||||
- [`NonNull:offset_from`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.offset_from)
|
||||
- [`NonNull::offset_from`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.offset_from)
|
||||
- [`NonNull::byte_offset_from`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.byte_offset_from)
|
||||
- [`NonNull::read`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.read)
|
||||
- [`NonNull::read_volatile`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.read_volatile)
|
||||
|
@ -91,9 +91,9 @@ Stabilized APIs
|
|||
- [`str::trim_ascii`](https://doc.rust-lang.org/beta/std/primitive.str.html#method.trim_ascii)
|
||||
- [`str::trim_ascii_start`](https://doc.rust-lang.org/beta/std/primitive.str.html#method.trim_ascii_start)
|
||||
- [`str::trim_ascii_end`](https://doc.rust-lang.org/beta/std/primitive.str.html#method.trim_ascii_end)
|
||||
- [`<[AsciiChar]>::trim_ascii`](https://doc.rust-lang.org/beta/core/primitive.slice.html#method.trim_ascii)
|
||||
- [`<[AsciiChar]>::trim_ascii_start`](https://doc.rust-lang.org/beta/core/primitive.slice.html#method.trim_ascii_start)
|
||||
- [`<[AsciiChar]>::trim_ascii_end`](https://doc.rust-lang.org/beta/core/primitive.slice.html#method.trim_ascii_end)
|
||||
- [`<[u8]>::trim_ascii`](https://doc.rust-lang.org/beta/core/primitive.slice.html#method.trim_ascii)
|
||||
- [`<[u8]>::trim_ascii_start`](https://doc.rust-lang.org/beta/core/primitive.slice.html#method.trim_ascii_start)
|
||||
- [`<[u8]>::trim_ascii_end`](https://doc.rust-lang.org/beta/core/primitive.slice.html#method.trim_ascii_end)
|
||||
- [`Ipv4Addr::BITS`](https://doc.rust-lang.org/beta/core/net/struct.Ipv4Addr.html#associatedconstant.BITS)
|
||||
- [`Ipv4Addr::to_bits`](https://doc.rust-lang.org/beta/core/net/struct.Ipv4Addr.html#method.to_bits)
|
||||
- [`Ipv4Addr::from_bits`](https://doc.rust-lang.org/beta/core/net/struct.Ipv4Addr.html#method.from_bits)
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
#![allow(rustc::untranslatable_diagnostic)]
|
||||
|
||||
use either::Either;
|
||||
use hir::ClosureKind;
|
||||
use hir::{ClosureKind, Path};
|
||||
use rustc_data_structures::captures::Captures;
|
||||
use rustc_data_structures::fx::FxIndexSet;
|
||||
use rustc_errors::{codes::*, struct_span_code_err, Applicability, Diag, MultiSpan};
|
||||
|
@ -16,6 +16,7 @@ use rustc_hir::{CoroutineKind, CoroutineSource, LangItem};
|
|||
use rustc_middle::bug;
|
||||
use rustc_middle::hir::nested_filter::OnlyBodies;
|
||||
use rustc_middle::mir::tcx::PlaceTy;
|
||||
use rustc_middle::mir::VarDebugInfoContents;
|
||||
use rustc_middle::mir::{
|
||||
self, AggregateKind, BindingForm, BorrowKind, CallSource, ClearCrossCrate, ConstraintCategory,
|
||||
FakeBorrowKind, FakeReadCause, LocalDecl, LocalInfo, LocalKind, Location, MutBorrowKind,
|
||||
|
@ -546,7 +547,14 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
|
|||
self.suggest_cloning(err, ty, expr, None, Some(move_spans));
|
||||
}
|
||||
}
|
||||
if let Some(pat) = finder.pat {
|
||||
|
||||
self.suggest_ref_for_dbg_args(expr, place, move_span, err);
|
||||
|
||||
// it's useless to suggest inserting `ref` when the span don't comes from local code
|
||||
if let Some(pat) = finder.pat
|
||||
&& !move_span.is_dummy()
|
||||
&& !self.infcx.tcx.sess.source_map().is_imported(move_span)
|
||||
{
|
||||
*in_pattern = true;
|
||||
let mut sugg = vec![(pat.span.shrink_to_lo(), "ref ".to_string())];
|
||||
if let Some(pat) = finder.parent_pat {
|
||||
|
@ -561,6 +569,59 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
// for dbg!(x) which may take ownership, suggest dbg!(&x) instead
|
||||
// but here we actually do not check whether the macro name is `dbg!`
|
||||
// so that we may extend the scope a bit larger to cover more cases
|
||||
fn suggest_ref_for_dbg_args(
|
||||
&self,
|
||||
body: &hir::Expr<'_>,
|
||||
place: &Place<'tcx>,
|
||||
move_span: Span,
|
||||
err: &mut Diag<'infcx>,
|
||||
) {
|
||||
let var_info = self.body.var_debug_info.iter().find(|info| match info.value {
|
||||
VarDebugInfoContents::Place(ref p) => p == place,
|
||||
_ => false,
|
||||
});
|
||||
let arg_name = if let Some(var_info) = var_info {
|
||||
var_info.name
|
||||
} else {
|
||||
return;
|
||||
};
|
||||
struct MatchArgFinder {
|
||||
expr_span: Span,
|
||||
match_arg_span: Option<Span>,
|
||||
arg_name: Symbol,
|
||||
}
|
||||
impl Visitor<'_> for MatchArgFinder {
|
||||
fn visit_expr(&mut self, e: &hir::Expr<'_>) {
|
||||
// dbg! is expanded into a match pattern, we need to find the right argument span
|
||||
if let hir::ExprKind::Match(expr, ..) = &e.kind
|
||||
&& let hir::ExprKind::Path(hir::QPath::Resolved(
|
||||
_,
|
||||
path @ Path { segments: [seg], .. },
|
||||
)) = &expr.kind
|
||||
&& seg.ident.name == self.arg_name
|
||||
&& self.expr_span.source_callsite().contains(expr.span)
|
||||
{
|
||||
self.match_arg_span = Some(path.span);
|
||||
}
|
||||
hir::intravisit::walk_expr(self, e);
|
||||
}
|
||||
}
|
||||
|
||||
let mut finder = MatchArgFinder { expr_span: move_span, match_arg_span: None, arg_name };
|
||||
finder.visit_expr(body);
|
||||
if let Some(macro_arg_span) = finder.match_arg_span {
|
||||
err.span_suggestion_verbose(
|
||||
macro_arg_span.shrink_to_lo(),
|
||||
"consider borrowing instead of transferring ownership",
|
||||
"&",
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn report_use_of_uninitialized(
|
||||
&self,
|
||||
mpi: MovePathIndex,
|
||||
|
|
254
compiler/rustc_mir_build/src/build/matches/match_pair.rs
Normal file
254
compiler/rustc_mir_build/src/build/matches/match_pair.rs
Normal file
|
@ -0,0 +1,254 @@
|
|||
use rustc_middle::mir::*;
|
||||
use rustc_middle::thir::{self, *};
|
||||
use rustc_middle::ty::{self, Ty, TypeVisitableExt};
|
||||
|
||||
use crate::build::expr::as_place::{PlaceBase, PlaceBuilder};
|
||||
use crate::build::matches::{FlatPat, MatchPair, TestCase};
|
||||
use crate::build::Builder;
|
||||
|
||||
impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
/// Builds and returns [`MatchPair`] trees, one for each pattern in
|
||||
/// `subpatterns`, representing the fields of a [`PatKind::Variant`] or
|
||||
/// [`PatKind::Leaf`].
|
||||
///
|
||||
/// Used internally by [`MatchPair::new`].
|
||||
fn field_match_pairs<'pat>(
|
||||
&mut self,
|
||||
place: PlaceBuilder<'tcx>,
|
||||
subpatterns: &'pat [FieldPat<'tcx>],
|
||||
) -> Vec<MatchPair<'pat, 'tcx>> {
|
||||
subpatterns
|
||||
.iter()
|
||||
.map(|fieldpat| {
|
||||
let place =
|
||||
place.clone_project(PlaceElem::Field(fieldpat.field, fieldpat.pattern.ty));
|
||||
MatchPair::new(place, &fieldpat.pattern, self)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Builds [`MatchPair`] trees for the prefix/middle/suffix parts of an
|
||||
/// array pattern or slice pattern, and adds those trees to `match_pairs`.
|
||||
///
|
||||
/// Used internally by [`MatchPair::new`].
|
||||
fn prefix_slice_suffix<'pat>(
|
||||
&mut self,
|
||||
match_pairs: &mut Vec<MatchPair<'pat, 'tcx>>,
|
||||
place: &PlaceBuilder<'tcx>,
|
||||
prefix: &'pat [Box<Pat<'tcx>>],
|
||||
opt_slice: &'pat Option<Box<Pat<'tcx>>>,
|
||||
suffix: &'pat [Box<Pat<'tcx>>],
|
||||
) {
|
||||
let tcx = self.tcx;
|
||||
let (min_length, exact_size) = if let Some(place_resolved) = place.try_to_place(self) {
|
||||
match place_resolved.ty(&self.local_decls, tcx).ty.kind() {
|
||||
ty::Array(_, length) => (length.eval_target_usize(tcx, self.param_env), true),
|
||||
_ => ((prefix.len() + suffix.len()).try_into().unwrap(), false),
|
||||
}
|
||||
} else {
|
||||
((prefix.len() + suffix.len()).try_into().unwrap(), false)
|
||||
};
|
||||
|
||||
match_pairs.extend(prefix.iter().enumerate().map(|(idx, subpattern)| {
|
||||
let elem =
|
||||
ProjectionElem::ConstantIndex { offset: idx as u64, min_length, from_end: false };
|
||||
MatchPair::new(place.clone_project(elem), subpattern, self)
|
||||
}));
|
||||
|
||||
if let Some(subslice_pat) = opt_slice {
|
||||
let suffix_len = suffix.len() as u64;
|
||||
let subslice = place.clone_project(PlaceElem::Subslice {
|
||||
from: prefix.len() as u64,
|
||||
to: if exact_size { min_length - suffix_len } else { suffix_len },
|
||||
from_end: !exact_size,
|
||||
});
|
||||
match_pairs.push(MatchPair::new(subslice, subslice_pat, self));
|
||||
}
|
||||
|
||||
match_pairs.extend(suffix.iter().rev().enumerate().map(|(idx, subpattern)| {
|
||||
let end_offset = (idx + 1) as u64;
|
||||
let elem = ProjectionElem::ConstantIndex {
|
||||
offset: if exact_size { min_length - end_offset } else { end_offset },
|
||||
min_length,
|
||||
from_end: !exact_size,
|
||||
};
|
||||
let place = place.clone_project(elem);
|
||||
MatchPair::new(place, subpattern, self)
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
impl<'pat, 'tcx> MatchPair<'pat, 'tcx> {
|
||||
/// Recursively builds a `MatchPair` tree for the given pattern and its
|
||||
/// subpatterns.
|
||||
pub(in crate::build) fn new(
|
||||
mut place_builder: PlaceBuilder<'tcx>,
|
||||
pattern: &'pat Pat<'tcx>,
|
||||
cx: &mut Builder<'_, 'tcx>,
|
||||
) -> MatchPair<'pat, 'tcx> {
|
||||
// Force the place type to the pattern's type.
|
||||
// FIXME(oli-obk): can we use this to simplify slice/array pattern hacks?
|
||||
if let Some(resolved) = place_builder.resolve_upvar(cx) {
|
||||
place_builder = resolved;
|
||||
}
|
||||
|
||||
// Only add the OpaqueCast projection if the given place is an opaque type and the
|
||||
// expected type from the pattern is not.
|
||||
let may_need_cast = match place_builder.base() {
|
||||
PlaceBase::Local(local) => {
|
||||
let ty =
|
||||
Place::ty_from(local, place_builder.projection(), &cx.local_decls, cx.tcx).ty;
|
||||
ty != pattern.ty && ty.has_opaque_types()
|
||||
}
|
||||
_ => true,
|
||||
};
|
||||
if may_need_cast {
|
||||
place_builder = place_builder.project(ProjectionElem::OpaqueCast(pattern.ty));
|
||||
}
|
||||
|
||||
let place = place_builder.try_to_place(cx);
|
||||
let default_irrefutable = || TestCase::Irrefutable { binding: None, ascription: None };
|
||||
let mut subpairs = Vec::new();
|
||||
let test_case = match pattern.kind {
|
||||
PatKind::Wild | PatKind::Error(_) => default_irrefutable(),
|
||||
|
||||
PatKind::Or { ref pats } => TestCase::Or {
|
||||
pats: pats.iter().map(|pat| FlatPat::new(place_builder.clone(), pat, cx)).collect(),
|
||||
},
|
||||
|
||||
PatKind::Range(ref range) => {
|
||||
if range.is_full_range(cx.tcx) == Some(true) {
|
||||
default_irrefutable()
|
||||
} else {
|
||||
TestCase::Range(range)
|
||||
}
|
||||
}
|
||||
|
||||
PatKind::Constant { value } => TestCase::Constant { value },
|
||||
|
||||
PatKind::AscribeUserType {
|
||||
ascription: thir::Ascription { ref annotation, variance },
|
||||
ref subpattern,
|
||||
..
|
||||
} => {
|
||||
// Apply the type ascription to the value at `match_pair.place`
|
||||
let ascription = place.map(|source| super::Ascription {
|
||||
annotation: annotation.clone(),
|
||||
source,
|
||||
variance,
|
||||
});
|
||||
|
||||
subpairs.push(MatchPair::new(place_builder, subpattern, cx));
|
||||
TestCase::Irrefutable { ascription, binding: None }
|
||||
}
|
||||
|
||||
PatKind::Binding { mode, var, ref subpattern, .. } => {
|
||||
let binding = place.map(|source| super::Binding {
|
||||
span: pattern.span,
|
||||
source,
|
||||
var_id: var,
|
||||
binding_mode: mode,
|
||||
});
|
||||
|
||||
if let Some(subpattern) = subpattern.as_ref() {
|
||||
// this is the `x @ P` case; have to keep matching against `P` now
|
||||
subpairs.push(MatchPair::new(place_builder, subpattern, cx));
|
||||
}
|
||||
TestCase::Irrefutable { ascription: None, binding }
|
||||
}
|
||||
|
||||
PatKind::InlineConstant { subpattern: ref pattern, def, .. } => {
|
||||
// Apply a type ascription for the inline constant to the value at `match_pair.place`
|
||||
let ascription = place.map(|source| {
|
||||
let span = pattern.span;
|
||||
let parent_id = cx.tcx.typeck_root_def_id(cx.def_id.to_def_id());
|
||||
let args = ty::InlineConstArgs::new(
|
||||
cx.tcx,
|
||||
ty::InlineConstArgsParts {
|
||||
parent_args: ty::GenericArgs::identity_for_item(cx.tcx, parent_id),
|
||||
ty: cx.infcx.next_ty_var(span),
|
||||
},
|
||||
)
|
||||
.args;
|
||||
let user_ty = cx.infcx.canonicalize_user_type_annotation(ty::UserType::TypeOf(
|
||||
def.to_def_id(),
|
||||
ty::UserArgs { args, user_self_ty: None },
|
||||
));
|
||||
let annotation = ty::CanonicalUserTypeAnnotation {
|
||||
inferred_ty: pattern.ty,
|
||||
span,
|
||||
user_ty: Box::new(user_ty),
|
||||
};
|
||||
super::Ascription { annotation, source, variance: ty::Contravariant }
|
||||
});
|
||||
|
||||
subpairs.push(MatchPair::new(place_builder, pattern, cx));
|
||||
TestCase::Irrefutable { ascription, binding: None }
|
||||
}
|
||||
|
||||
PatKind::Array { ref prefix, ref slice, ref suffix } => {
|
||||
cx.prefix_slice_suffix(&mut subpairs, &place_builder, prefix, slice, suffix);
|
||||
default_irrefutable()
|
||||
}
|
||||
PatKind::Slice { ref prefix, ref slice, ref suffix } => {
|
||||
cx.prefix_slice_suffix(&mut subpairs, &place_builder, prefix, slice, suffix);
|
||||
|
||||
if prefix.is_empty() && slice.is_some() && suffix.is_empty() {
|
||||
default_irrefutable()
|
||||
} else {
|
||||
TestCase::Slice {
|
||||
len: prefix.len() + suffix.len(),
|
||||
variable_length: slice.is_some(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PatKind::Variant { adt_def, variant_index, args, ref subpatterns } => {
|
||||
let downcast_place = place_builder.downcast(adt_def, variant_index); // `(x as Variant)`
|
||||
subpairs = cx.field_match_pairs(downcast_place, subpatterns);
|
||||
|
||||
let irrefutable = adt_def.variants().iter_enumerated().all(|(i, v)| {
|
||||
i == variant_index || {
|
||||
(cx.tcx.features().exhaustive_patterns
|
||||
|| cx.tcx.features().min_exhaustive_patterns)
|
||||
&& !v
|
||||
.inhabited_predicate(cx.tcx, adt_def)
|
||||
.instantiate(cx.tcx, args)
|
||||
.apply_ignore_module(cx.tcx, cx.param_env)
|
||||
}
|
||||
}) && (adt_def.did().is_local()
|
||||
|| !adt_def.is_variant_list_non_exhaustive());
|
||||
if irrefutable {
|
||||
default_irrefutable()
|
||||
} else {
|
||||
TestCase::Variant { adt_def, variant_index }
|
||||
}
|
||||
}
|
||||
|
||||
PatKind::Leaf { ref subpatterns } => {
|
||||
subpairs = cx.field_match_pairs(place_builder, subpatterns);
|
||||
default_irrefutable()
|
||||
}
|
||||
|
||||
PatKind::Deref { ref subpattern } => {
|
||||
subpairs.push(MatchPair::new(place_builder.deref(), subpattern, cx));
|
||||
default_irrefutable()
|
||||
}
|
||||
|
||||
PatKind::DerefPattern { ref subpattern, mutability } => {
|
||||
// Create a new temporary for each deref pattern.
|
||||
// FIXME(deref_patterns): dedup temporaries to avoid multiple `deref()` calls?
|
||||
let temp = cx.temp(
|
||||
Ty::new_ref(cx.tcx, cx.tcx.lifetimes.re_erased, subpattern.ty, mutability),
|
||||
pattern.span,
|
||||
);
|
||||
subpairs.push(MatchPair::new(PlaceBuilder::from(temp).deref(), subpattern, cx));
|
||||
TestCase::Deref { temp, mutability }
|
||||
}
|
||||
|
||||
PatKind::Never => TestCase::Never,
|
||||
};
|
||||
|
||||
MatchPair { place, test_case, subpairs, pattern }
|
||||
}
|
||||
}
|
|
@ -24,6 +24,7 @@ use tracing::{debug, instrument};
|
|||
use util::visit_bindings;
|
||||
|
||||
// helper functions, broken out by category:
|
||||
mod match_pair;
|
||||
mod simplify;
|
||||
mod test;
|
||||
mod util;
|
||||
|
@ -1195,17 +1196,27 @@ impl<'pat, 'tcx> TestCase<'pat, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Node in a tree of "match pairs", where each pair consists of a place to be
|
||||
/// tested, and a test to perform on that place.
|
||||
///
|
||||
/// Each node also has a list of subpairs (possibly empty) that must also match,
|
||||
/// and a reference to the THIR pattern it represents.
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct MatchPair<'pat, 'tcx> {
|
||||
/// This place...
|
||||
// This can be `None` if it referred to a non-captured place in a closure.
|
||||
// Invariant: place.is_none() => test_case is Irrefutable
|
||||
// In other words this must be `Some(_)` after simplification.
|
||||
///
|
||||
/// ---
|
||||
/// This can be `None` if it referred to a non-captured place in a closure.
|
||||
///
|
||||
/// Invariant: Can only be `None` when `test_case` is `Irrefutable`.
|
||||
/// Therefore this must be `Some(_)` after simplification.
|
||||
place: Option<Place<'tcx>>,
|
||||
|
||||
/// ... must pass this test...
|
||||
// Invariant: after creation and simplification in `Candidate::new()`, this must not be
|
||||
// `Irrefutable`.
|
||||
///
|
||||
/// ---
|
||||
/// Invariant: after creation and simplification in [`FlatPat::new`],
|
||||
/// this must not be [`TestCase::Irrefutable`].
|
||||
test_case: TestCase<'pat, 'tcx>,
|
||||
|
||||
/// ... and these subpairs must match.
|
||||
|
|
|
@ -1,78 +1,15 @@
|
|||
use std::marker::PhantomData;
|
||||
|
||||
use crate::build::expr::as_place::{PlaceBase, PlaceBuilder};
|
||||
use crate::build::expr::as_place::PlaceBase;
|
||||
use crate::build::matches::{Binding, Candidate, FlatPat, MatchPair, TestCase};
|
||||
use crate::build::Builder;
|
||||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_middle::mir::*;
|
||||
use rustc_middle::thir::{self, *};
|
||||
use rustc_middle::ty::TypeVisitableExt;
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
use rustc_middle::ty::Ty;
|
||||
use rustc_span::Span;
|
||||
use tracing::debug;
|
||||
|
||||
impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
pub(crate) fn field_match_pairs<'pat>(
|
||||
&mut self,
|
||||
place: PlaceBuilder<'tcx>,
|
||||
subpatterns: &'pat [FieldPat<'tcx>],
|
||||
) -> Vec<MatchPair<'pat, 'tcx>> {
|
||||
subpatterns
|
||||
.iter()
|
||||
.map(|fieldpat| {
|
||||
let place =
|
||||
place.clone_project(PlaceElem::Field(fieldpat.field, fieldpat.pattern.ty));
|
||||
MatchPair::new(place, &fieldpat.pattern, self)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub(crate) fn prefix_slice_suffix<'pat>(
|
||||
&mut self,
|
||||
match_pairs: &mut Vec<MatchPair<'pat, 'tcx>>,
|
||||
place: &PlaceBuilder<'tcx>,
|
||||
prefix: &'pat [Box<Pat<'tcx>>],
|
||||
opt_slice: &'pat Option<Box<Pat<'tcx>>>,
|
||||
suffix: &'pat [Box<Pat<'tcx>>],
|
||||
) {
|
||||
let tcx = self.tcx;
|
||||
let (min_length, exact_size) = if let Some(place_resolved) = place.try_to_place(self) {
|
||||
match place_resolved.ty(&self.local_decls, tcx).ty.kind() {
|
||||
ty::Array(_, length) => (length.eval_target_usize(tcx, self.param_env), true),
|
||||
_ => ((prefix.len() + suffix.len()).try_into().unwrap(), false),
|
||||
}
|
||||
} else {
|
||||
((prefix.len() + suffix.len()).try_into().unwrap(), false)
|
||||
};
|
||||
|
||||
match_pairs.extend(prefix.iter().enumerate().map(|(idx, subpattern)| {
|
||||
let elem =
|
||||
ProjectionElem::ConstantIndex { offset: idx as u64, min_length, from_end: false };
|
||||
MatchPair::new(place.clone_project(elem), subpattern, self)
|
||||
}));
|
||||
|
||||
if let Some(subslice_pat) = opt_slice {
|
||||
let suffix_len = suffix.len() as u64;
|
||||
let subslice = place.clone_project(PlaceElem::Subslice {
|
||||
from: prefix.len() as u64,
|
||||
to: if exact_size { min_length - suffix_len } else { suffix_len },
|
||||
from_end: !exact_size,
|
||||
});
|
||||
match_pairs.push(MatchPair::new(subslice, subslice_pat, self));
|
||||
}
|
||||
|
||||
match_pairs.extend(suffix.iter().rev().enumerate().map(|(idx, subpattern)| {
|
||||
let end_offset = (idx + 1) as u64;
|
||||
let elem = ProjectionElem::ConstantIndex {
|
||||
offset: if exact_size { min_length - end_offset } else { end_offset },
|
||||
min_length,
|
||||
from_end: !exact_size,
|
||||
};
|
||||
let place = place.clone_project(elem);
|
||||
MatchPair::new(place, subpattern, self)
|
||||
}));
|
||||
}
|
||||
|
||||
/// Creates a false edge to `imaginary_target` and a real edge to
|
||||
/// real_target. If `imaginary_target` is none, or is the same as the real
|
||||
/// target, a Goto is generated instead to simplify the generated MIR.
|
||||
|
@ -96,181 +33,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'pat, 'tcx> MatchPair<'pat, 'tcx> {
|
||||
/// Recursively builds a `MatchPair` tree for the given pattern and its
|
||||
/// subpatterns.
|
||||
pub(in crate::build) fn new(
|
||||
mut place_builder: PlaceBuilder<'tcx>,
|
||||
pattern: &'pat Pat<'tcx>,
|
||||
cx: &mut Builder<'_, 'tcx>,
|
||||
) -> MatchPair<'pat, 'tcx> {
|
||||
// Force the place type to the pattern's type.
|
||||
// FIXME(oli-obk): can we use this to simplify slice/array pattern hacks?
|
||||
if let Some(resolved) = place_builder.resolve_upvar(cx) {
|
||||
place_builder = resolved;
|
||||
}
|
||||
|
||||
// Only add the OpaqueCast projection if the given place is an opaque type and the
|
||||
// expected type from the pattern is not.
|
||||
let may_need_cast = match place_builder.base() {
|
||||
PlaceBase::Local(local) => {
|
||||
let ty =
|
||||
Place::ty_from(local, place_builder.projection(), &cx.local_decls, cx.tcx).ty;
|
||||
ty != pattern.ty && ty.has_opaque_types()
|
||||
}
|
||||
_ => true,
|
||||
};
|
||||
if may_need_cast {
|
||||
place_builder = place_builder.project(ProjectionElem::OpaqueCast(pattern.ty));
|
||||
}
|
||||
|
||||
let place = place_builder.try_to_place(cx);
|
||||
let default_irrefutable = || TestCase::Irrefutable { binding: None, ascription: None };
|
||||
let mut subpairs = Vec::new();
|
||||
let test_case = match pattern.kind {
|
||||
PatKind::Wild | PatKind::Error(_) => default_irrefutable(),
|
||||
|
||||
PatKind::Or { ref pats } => TestCase::Or {
|
||||
pats: pats.iter().map(|pat| FlatPat::new(place_builder.clone(), pat, cx)).collect(),
|
||||
},
|
||||
|
||||
PatKind::Range(ref range) => {
|
||||
if range.is_full_range(cx.tcx) == Some(true) {
|
||||
default_irrefutable()
|
||||
} else {
|
||||
TestCase::Range(range)
|
||||
}
|
||||
}
|
||||
|
||||
PatKind::Constant { value } => TestCase::Constant { value },
|
||||
|
||||
PatKind::AscribeUserType {
|
||||
ascription: thir::Ascription { ref annotation, variance },
|
||||
ref subpattern,
|
||||
..
|
||||
} => {
|
||||
// Apply the type ascription to the value at `match_pair.place`
|
||||
let ascription = place.map(|source| super::Ascription {
|
||||
annotation: annotation.clone(),
|
||||
source,
|
||||
variance,
|
||||
});
|
||||
|
||||
subpairs.push(MatchPair::new(place_builder, subpattern, cx));
|
||||
TestCase::Irrefutable { ascription, binding: None }
|
||||
}
|
||||
|
||||
PatKind::Binding { mode, var, ref subpattern, .. } => {
|
||||
let binding = place.map(|source| super::Binding {
|
||||
span: pattern.span,
|
||||
source,
|
||||
var_id: var,
|
||||
binding_mode: mode,
|
||||
});
|
||||
|
||||
if let Some(subpattern) = subpattern.as_ref() {
|
||||
// this is the `x @ P` case; have to keep matching against `P` now
|
||||
subpairs.push(MatchPair::new(place_builder, subpattern, cx));
|
||||
}
|
||||
TestCase::Irrefutable { ascription: None, binding }
|
||||
}
|
||||
|
||||
PatKind::InlineConstant { subpattern: ref pattern, def, .. } => {
|
||||
// Apply a type ascription for the inline constant to the value at `match_pair.place`
|
||||
let ascription = place.map(|source| {
|
||||
let span = pattern.span;
|
||||
let parent_id = cx.tcx.typeck_root_def_id(cx.def_id.to_def_id());
|
||||
let args = ty::InlineConstArgs::new(
|
||||
cx.tcx,
|
||||
ty::InlineConstArgsParts {
|
||||
parent_args: ty::GenericArgs::identity_for_item(cx.tcx, parent_id),
|
||||
ty: cx.infcx.next_ty_var(span),
|
||||
},
|
||||
)
|
||||
.args;
|
||||
let user_ty = cx.infcx.canonicalize_user_type_annotation(ty::UserType::TypeOf(
|
||||
def.to_def_id(),
|
||||
ty::UserArgs { args, user_self_ty: None },
|
||||
));
|
||||
let annotation = ty::CanonicalUserTypeAnnotation {
|
||||
inferred_ty: pattern.ty,
|
||||
span,
|
||||
user_ty: Box::new(user_ty),
|
||||
};
|
||||
super::Ascription { annotation, source, variance: ty::Contravariant }
|
||||
});
|
||||
|
||||
subpairs.push(MatchPair::new(place_builder, pattern, cx));
|
||||
TestCase::Irrefutable { ascription, binding: None }
|
||||
}
|
||||
|
||||
PatKind::Array { ref prefix, ref slice, ref suffix } => {
|
||||
cx.prefix_slice_suffix(&mut subpairs, &place_builder, prefix, slice, suffix);
|
||||
default_irrefutable()
|
||||
}
|
||||
PatKind::Slice { ref prefix, ref slice, ref suffix } => {
|
||||
cx.prefix_slice_suffix(&mut subpairs, &place_builder, prefix, slice, suffix);
|
||||
|
||||
if prefix.is_empty() && slice.is_some() && suffix.is_empty() {
|
||||
default_irrefutable()
|
||||
} else {
|
||||
TestCase::Slice {
|
||||
len: prefix.len() + suffix.len(),
|
||||
variable_length: slice.is_some(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PatKind::Variant { adt_def, variant_index, args, ref subpatterns } => {
|
||||
let downcast_place = place_builder.downcast(adt_def, variant_index); // `(x as Variant)`
|
||||
subpairs = cx.field_match_pairs(downcast_place, subpatterns);
|
||||
|
||||
let irrefutable = adt_def.variants().iter_enumerated().all(|(i, v)| {
|
||||
i == variant_index || {
|
||||
(cx.tcx.features().exhaustive_patterns
|
||||
|| cx.tcx.features().min_exhaustive_patterns)
|
||||
&& !v
|
||||
.inhabited_predicate(cx.tcx, adt_def)
|
||||
.instantiate(cx.tcx, args)
|
||||
.apply_ignore_module(cx.tcx, cx.param_env)
|
||||
}
|
||||
}) && (adt_def.did().is_local()
|
||||
|| !adt_def.is_variant_list_non_exhaustive());
|
||||
if irrefutable {
|
||||
default_irrefutable()
|
||||
} else {
|
||||
TestCase::Variant { adt_def, variant_index }
|
||||
}
|
||||
}
|
||||
|
||||
PatKind::Leaf { ref subpatterns } => {
|
||||
subpairs = cx.field_match_pairs(place_builder, subpatterns);
|
||||
default_irrefutable()
|
||||
}
|
||||
|
||||
PatKind::Deref { ref subpattern } => {
|
||||
subpairs.push(MatchPair::new(place_builder.deref(), subpattern, cx));
|
||||
default_irrefutable()
|
||||
}
|
||||
|
||||
PatKind::DerefPattern { ref subpattern, mutability } => {
|
||||
// Create a new temporary for each deref pattern.
|
||||
// FIXME(deref_patterns): dedup temporaries to avoid multiple `deref()` calls?
|
||||
let temp = cx.temp(
|
||||
Ty::new_ref(cx.tcx, cx.tcx.lifetimes.re_erased, subpattern.ty, mutability),
|
||||
pattern.span,
|
||||
);
|
||||
subpairs.push(MatchPair::new(PlaceBuilder::from(temp).deref(), subpattern, cx));
|
||||
TestCase::Deref { temp, mutability }
|
||||
}
|
||||
|
||||
PatKind::Never => TestCase::Never,
|
||||
};
|
||||
|
||||
MatchPair { place, test_case, subpairs, pattern }
|
||||
}
|
||||
}
|
||||
|
||||
/// Determine the set of places that have to be stable across match guards.
|
||||
///
|
||||
/// Returns a list of places that need a fake borrow along with a local to store it.
|
||||
|
|
|
@ -3810,6 +3810,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
{
|
||||
if let Some(where_pred) = where_pred.as_trait_clause()
|
||||
&& let Some(failed_pred) = failed_pred.as_trait_clause()
|
||||
&& where_pred.def_id() == failed_pred.def_id()
|
||||
{
|
||||
self.enter_forall(where_pred, |where_pred| {
|
||||
let failed_pred = self.instantiate_binder_with_fresh_vars(
|
||||
|
|
|
@ -170,7 +170,7 @@ impl f128 {
|
|||
/// [Machine epsilon]: https://en.wikipedia.org/wiki/Machine_epsilon
|
||||
/// [`MANTISSA_DIGITS`]: f128::MANTISSA_DIGITS
|
||||
#[unstable(feature = "f128", issue = "116909")]
|
||||
pub const EPSILON: f128 = 1.92592994438723585305597794258492731e-34_f128;
|
||||
pub const EPSILON: f128 = 1.92592994438723585305597794258492732e-34_f128;
|
||||
|
||||
/// Smallest finite `f128` value.
|
||||
///
|
||||
|
@ -178,7 +178,7 @@ impl f128 {
|
|||
///
|
||||
/// [`MAX`]: f128::MAX
|
||||
#[unstable(feature = "f128", issue = "116909")]
|
||||
pub const MIN: f128 = -1.18973149535723176508575932662800701e+4932_f128;
|
||||
pub const MIN: f128 = -1.18973149535723176508575932662800702e+4932_f128;
|
||||
/// Smallest positive normal `f128` value.
|
||||
///
|
||||
/// Equal to 2<sup>[`MIN_EXP`] − 1</sup>.
|
||||
|
@ -194,7 +194,7 @@ impl f128 {
|
|||
/// [`MANTISSA_DIGITS`]: f128::MANTISSA_DIGITS
|
||||
/// [`MAX_EXP`]: f128::MAX_EXP
|
||||
#[unstable(feature = "f128", issue = "116909")]
|
||||
pub const MAX: f128 = 1.18973149535723176508575932662800701e+4932_f128;
|
||||
pub const MAX: f128 = 1.18973149535723176508575932662800702e+4932_f128;
|
||||
|
||||
/// One greater than the minimum possible normal power of 2 exponent.
|
||||
///
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit f1e49bf7a8ea6c31ce016a52b8a4f6e1ffcfbc64
|
||||
Subproject commit 67fa536768013d9d5a13f3a06790521d511ef711
|
|
@ -1 +1 @@
|
|||
Subproject commit 941db8b3df45fd46cd87b50a5c86714b91dcde9c
|
||||
Subproject commit 5454de3d12b9ccc6375b629cf7ccda8264640aac
|
|
@ -1 +1 @@
|
|||
Subproject commit b10c6acaf0f43481f6600e95d4b5013446e29f7a
|
||||
Subproject commit 019f3928d8b939ec71b63722dcc2e46330156441
|
|
@ -1 +1 @@
|
|||
Subproject commit 1ae3deebc3ac16e276b6558e01420f8e605def08
|
||||
Subproject commit e2f0bdc4031866734661dcdb548184bde1450baf
|
|
@ -1 +1 @@
|
|||
Subproject commit 658c6c27cb975b92227936024816986c2d3716fb
|
||||
Subproject commit 89aecb6951b77bc746da73df8c9f2b2ceaad494a
|
|
@ -1 +1 @@
|
|||
Subproject commit d6e3a32a557db5902e714604def8015d6bb7e0f7
|
||||
Subproject commit 0c4d55cb59fe440d1a630e4e5774d043968edb3f
|
|
@ -1,20 +0,0 @@
|
|||
//@ known-bug: rust-lang/rust#126416
|
||||
|
||||
trait Output<'a, T: 'a> {
|
||||
type Type;
|
||||
}
|
||||
|
||||
struct Wrapper;
|
||||
|
||||
impl Wrapper {
|
||||
fn do_something_wrapper<O, F>(&mut self, _: F)
|
||||
where
|
||||
F: for<'a> FnOnce(<F as Output<i32>>::Type),
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut wrapper = Wrapper;
|
||||
wrapper.do_something_wrapper(|value| ());
|
||||
}
|
68
tests/ui/borrowck/dbg-issue-120327.rs
Normal file
68
tests/ui/borrowck/dbg-issue-120327.rs
Normal file
|
@ -0,0 +1,68 @@
|
|||
fn s() -> String {
|
||||
let a = String::new();
|
||||
dbg!(a);
|
||||
return a; //~ ERROR use of moved value:
|
||||
}
|
||||
|
||||
fn m() -> String {
|
||||
let a = String::new();
|
||||
dbg!(1, 2, a, 1, 2);
|
||||
return a; //~ ERROR use of moved value:
|
||||
}
|
||||
|
||||
fn t(a: String) -> String {
|
||||
let b: String = "".to_string();
|
||||
dbg!(a, b);
|
||||
return b; //~ ERROR use of moved value:
|
||||
}
|
||||
|
||||
fn x(a: String) -> String {
|
||||
let b: String = "".to_string();
|
||||
dbg!(a, b);
|
||||
return a; //~ ERROR use of moved value:
|
||||
}
|
||||
|
||||
macro_rules! my_dbg {
|
||||
() => {
|
||||
eprintln!("[{}:{}:{}]", file!(), line!(), column!())
|
||||
};
|
||||
($val:expr $(,)?) => {
|
||||
match $val {
|
||||
tmp => {
|
||||
eprintln!("[{}:{}:{}] {} = {:#?}",
|
||||
file!(), line!(), column!(), stringify!($val), &tmp);
|
||||
tmp
|
||||
}
|
||||
}
|
||||
};
|
||||
($($val:expr),+ $(,)?) => {
|
||||
($(my_dbg!($val)),+,)
|
||||
};
|
||||
}
|
||||
|
||||
fn test_my_dbg() -> String {
|
||||
let b: String = "".to_string();
|
||||
my_dbg!(b, 1);
|
||||
return b; //~ ERROR use of moved value:
|
||||
}
|
||||
|
||||
fn test_not_macro() -> String {
|
||||
let a = String::new();
|
||||
let _b = match a {
|
||||
tmp => {
|
||||
eprintln!("dbg: {}", tmp);
|
||||
tmp
|
||||
}
|
||||
};
|
||||
return a; //~ ERROR use of moved value:
|
||||
}
|
||||
|
||||
fn get_expr(_s: String) {}
|
||||
|
||||
fn test() {
|
||||
let a: String = "".to_string();
|
||||
let _res = get_expr(dbg!(a));
|
||||
let _l = a.len(); //~ ERROR borrow of moved value
|
||||
}
|
||||
|
||||
fn main() {}
|
117
tests/ui/borrowck/dbg-issue-120327.stderr
Normal file
117
tests/ui/borrowck/dbg-issue-120327.stderr
Normal file
|
@ -0,0 +1,117 @@
|
|||
error[E0382]: use of moved value: `a`
|
||||
--> $DIR/dbg-issue-120327.rs:4:12
|
||||
|
|
||||
LL | let a = String::new();
|
||||
| - move occurs because `a` has type `String`, which does not implement the `Copy` trait
|
||||
LL | dbg!(a);
|
||||
| ------- value moved here
|
||||
LL | return a;
|
||||
| ^ value used here after move
|
||||
|
|
||||
help: consider borrowing instead of transferring ownership
|
||||
|
|
||||
LL | dbg!(&a);
|
||||
| +
|
||||
|
||||
error[E0382]: use of moved value: `a`
|
||||
--> $DIR/dbg-issue-120327.rs:10:12
|
||||
|
|
||||
LL | let a = String::new();
|
||||
| - move occurs because `a` has type `String`, which does not implement the `Copy` trait
|
||||
LL | dbg!(1, 2, a, 1, 2);
|
||||
| ------------------- value moved here
|
||||
LL | return a;
|
||||
| ^ value used here after move
|
||||
|
|
||||
help: consider borrowing instead of transferring ownership
|
||||
|
|
||||
LL | dbg!(1, 2, &a, 1, 2);
|
||||
| +
|
||||
|
||||
error[E0382]: use of moved value: `b`
|
||||
--> $DIR/dbg-issue-120327.rs:16:12
|
||||
|
|
||||
LL | let b: String = "".to_string();
|
||||
| - move occurs because `b` has type `String`, which does not implement the `Copy` trait
|
||||
LL | dbg!(a, b);
|
||||
| ---------- value moved here
|
||||
LL | return b;
|
||||
| ^ value used here after move
|
||||
|
|
||||
help: consider borrowing instead of transferring ownership
|
||||
|
|
||||
LL | dbg!(a, &b);
|
||||
| +
|
||||
|
||||
error[E0382]: use of moved value: `a`
|
||||
--> $DIR/dbg-issue-120327.rs:22:12
|
||||
|
|
||||
LL | fn x(a: String) -> String {
|
||||
| - move occurs because `a` has type `String`, which does not implement the `Copy` trait
|
||||
LL | let b: String = "".to_string();
|
||||
LL | dbg!(a, b);
|
||||
| ---------- value moved here
|
||||
LL | return a;
|
||||
| ^ value used here after move
|
||||
|
|
||||
help: consider borrowing instead of transferring ownership
|
||||
|
|
||||
LL | dbg!(&a, b);
|
||||
| +
|
||||
|
||||
error[E0382]: use of moved value: `b`
|
||||
--> $DIR/dbg-issue-120327.rs:46:12
|
||||
|
|
||||
LL | tmp => {
|
||||
| --- value moved here
|
||||
...
|
||||
LL | let b: String = "".to_string();
|
||||
| - move occurs because `b` has type `String`, which does not implement the `Copy` trait
|
||||
LL | my_dbg!(b, 1);
|
||||
LL | return b;
|
||||
| ^ value used here after move
|
||||
|
|
||||
help: consider borrowing instead of transferring ownership
|
||||
|
|
||||
LL | my_dbg!(&b, 1);
|
||||
| +
|
||||
help: borrow this binding in the pattern to avoid moving the value
|
||||
|
|
||||
LL | ref tmp => {
|
||||
| +++
|
||||
|
||||
error[E0382]: use of moved value: `a`
|
||||
--> $DIR/dbg-issue-120327.rs:57:12
|
||||
|
|
||||
LL | let a = String::new();
|
||||
| - move occurs because `a` has type `String`, which does not implement the `Copy` trait
|
||||
LL | let _b = match a {
|
||||
LL | tmp => {
|
||||
| --- value moved here
|
||||
...
|
||||
LL | return a;
|
||||
| ^ value used here after move
|
||||
|
|
||||
help: borrow this binding in the pattern to avoid moving the value
|
||||
|
|
||||
LL | ref tmp => {
|
||||
| +++
|
||||
|
||||
error[E0382]: borrow of moved value: `a`
|
||||
--> $DIR/dbg-issue-120327.rs:65:14
|
||||
|
|
||||
LL | let a: String = "".to_string();
|
||||
| - move occurs because `a` has type `String`, which does not implement the `Copy` trait
|
||||
LL | let _res = get_expr(dbg!(a));
|
||||
| ------- value moved here
|
||||
LL | let _l = a.len();
|
||||
| ^ value borrowed here after move
|
||||
|
|
||||
help: consider borrowing instead of transferring ownership
|
||||
|
|
||||
LL | let _res = get_expr(dbg!(&a));
|
||||
| +
|
||||
|
||||
error: aborting due to 7 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0382`.
|
23
tests/ui/methods/filter-relevant-fn-bounds.rs
Normal file
23
tests/ui/methods/filter-relevant-fn-bounds.rs
Normal file
|
@ -0,0 +1,23 @@
|
|||
trait Output<'a> {
|
||||
type Type;
|
||||
}
|
||||
|
||||
struct Wrapper;
|
||||
|
||||
impl Wrapper {
|
||||
fn do_something_wrapper<O, F>(self, _: F)
|
||||
//~^ ERROR the trait bound `for<'a> F: Output<'a>` is not satisfied
|
||||
//~| ERROR the trait bound `for<'a> F: Output<'a>` is not satisfied
|
||||
where
|
||||
F: for<'a> FnOnce(<F as Output<'a>>::Type),
|
||||
//~^ ERROR the trait bound `F: Output<'_>` is not satisfied
|
||||
//~| ERROR the trait bound `F: Output<'_>` is not satisfied
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut wrapper = Wrapper;
|
||||
wrapper.do_something_wrapper(|value| ());
|
||||
//~^ ERROR expected a `FnOnce
|
||||
}
|
74
tests/ui/methods/filter-relevant-fn-bounds.stderr
Normal file
74
tests/ui/methods/filter-relevant-fn-bounds.stderr
Normal file
|
@ -0,0 +1,74 @@
|
|||
error[E0277]: the trait bound `for<'a> F: Output<'a>` is not satisfied
|
||||
--> $DIR/filter-relevant-fn-bounds.rs:8:5
|
||||
|
|
||||
LL | / fn do_something_wrapper<O, F>(self, _: F)
|
||||
LL | |
|
||||
LL | |
|
||||
LL | | where
|
||||
LL | | F: for<'a> FnOnce(<F as Output<'a>>::Type),
|
||||
| |___________________________________________________^ the trait `for<'a> Output<'a>` is not implemented for `F`
|
||||
|
|
||||
help: consider further restricting this bound
|
||||
|
|
||||
LL | F: for<'a> FnOnce(<F as Output<'a>>::Type) + for<'a> Output<'a>,
|
||||
| ++++++++++++++++++++
|
||||
|
||||
error[E0277]: the trait bound `for<'a> F: Output<'a>` is not satisfied
|
||||
--> $DIR/filter-relevant-fn-bounds.rs:8:8
|
||||
|
|
||||
LL | fn do_something_wrapper<O, F>(self, _: F)
|
||||
| ^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> Output<'a>` is not implemented for `F`
|
||||
|
|
||||
help: consider further restricting this bound
|
||||
|
|
||||
LL | F: for<'a> FnOnce(<F as Output<'a>>::Type) + for<'a> Output<'a>,
|
||||
| ++++++++++++++++++++
|
||||
|
||||
error[E0277]: the trait bound `F: Output<'_>` is not satisfied
|
||||
--> $DIR/filter-relevant-fn-bounds.rs:12:12
|
||||
|
|
||||
LL | F: for<'a> FnOnce(<F as Output<'a>>::Type),
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Output<'_>` is not implemented for `F`
|
||||
|
|
||||
help: consider further restricting this bound
|
||||
|
|
||||
LL | F: for<'a> FnOnce(<F as Output<'a>>::Type) + Output<'_>,
|
||||
| ++++++++++++
|
||||
|
||||
error[E0277]: the trait bound `F: Output<'_>` is not satisfied
|
||||
--> $DIR/filter-relevant-fn-bounds.rs:12:20
|
||||
|
|
||||
LL | F: for<'a> FnOnce(<F as Output<'a>>::Type),
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Output<'_>` is not implemented for `F`
|
||||
|
|
||||
help: consider further restricting this bound
|
||||
|
|
||||
LL | F: for<'a> FnOnce(<F as Output<'a>>::Type) + Output<'_>,
|
||||
| ++++++++++++
|
||||
|
||||
error[E0277]: expected a `FnOnce(<{closure@$DIR/filter-relevant-fn-bounds.rs:21:34: 21:41} as Output<'a>>::Type)` closure, found `{closure@$DIR/filter-relevant-fn-bounds.rs:21:34: 21:41}`
|
||||
--> $DIR/filter-relevant-fn-bounds.rs:21:34
|
||||
|
|
||||
LL | wrapper.do_something_wrapper(|value| ());
|
||||
| -------------------- ^^^^^^^^^^ expected an `FnOnce(<{closure@$DIR/filter-relevant-fn-bounds.rs:21:34: 21:41} as Output<'a>>::Type)` closure, found `{closure@$DIR/filter-relevant-fn-bounds.rs:21:34: 21:41}`
|
||||
| |
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
= help: the trait `for<'a> Output<'a>` is not implemented for closure `{closure@$DIR/filter-relevant-fn-bounds.rs:21:34: 21:41}`
|
||||
help: this trait has no implementations, consider adding one
|
||||
--> $DIR/filter-relevant-fn-bounds.rs:1:1
|
||||
|
|
||||
LL | trait Output<'a> {
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
note: required by a bound in `Wrapper::do_something_wrapper`
|
||||
--> $DIR/filter-relevant-fn-bounds.rs:12:12
|
||||
|
|
||||
LL | fn do_something_wrapper<O, F>(self, _: F)
|
||||
| -------------------- required by a bound in this associated function
|
||||
...
|
||||
LL | F: for<'a> FnOnce(<F as Output<'a>>::Type),
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Wrapper::do_something_wrapper`
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
|
@ -9,6 +9,10 @@ LL | let _ = dbg!(a);
|
|||
| ^^^^^^^ value used here after move
|
||||
|
|
||||
= note: this error originates in the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
help: consider borrowing instead of transferring ownership
|
||||
|
|
||||
LL | let _ = dbg!(&a);
|
||||
| +
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue