Auto merge of #129595 - matthiaskrgr:rollup-4udn7nn, r=matthiaskrgr
Rollup of 9 pull requests Successful merges: - #129288 (Use subtyping for `UnsafeFnPointer` coercion, too) - #129405 (Fixing span manipulation and indentation of the suggestion introduced by #126187) - #129518 (gitignore: ignore ICE reports regardless of directory) - #129519 (Remove redundant flags from `lower_ty_common` that can be inferred from the HIR) - #129525 (rustdoc: clean up tuple <-> primitive conversion docs) - #129526 (Use `FxHasher` on new solver unconditionally) - #129544 (Removes dead code from the compiler) - #129553 (add back test for stable-const-can-only-call-stable-const) - #129590 (Avoid taking reference of &TyKind) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
f48062e7d0
4
.gitignore
vendored
4
.gitignore
vendored
@ -56,7 +56,9 @@ build/
|
|||||||
/src/tools/x/target
|
/src/tools/x/target
|
||||||
# Created by default with `src/ci/docker/run.sh`
|
# Created by default with `src/ci/docker/run.sh`
|
||||||
/obj/
|
/obj/
|
||||||
/rustc-ice*
|
|
||||||
|
## ICE reports
|
||||||
|
rustc-ice-*.txt
|
||||||
|
|
||||||
## Temporary files
|
## Temporary files
|
||||||
*~
|
*~
|
||||||
|
@ -4536,6 +4536,7 @@ dependencies = [
|
|||||||
"bitflags 2.6.0",
|
"bitflags 2.6.0",
|
||||||
"derive-where",
|
"derive-where",
|
||||||
"indexmap",
|
"indexmap",
|
||||||
|
"rustc-hash",
|
||||||
"rustc_ast_ir",
|
"rustc_ast_ir",
|
||||||
"rustc_data_structures",
|
"rustc_data_structures",
|
||||||
"rustc_index",
|
"rustc_index",
|
||||||
|
@ -290,7 +290,7 @@ impl<'infcx, 'tcx> crate::MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
|
|||||||
ty: Ty<'_>,
|
ty: Ty<'_>,
|
||||||
is_index: Option<bool>,
|
is_index: Option<bool>,
|
||||||
) -> Diag<'infcx> {
|
) -> Diag<'infcx> {
|
||||||
let type_name = match (&ty.kind(), is_index) {
|
let type_name = match (ty.kind(), is_index) {
|
||||||
(&ty::Array(_, _), Some(true)) | (&ty::Array(_, _), None) => "array",
|
(&ty::Array(_, _), Some(true)) | (&ty::Array(_, _), None) => "array",
|
||||||
(&ty::Slice(_), _) => "slice",
|
(&ty::Slice(_), _) => "slice",
|
||||||
_ => span_bug!(move_from_span, "this path should not cause illegal move"),
|
_ => span_bug!(move_from_span, "this path should not cause illegal move"),
|
||||||
|
@ -201,7 +201,7 @@ fn place_components_conflict<'tcx>(
|
|||||||
|
|
||||||
let base_ty = base.ty(body, tcx).ty;
|
let base_ty = base.ty(body, tcx).ty;
|
||||||
|
|
||||||
match (elem, &base_ty.kind(), access) {
|
match (elem, base_ty.kind(), access) {
|
||||||
(_, _, Shallow(Some(ArtificialField::ArrayLength)))
|
(_, _, Shallow(Some(ArtificialField::ArrayLength)))
|
||||||
| (_, _, Shallow(Some(ArtificialField::FakeBorrow))) => {
|
| (_, _, Shallow(Some(ArtificialField::FakeBorrow))) => {
|
||||||
// The array length is like additional fields on the
|
// The array length is like additional fields on the
|
||||||
|
@ -2043,9 +2043,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||||||
|
|
||||||
let ty_fn_ptr_from = tcx.safe_to_unsafe_fn_ty(fn_sig);
|
let ty_fn_ptr_from = tcx.safe_to_unsafe_fn_ty(fn_sig);
|
||||||
|
|
||||||
if let Err(terr) = self.eq_types(
|
if let Err(terr) = self.sub_types(
|
||||||
*ty,
|
|
||||||
ty_fn_ptr_from,
|
ty_fn_ptr_from,
|
||||||
|
*ty,
|
||||||
location.to_locations(),
|
location.to_locations(),
|
||||||
ConstraintCategory::Cast { unsize_to: None },
|
ConstraintCategory::Cast { unsize_to: None },
|
||||||
) {
|
) {
|
||||||
|
@ -419,7 +419,7 @@ const_eval_unstable_const_fn = `{$def_path}` is not yet stable as a const fn
|
|||||||
const_eval_unstable_in_stable =
|
const_eval_unstable_in_stable =
|
||||||
const-stable function cannot use `#[feature({$gate})]`
|
const-stable function cannot use `#[feature({$gate})]`
|
||||||
.unstable_sugg = if it is not part of the public API, make this function unstably const
|
.unstable_sugg = if it is not part of the public API, make this function unstably const
|
||||||
.bypass_sugg = otherwise `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks
|
.bypass_sugg = otherwise `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (but requires team approval)
|
||||||
|
|
||||||
const_eval_unterminated_c_string =
|
const_eval_unterminated_c_string =
|
||||||
reading a null-terminated string starting at {$pointer} with no null found before end of allocation
|
reading a null-terminated string starting at {$pointer} with no null found before end of allocation
|
||||||
|
@ -388,7 +388,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||||||
let (src_pointee_ty, dest_pointee_ty) =
|
let (src_pointee_ty, dest_pointee_ty) =
|
||||||
self.tcx.struct_lockstep_tails_for_codegen(source_ty, cast_ty, self.param_env);
|
self.tcx.struct_lockstep_tails_for_codegen(source_ty, cast_ty, self.param_env);
|
||||||
|
|
||||||
match (&src_pointee_ty.kind(), &dest_pointee_ty.kind()) {
|
match (src_pointee_ty.kind(), dest_pointee_ty.kind()) {
|
||||||
(&ty::Array(_, length), &ty::Slice(_)) => {
|
(&ty::Array(_, length), &ty::Slice(_)) => {
|
||||||
let ptr = self.read_pointer(src)?;
|
let ptr = self.read_pointer(src)?;
|
||||||
let val = Immediate::new_slice(
|
let val = Immediate::new_slice(
|
||||||
@ -478,9 +478,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||||||
dest: &PlaceTy<'tcx, M::Provenance>,
|
dest: &PlaceTy<'tcx, M::Provenance>,
|
||||||
) -> InterpResult<'tcx> {
|
) -> InterpResult<'tcx> {
|
||||||
trace!("Unsizing {:?} of type {} into {}", *src, src.layout.ty, cast_ty.ty);
|
trace!("Unsizing {:?} of type {} into {}", *src, src.layout.ty, cast_ty.ty);
|
||||||
match (&src.layout.ty.kind(), &cast_ty.ty.kind()) {
|
match (src.layout.ty.kind(), cast_ty.ty.kind()) {
|
||||||
(&ty::Ref(_, s, _), &ty::Ref(_, c, _) | &ty::RawPtr(c, _))
|
(&ty::Ref(_, s, _), &ty::Ref(_, c, _) | &ty::RawPtr(c, _))
|
||||||
| (&ty::RawPtr(s, _), &ty::RawPtr(c, _)) => self.unsize_into_ptr(src, dest, *s, *c),
|
| (&ty::RawPtr(s, _), &ty::RawPtr(c, _)) => self.unsize_into_ptr(src, dest, s, c),
|
||||||
(&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => {
|
(&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => {
|
||||||
assert_eq!(def_a, def_b); // implies same number of fields
|
assert_eq!(def_a, def_b); // implies same number of fields
|
||||||
|
|
||||||
|
@ -392,7 +392,7 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn re_infer(&self, span: Span, reason: RegionInferReason<'_>) -> ty::Region<'tcx> {
|
fn re_infer(&self, span: Span, reason: RegionInferReason<'_>) -> ty::Region<'tcx> {
|
||||||
if let RegionInferReason::BorrowedObjectLifetimeDefault = reason {
|
if let RegionInferReason::ObjectLifetimeDefault = reason {
|
||||||
let e = struct_span_code_err!(
|
let e = struct_span_code_err!(
|
||||||
self.dcx(),
|
self.dcx(),
|
||||||
span,
|
span,
|
||||||
|
@ -608,7 +608,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||||||
|
|
||||||
let mut bound_span_label = |self_ty: Ty<'_>, obligation: &str, quiet: &str| {
|
let mut bound_span_label = |self_ty: Ty<'_>, obligation: &str, quiet: &str| {
|
||||||
let msg = format!("`{}`", if obligation.len() > 50 { quiet } else { obligation });
|
let msg = format!("`{}`", if obligation.len() > 50 { quiet } else { obligation });
|
||||||
match &self_ty.kind() {
|
match self_ty.kind() {
|
||||||
// Point at the type that couldn't satisfy the bound.
|
// Point at the type that couldn't satisfy the bound.
|
||||||
ty::Adt(def, _) => {
|
ty::Adt(def, _) => {
|
||||||
bound_spans.get_mut_or_insert_default(tcx.def_span(def.did())).push(msg)
|
bound_spans.get_mut_or_insert_default(tcx.def_span(def.did())).push(msg)
|
||||||
|
@ -15,11 +15,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||||||
///
|
///
|
||||||
/// *Bare* trait object types are ones that aren't preceded by the keyword `dyn`.
|
/// *Bare* trait object types are ones that aren't preceded by the keyword `dyn`.
|
||||||
/// In edition 2021 and onward we emit a hard error for them.
|
/// In edition 2021 and onward we emit a hard error for them.
|
||||||
pub(super) fn prohibit_or_lint_bare_trait_object_ty(
|
pub(super) fn prohibit_or_lint_bare_trait_object_ty(&self, self_ty: &hir::Ty<'_>) {
|
||||||
&self,
|
|
||||||
self_ty: &hir::Ty<'_>,
|
|
||||||
in_path: bool,
|
|
||||||
) {
|
|
||||||
let tcx = self.tcx();
|
let tcx = self.tcx();
|
||||||
|
|
||||||
let hir::TyKind::TraitObject([poly_trait_ref, ..], _, TraitObjectSyntax::None) =
|
let hir::TyKind::TraitObject([poly_trait_ref, ..], _, TraitObjectSyntax::None) =
|
||||||
@ -28,6 +24,21 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let in_path = match tcx.parent_hir_node(self_ty.hir_id) {
|
||||||
|
hir::Node::Ty(hir::Ty {
|
||||||
|
kind: hir::TyKind::Path(hir::QPath::TypeRelative(qself, _)),
|
||||||
|
..
|
||||||
|
})
|
||||||
|
| hir::Node::Expr(hir::Expr {
|
||||||
|
kind: hir::ExprKind::Path(hir::QPath::TypeRelative(qself, _)),
|
||||||
|
..
|
||||||
|
})
|
||||||
|
| hir::Node::Pat(hir::Pat {
|
||||||
|
kind: hir::PatKind::Path(hir::QPath::TypeRelative(qself, _)),
|
||||||
|
..
|
||||||
|
}) if qself.hir_id == self_ty.hir_id => true,
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
let needs_bracket = in_path
|
let needs_bracket = in_path
|
||||||
&& !tcx
|
&& !tcx
|
||||||
.sess
|
.sess
|
||||||
|
@ -85,10 +85,9 @@ pub enum PredicateFilter {
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum RegionInferReason<'a> {
|
pub enum RegionInferReason<'a> {
|
||||||
/// Lifetime on a trait object behind a reference.
|
/// Lifetime on a trait object that is spelled explicitly, e.g. `+ 'a` or `+ '_`.
|
||||||
/// This allows inferring information from the reference.
|
ExplicitObjectLifetime,
|
||||||
BorrowedObjectLifetimeDefault,
|
/// A trait object's lifetime when it is elided, e.g. `dyn Any`.
|
||||||
/// A trait object's lifetime.
|
|
||||||
ObjectLifetimeDefault,
|
ObjectLifetimeDefault,
|
||||||
/// Generic lifetime parameter
|
/// Generic lifetime parameter
|
||||||
Param(&'a ty::GenericParamDef),
|
Param(&'a ty::GenericParamDef),
|
||||||
@ -1057,7 +1056,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||||||
|
|
||||||
// Find the type of the associated item, and the trait where the associated
|
// Find the type of the associated item, and the trait where the associated
|
||||||
// item is declared.
|
// item is declared.
|
||||||
let bound = match (&qself_ty.kind(), qself_res) {
|
let bound = match (qself_ty.kind(), qself_res) {
|
||||||
(_, Res::SelfTyAlias { alias_to: impl_def_id, is_trait_impl: true, .. }) => {
|
(_, Res::SelfTyAlias { alias_to: impl_def_id, is_trait_impl: true, .. }) => {
|
||||||
// `Self` in an impl of a trait -- we have a concrete self type and a
|
// `Self` in an impl of a trait -- we have a concrete self type and a
|
||||||
// trait reference.
|
// trait reference.
|
||||||
@ -1999,16 +1998,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Lower a type from the HIR to our internal notion of a type.
|
|
||||||
pub fn lower_ty(&self, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> {
|
|
||||||
self.lower_ty_common(hir_ty, false, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Lower a type inside of a path from the HIR to our internal notion of a type.
|
|
||||||
pub fn lower_ty_in_path(&self, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> {
|
|
||||||
self.lower_ty_common(hir_ty, false, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn lower_delegation_ty(&self, idx: hir::InferDelegationKind) -> Ty<'tcx> {
|
fn lower_delegation_ty(&self, idx: hir::InferDelegationKind) -> Ty<'tcx> {
|
||||||
let delegation_sig = self.tcx().inherit_sig_for_delegation_item(self.item_def_id());
|
let delegation_sig = self.tcx().inherit_sig_for_delegation_item(self.item_def_id());
|
||||||
match idx {
|
match idx {
|
||||||
@ -2026,7 +2015,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||||||
/// 2. `in_path`: Whether the type appears inside of a path.
|
/// 2. `in_path`: Whether the type appears inside of a path.
|
||||||
/// Used to provide correct diagnostics for bare trait object types.
|
/// Used to provide correct diagnostics for bare trait object types.
|
||||||
#[instrument(level = "debug", skip(self), ret)]
|
#[instrument(level = "debug", skip(self), ret)]
|
||||||
fn lower_ty_common(&self, hir_ty: &hir::Ty<'tcx>, borrowed: bool, in_path: bool) -> Ty<'tcx> {
|
pub fn lower_ty(&self, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> {
|
||||||
let tcx = self.tcx();
|
let tcx = self.tcx();
|
||||||
|
|
||||||
let result_ty = match &hir_ty.kind {
|
let result_ty = match &hir_ty.kind {
|
||||||
@ -2036,7 +2025,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||||||
hir::TyKind::Ref(region, mt) => {
|
hir::TyKind::Ref(region, mt) => {
|
||||||
let r = self.lower_lifetime(region, RegionInferReason::Reference);
|
let r = self.lower_lifetime(region, RegionInferReason::Reference);
|
||||||
debug!(?r);
|
debug!(?r);
|
||||||
let t = self.lower_ty_common(mt.ty, true, false);
|
let t = self.lower_ty(mt.ty);
|
||||||
Ty::new_ref(tcx, r, t, mt.mutbl)
|
Ty::new_ref(tcx, r, t, mt.mutbl)
|
||||||
}
|
}
|
||||||
hir::TyKind::Never => tcx.types.never,
|
hir::TyKind::Never => tcx.types.never,
|
||||||
@ -2065,20 +2054,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
hir::TyKind::TraitObject(bounds, lifetime, repr) => {
|
hir::TyKind::TraitObject(bounds, lifetime, repr) => {
|
||||||
self.prohibit_or_lint_bare_trait_object_ty(hir_ty, in_path);
|
self.prohibit_or_lint_bare_trait_object_ty(hir_ty);
|
||||||
|
|
||||||
let repr = match repr {
|
let repr = match repr {
|
||||||
TraitObjectSyntax::Dyn | TraitObjectSyntax::None => ty::Dyn,
|
TraitObjectSyntax::Dyn | TraitObjectSyntax::None => ty::Dyn,
|
||||||
TraitObjectSyntax::DynStar => ty::DynStar,
|
TraitObjectSyntax::DynStar => ty::DynStar,
|
||||||
};
|
};
|
||||||
self.lower_trait_object_ty(
|
self.lower_trait_object_ty(hir_ty.span, hir_ty.hir_id, bounds, lifetime, repr)
|
||||||
hir_ty.span,
|
|
||||||
hir_ty.hir_id,
|
|
||||||
bounds,
|
|
||||||
lifetime,
|
|
||||||
borrowed,
|
|
||||||
repr,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
hir::TyKind::Path(hir::QPath::Resolved(maybe_qself, path)) => {
|
hir::TyKind::Path(hir::QPath::Resolved(maybe_qself, path)) => {
|
||||||
debug!(?maybe_qself, ?path);
|
debug!(?maybe_qself, ?path);
|
||||||
@ -2106,7 +2088,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||||||
}
|
}
|
||||||
hir::TyKind::Path(hir::QPath::TypeRelative(qself, segment)) => {
|
hir::TyKind::Path(hir::QPath::TypeRelative(qself, segment)) => {
|
||||||
debug!(?qself, ?segment);
|
debug!(?qself, ?segment);
|
||||||
let ty = self.lower_ty_common(qself, false, true);
|
let ty = self.lower_ty(qself);
|
||||||
self.lower_assoc_path(hir_ty.hir_id, hir_ty.span, ty, qself, segment, false)
|
self.lower_assoc_path(hir_ty.hir_id, hir_ty.span, ty, qself, segment, false)
|
||||||
.map(|(ty, _, _)| ty)
|
.map(|(ty, _, _)| ty)
|
||||||
.unwrap_or_else(|guar| Ty::new_error(tcx, guar))
|
.unwrap_or_else(|guar| Ty::new_error(tcx, guar))
|
||||||
|
@ -30,7 +30,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||||||
hir_id: hir::HirId,
|
hir_id: hir::HirId,
|
||||||
hir_trait_bounds: &[(hir::PolyTraitRef<'tcx>, hir::TraitBoundModifier)],
|
hir_trait_bounds: &[(hir::PolyTraitRef<'tcx>, hir::TraitBoundModifier)],
|
||||||
lifetime: &hir::Lifetime,
|
lifetime: &hir::Lifetime,
|
||||||
borrowed: bool,
|
|
||||||
representation: DynKind,
|
representation: DynKind,
|
||||||
) -> Ty<'tcx> {
|
) -> Ty<'tcx> {
|
||||||
let tcx = self.tcx();
|
let tcx = self.tcx();
|
||||||
@ -325,22 +324,32 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||||||
v.dedup();
|
v.dedup();
|
||||||
let existential_predicates = tcx.mk_poly_existential_predicates(&v);
|
let existential_predicates = tcx.mk_poly_existential_predicates(&v);
|
||||||
|
|
||||||
// Use explicitly-specified region bound.
|
// Use explicitly-specified region bound, unless the bound is missing.
|
||||||
let region_bound = if !lifetime.is_elided() {
|
let region_bound = if !lifetime.is_elided() {
|
||||||
self.lower_lifetime(lifetime, RegionInferReason::ObjectLifetimeDefault)
|
self.lower_lifetime(lifetime, RegionInferReason::ExplicitObjectLifetime)
|
||||||
} else {
|
} else {
|
||||||
self.compute_object_lifetime_bound(span, existential_predicates).unwrap_or_else(|| {
|
self.compute_object_lifetime_bound(span, existential_predicates).unwrap_or_else(|| {
|
||||||
|
// Curiously, we prefer object lifetime default for `+ '_`...
|
||||||
if tcx.named_bound_var(lifetime.hir_id).is_some() {
|
if tcx.named_bound_var(lifetime.hir_id).is_some() {
|
||||||
self.lower_lifetime(lifetime, RegionInferReason::ObjectLifetimeDefault)
|
self.lower_lifetime(lifetime, RegionInferReason::ExplicitObjectLifetime)
|
||||||
} else {
|
} else {
|
||||||
self.re_infer(
|
let reason =
|
||||||
span,
|
if let hir::LifetimeName::ImplicitObjectLifetimeDefault = lifetime.res {
|
||||||
if borrowed {
|
if let hir::Node::Ty(hir::Ty {
|
||||||
RegionInferReason::ObjectLifetimeDefault
|
kind: hir::TyKind::Ref(parent_lifetime, _),
|
||||||
|
..
|
||||||
|
}) = tcx.parent_hir_node(hir_id)
|
||||||
|
&& tcx.named_bound_var(parent_lifetime.hir_id).is_none()
|
||||||
|
{
|
||||||
|
// Parent lifetime must have failed to resolve. Don't emit a redundant error.
|
||||||
|
RegionInferReason::ExplicitObjectLifetime
|
||||||
|
} else {
|
||||||
|
RegionInferReason::ObjectLifetimeDefault
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
RegionInferReason::BorrowedObjectLifetimeDefault
|
RegionInferReason::ExplicitObjectLifetime
|
||||||
},
|
};
|
||||||
)
|
self.re_infer(span, reason)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
@ -798,7 +798,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
// to be object-safe.
|
// to be object-safe.
|
||||||
// We manually call `register_wf_obligation` in the success path
|
// We manually call `register_wf_obligation` in the success path
|
||||||
// below.
|
// below.
|
||||||
let ty = self.lowerer().lower_ty_in_path(qself);
|
let ty = self.lowerer().lower_ty(qself);
|
||||||
(LoweredTy::from_raw(self, span, ty), qself, segment)
|
(LoweredTy::from_raw(self, span, ty), qself, segment)
|
||||||
}
|
}
|
||||||
QPath::LangItem(..) => {
|
QPath::LangItem(..) => {
|
||||||
|
@ -2975,7 +2975,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
let mut suffix_suggestion = sugg.clone();
|
let mut suffix_suggestion = sugg.clone();
|
||||||
suffix_suggestion.push((
|
suffix_suggestion.push((
|
||||||
if matches!(
|
if matches!(
|
||||||
(&expected_ty.kind(), &checked_ty.kind()),
|
(expected_ty.kind(), checked_ty.kind()),
|
||||||
(ty::Int(_) | ty::Uint(_), ty::Float(_))
|
(ty::Int(_) | ty::Uint(_), ty::Float(_))
|
||||||
) {
|
) {
|
||||||
// Remove fractional part from literal, for example `42.0f32` into `42`
|
// Remove fractional part from literal, for example `42.0f32` into `42`
|
||||||
@ -3077,7 +3077,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
err.multipart_suggestion_verbose(msg, suggestion, Applicability::MachineApplicable);
|
err.multipart_suggestion_verbose(msg, suggestion, Applicability::MachineApplicable);
|
||||||
};
|
};
|
||||||
|
|
||||||
match (&expected_ty.kind(), &checked_ty.kind()) {
|
match (expected_ty.kind(), checked_ty.kind()) {
|
||||||
(ty::Int(exp), ty::Int(found)) => {
|
(ty::Int(exp), ty::Int(found)) => {
|
||||||
let (f2e_is_fallible, e2f_is_fallible) = match (exp.bit_width(), found.bit_width())
|
let (f2e_is_fallible, e2f_is_fallible) = match (exp.bit_width(), found.bit_width())
|
||||||
{
|
{
|
||||||
|
@ -1012,7 +1012,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
};
|
};
|
||||||
let mut bound_span_label = |self_ty: Ty<'_>, obligation: &str, quiet: &str| {
|
let mut bound_span_label = |self_ty: Ty<'_>, obligation: &str, quiet: &str| {
|
||||||
let msg = format!("`{}`", if obligation.len() > 50 { quiet } else { obligation });
|
let msg = format!("`{}`", if obligation.len() > 50 { quiet } else { obligation });
|
||||||
match &self_ty.kind() {
|
match self_ty.kind() {
|
||||||
// Point at the type that couldn't satisfy the bound.
|
// Point at the type that couldn't satisfy the bound.
|
||||||
ty::Adt(def, _) => {
|
ty::Adt(def, _) => {
|
||||||
bound_spans.get_mut_or_insert_default(tcx.def_span(def.did())).push(msg)
|
bound_spans.get_mut_or_insert_default(tcx.def_span(def.did())).push(msg)
|
||||||
|
@ -1336,7 +1336,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
// More generally, the expected type wants a tuple variant with one field of an
|
// More generally, the expected type wants a tuple variant with one field of an
|
||||||
// N-arity-tuple, e.g., `V_i((p_0, .., p_N))`. Meanwhile, the user supplied a pattern
|
// N-arity-tuple, e.g., `V_i((p_0, .., p_N))`. Meanwhile, the user supplied a pattern
|
||||||
// with the subpatterns directly in the tuple variant pattern, e.g., `V_i(p_0, .., p_N)`.
|
// with the subpatterns directly in the tuple variant pattern, e.g., `V_i(p_0, .., p_N)`.
|
||||||
let missing_parentheses = match (&expected.kind(), fields, had_err) {
|
let missing_parentheses = match (expected.kind(), fields, had_err) {
|
||||||
// #67037: only do this if we could successfully type-check the expected type against
|
// #67037: only do this if we could successfully type-check the expected type against
|
||||||
// the tuple struct pattern. Otherwise the args could get out of range on e.g.,
|
// the tuple struct pattern. Otherwise the args could get out of range on e.g.,
|
||||||
// `let P() = U;` where `P != U` with `struct P<T>(T);`.
|
// `let P() = U;` where `P != U` with `struct P<T>(T);`.
|
||||||
|
@ -99,6 +99,4 @@ incremental_unrecognized_depnode = unrecognized `DepNode` variant: {$name}
|
|||||||
|
|
||||||
incremental_unrecognized_depnode_label = dep-node label `{$label}` not recognized
|
incremental_unrecognized_depnode_label = dep-node label `{$label}` not recognized
|
||||||
|
|
||||||
incremental_write_dep_graph = failed to write dependency graph to `{$path}`: {$err}
|
|
||||||
|
|
||||||
incremental_write_new = failed to write {$name} to `{$path}`: {$err}
|
incremental_write_new = failed to write {$name} to `{$path}`: {$err}
|
||||||
|
@ -272,13 +272,6 @@ pub struct LoadDepGraph {
|
|||||||
pub err: std::io::Error,
|
pub err: std::io::Error,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
|
||||||
#[diag(incremental_write_dep_graph)]
|
|
||||||
pub struct WriteDepGraph<'a> {
|
|
||||||
pub path: &'a Path,
|
|
||||||
pub err: std::io::Error,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag(incremental_move_dep_graph)]
|
#[diag(incremental_move_dep_graph)]
|
||||||
pub struct MoveDepGraph<'a> {
|
pub struct MoveDepGraph<'a> {
|
||||||
|
@ -1104,7 +1104,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn is_never(this: TyAndLayout<'tcx>) -> bool {
|
fn is_never(this: TyAndLayout<'tcx>) -> bool {
|
||||||
this.ty.kind() == &ty::Never
|
matches!(this.ty.kind(), ty::Never)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_tuple(this: TyAndLayout<'tcx>) -> bool {
|
fn is_tuple(this: TyAndLayout<'tcx>) -> bool {
|
||||||
|
@ -296,7 +296,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||||||
) -> (Ty<'tcx>, Ty<'tcx>) {
|
) -> (Ty<'tcx>, Ty<'tcx>) {
|
||||||
let (mut a, mut b) = (source, target);
|
let (mut a, mut b) = (source, target);
|
||||||
loop {
|
loop {
|
||||||
match (&a.kind(), &b.kind()) {
|
match (a.kind(), b.kind()) {
|
||||||
(&ty::Adt(a_def, a_args), &ty::Adt(b_def, b_args))
|
(&ty::Adt(a_def, a_args), &ty::Adt(b_def, b_args))
|
||||||
if a_def == b_def && a_def.is_struct() =>
|
if a_def == b_def && a_def.is_struct() =>
|
||||||
{
|
{
|
||||||
|
@ -127,7 +127,7 @@ fn lit_to_mir_constant<'tcx>(
|
|||||||
Ok(ConstValue::Scalar(Scalar::from_uint(result, width)))
|
Ok(ConstValue::Scalar(Scalar::from_uint(result, width)))
|
||||||
};
|
};
|
||||||
|
|
||||||
let value = match (lit, &ty.kind()) {
|
let value = match (lit, ty.kind()) {
|
||||||
(ast::LitKind::Str(s, _), ty::Ref(_, inner_ty, _)) if inner_ty.is_str() => {
|
(ast::LitKind::Str(s, _), ty::Ref(_, inner_ty, _)) if inner_ty.is_str() => {
|
||||||
let s = s.as_str();
|
let s = s.as_str();
|
||||||
let allocation = Allocation::from_bytes_byte_aligned_immutable(s.as_bytes());
|
let allocation = Allocation::from_bytes_byte_aligned_immutable(s.as_bytes());
|
||||||
|
@ -29,7 +29,7 @@ pub(crate) fn lit_to_const<'tcx>(
|
|||||||
.unwrap_or_else(|| bug!("expected to create ScalarInt from uint {:?}", result)))
|
.unwrap_or_else(|| bug!("expected to create ScalarInt from uint {:?}", result)))
|
||||||
};
|
};
|
||||||
|
|
||||||
let valtree = match (lit, &ty.kind()) {
|
let valtree = match (lit, ty.kind()) {
|
||||||
(ast::LitKind::Str(s, _), ty::Ref(_, inner_ty, _)) if inner_ty.is_str() => {
|
(ast::LitKind::Str(s, _), ty::Ref(_, inner_ty, _)) if inner_ty.is_str() => {
|
||||||
let str_bytes = s.as_str().as_bytes();
|
let str_bytes = s.as_str().as_bytes();
|
||||||
ty::ValTree::from_raw_bytes(tcx, str_bytes)
|
ty::ValTree::from_raw_bytes(tcx, str_bytes)
|
||||||
|
@ -1035,9 +1035,9 @@ fn find_vtable_types_for_unsizing<'tcx>(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
match (&source_ty.kind(), &target_ty.kind()) {
|
match (source_ty.kind(), target_ty.kind()) {
|
||||||
(&ty::Ref(_, a, _), &ty::Ref(_, b, _) | &ty::RawPtr(b, _))
|
(&ty::Ref(_, a, _), &ty::Ref(_, b, _) | &ty::RawPtr(b, _))
|
||||||
| (&ty::RawPtr(a, _), &ty::RawPtr(b, _)) => ptr_vtable(*a, *b),
|
| (&ty::RawPtr(a, _), &ty::RawPtr(b, _)) => ptr_vtable(a, b),
|
||||||
(&ty::Adt(def_a, _), &ty::Adt(def_b, _)) if def_a.is_box() && def_b.is_box() => {
|
(&ty::Adt(def_a, _), &ty::Adt(def_b, _)) if def_a.is_box() && def_b.is_box() => {
|
||||||
ptr_vtable(source_ty.boxed_ty(), target_ty.boxed_ty())
|
ptr_vtable(source_ty.boxed_ty(), target_ty.boxed_ty())
|
||||||
}
|
}
|
||||||
|
@ -481,10 +481,6 @@ passes_must_not_suspend =
|
|||||||
`must_not_suspend` attribute should be applied to a struct, enum, union, or trait
|
`must_not_suspend` attribute should be applied to a struct, enum, union, or trait
|
||||||
.label = is not a struct, enum, union, or trait
|
.label = is not a struct, enum, union, or trait
|
||||||
|
|
||||||
passes_must_use_async =
|
|
||||||
`must_use` attribute on `async` functions applies to the anonymous `Future` returned by the function, not the value within
|
|
||||||
.label = this attribute does nothing, the `Future`s returned by async functions are already `must_use`
|
|
||||||
|
|
||||||
passes_must_use_no_effect =
|
passes_must_use_no_effect =
|
||||||
`#[must_use]` has no effect when applied to {$article} {$target}
|
`#[must_use]` has no effect when applied to {$article} {$target}
|
||||||
|
|
||||||
|
@ -952,6 +952,16 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||||||
bare_fn_ty.decl.inputs.len() == 1
|
bare_fn_ty.decl.inputs.len() == 1
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
|
}
|
||||||
|
|| if let Some(&[hir::GenericArg::Type(ty)]) = i
|
||||||
|
.of_trait
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|trait_ref| trait_ref.path.segments.last())
|
||||||
|
.map(|last_segment| last_segment.args().args)
|
||||||
|
{
|
||||||
|
matches!(&ty.kind, hir::TyKind::Tup([_]))
|
||||||
|
} else {
|
||||||
|
false
|
||||||
};
|
};
|
||||||
if !is_valid {
|
if !is_valid {
|
||||||
self.dcx().emit_err(errors::DocFakeVariadicNotValid { span: meta.span() });
|
self.dcx().emit_err(errors::DocFakeVariadicNotValid { span: meta.span() });
|
||||||
|
@ -371,13 +371,6 @@ pub struct FfiConstInvalidTarget {
|
|||||||
pub attr_span: Span,
|
pub attr_span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(LintDiagnostic)]
|
|
||||||
#[diag(passes_must_use_async)]
|
|
||||||
pub struct MustUseAsync {
|
|
||||||
#[label]
|
|
||||||
pub span: Span,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(LintDiagnostic)]
|
#[derive(LintDiagnostic)]
|
||||||
#[diag(passes_must_use_no_effect)]
|
#[diag(passes_must_use_no_effect)]
|
||||||
pub struct MustUseNoEffect {
|
pub struct MustUseNoEffect {
|
||||||
|
@ -382,7 +382,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||||||
if !expected_inner.is_fn() || !found_inner.is_fn() {
|
if !expected_inner.is_fn() || !found_inner.is_fn() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
match (&expected_inner.kind(), &found_inner.kind()) {
|
match (expected_inner.kind(), found_inner.kind()) {
|
||||||
(ty::FnPtr(sig_tys, hdr), ty::FnDef(did, args)) => {
|
(ty::FnPtr(sig_tys, hdr), ty::FnDef(did, args)) => {
|
||||||
let sig = sig_tys.with(*hdr);
|
let sig = sig_tys.with(*hdr);
|
||||||
let expected_sig = &(self.normalize_fn_sig)(sig);
|
let expected_sig = &(self.normalize_fn_sig)(sig);
|
||||||
|
@ -4702,10 +4702,15 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||||||
if let hir::ExprKind::Block(b, _) = body.value.kind
|
if let hir::ExprKind::Block(b, _) = body.value.kind
|
||||||
&& b.expr.is_none()
|
&& b.expr.is_none()
|
||||||
{
|
{
|
||||||
|
// The span of '}' in the end of block.
|
||||||
|
let span = self.tcx.sess.source_map().end_point(b.span);
|
||||||
sugg_spans.push((
|
sugg_spans.push((
|
||||||
// The span will point to the closing curly brace `}` of the block.
|
span.shrink_to_lo(),
|
||||||
b.span.shrink_to_hi().with_lo(b.span.hi() - BytePos(1)),
|
format!(
|
||||||
"\n Ok(())\n}".to_string(),
|
"{}{}",
|
||||||
|
" Ok(())\n",
|
||||||
|
self.tcx.sess.source_map().indentation_before(span).unwrap_or_default(),
|
||||||
|
),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
err.multipart_suggestion_verbose(
|
err.multipart_suggestion_verbose(
|
||||||
|
@ -4,7 +4,6 @@ use crate::layout;
|
|||||||
pub(crate) trait QueryContext {
|
pub(crate) trait QueryContext {
|
||||||
type Def: layout::Def;
|
type Def: layout::Def;
|
||||||
type Ref: layout::Ref;
|
type Ref: layout::Ref;
|
||||||
type Scope: Copy;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@ -28,20 +27,17 @@ pub(crate) mod test {
|
|||||||
impl QueryContext for UltraMinimal {
|
impl QueryContext for UltraMinimal {
|
||||||
type Def = Def;
|
type Def = Def;
|
||||||
type Ref = !;
|
type Ref = !;
|
||||||
type Scope = ();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "rustc")]
|
#[cfg(feature = "rustc")]
|
||||||
mod rustc {
|
mod rustc {
|
||||||
use rustc_middle::ty::{Ty, TyCtxt};
|
use rustc_middle::ty::TyCtxt;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
impl<'tcx> super::QueryContext for TyCtxt<'tcx> {
|
impl<'tcx> super::QueryContext for TyCtxt<'tcx> {
|
||||||
type Def = layout::rustc::Def<'tcx>;
|
type Def = layout::rustc::Def<'tcx>;
|
||||||
type Ref = layout::rustc::Ref<'tcx>;
|
type Ref = layout::rustc::Ref<'tcx>;
|
||||||
|
|
||||||
type Scope = Ty<'tcx>;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ edition = "2021"
|
|||||||
bitflags = "2.4.1"
|
bitflags = "2.4.1"
|
||||||
derive-where = "1.2.7"
|
derive-where = "1.2.7"
|
||||||
indexmap = "2.0.0"
|
indexmap = "2.0.0"
|
||||||
|
rustc-hash = "1.1.0"
|
||||||
rustc_ast_ir = { path = "../rustc_ast_ir", default-features = false }
|
rustc_ast_ir = { path = "../rustc_ast_ir", default-features = false }
|
||||||
rustc_data_structures = { path = "../rustc_data_structures", optional = true }
|
rustc_data_structures = { path = "../rustc_data_structures", optional = true }
|
||||||
rustc_index = { path = "../rustc_index", default-features = false }
|
rustc_index = { path = "../rustc_index", default-features = false }
|
||||||
|
@ -1,8 +1,13 @@
|
|||||||
|
use std::hash::BuildHasherDefault;
|
||||||
|
|
||||||
|
use rustc_hash::FxHasher;
|
||||||
|
pub use rustc_hash::{FxHashMap as HashMap, FxHashSet as HashSet};
|
||||||
|
|
||||||
|
pub type IndexMap<K, V> = indexmap::IndexMap<K, V, BuildHasherDefault<FxHasher>>;
|
||||||
|
pub type IndexSet<V> = indexmap::IndexSet<V, BuildHasherDefault<FxHasher>>;
|
||||||
|
|
||||||
#[cfg(feature = "nightly")]
|
#[cfg(feature = "nightly")]
|
||||||
mod impl_ {
|
mod impl_ {
|
||||||
pub use rustc_data_structures::fx::{
|
|
||||||
FxHashMap as HashMap, FxHashSet as HashSet, FxIndexMap as IndexMap, FxIndexSet as IndexSet,
|
|
||||||
};
|
|
||||||
pub use rustc_data_structures::sso::{SsoHashMap, SsoHashSet};
|
pub use rustc_data_structures::sso::{SsoHashMap, SsoHashSet};
|
||||||
pub use rustc_data_structures::stack::ensure_sufficient_stack;
|
pub use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||||
pub use rustc_data_structures::sync::Lrc;
|
pub use rustc_data_structures::sync::Lrc;
|
||||||
@ -10,11 +15,9 @@ mod impl_ {
|
|||||||
|
|
||||||
#[cfg(not(feature = "nightly"))]
|
#[cfg(not(feature = "nightly"))]
|
||||||
mod impl_ {
|
mod impl_ {
|
||||||
pub use std::collections::{HashMap, HashMap as SsoHashMap, HashSet, HashSet as SsoHashSet};
|
pub use std::collections::{HashMap as SsoHashMap, HashSet as SsoHashSet};
|
||||||
pub use std::sync::Arc as Lrc;
|
pub use std::sync::Arc as Lrc;
|
||||||
|
|
||||||
pub use indexmap::{IndexMap, IndexSet};
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn ensure_sufficient_stack<R>(f: impl FnOnce() -> R) -> R {
|
pub fn ensure_sufficient_stack<R>(f: impl FnOnce() -> R) -> R {
|
||||||
f()
|
f()
|
||||||
|
@ -59,6 +59,7 @@ fn box_deref_lval() {
|
|||||||
assert_eq!(x.get(), 1000);
|
assert_eq!(x.get(), 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
pub struct ConstAllocator;
|
pub struct ConstAllocator;
|
||||||
|
|
||||||
unsafe impl Allocator for ConstAllocator {
|
unsafe impl Allocator for ConstAllocator {
|
||||||
|
@ -122,23 +122,29 @@ macro_rules! tuple_impls {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[stable(feature = "array_tuple_conv", since = "1.71.0")]
|
maybe_tuple_doc! {
|
||||||
impl<T> From<[T; ${count($T)}]> for ($(${ignore($T)} T,)+) {
|
$($T)+ @
|
||||||
#[inline]
|
#[stable(feature = "array_tuple_conv", since = "1.71.0")]
|
||||||
#[allow(non_snake_case)]
|
impl<T> From<[T; ${count($T)}]> for ($(${ignore($T)} T,)+) {
|
||||||
fn from(array: [T; ${count($T)}]) -> Self {
|
#[inline]
|
||||||
let [$($T,)+] = array;
|
#[allow(non_snake_case)]
|
||||||
($($T,)+)
|
fn from(array: [T; ${count($T)}]) -> Self {
|
||||||
|
let [$($T,)+] = array;
|
||||||
|
($($T,)+)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[stable(feature = "array_tuple_conv", since = "1.71.0")]
|
maybe_tuple_doc! {
|
||||||
impl<T> From<($(${ignore($T)} T,)+)> for [T; ${count($T)}] {
|
$($T)+ @
|
||||||
#[inline]
|
#[stable(feature = "array_tuple_conv", since = "1.71.0")]
|
||||||
#[allow(non_snake_case)]
|
impl<T> From<($(${ignore($T)} T,)+)> for [T; ${count($T)}] {
|
||||||
fn from(tuple: ($(${ignore($T)} T,)+)) -> Self {
|
#[inline]
|
||||||
let ($($T,)+) = tuple;
|
#[allow(non_snake_case)]
|
||||||
[$($T,)+]
|
fn from(tuple: ($(${ignore($T)} T,)+)) -> Self {
|
||||||
|
let ($($T,)+) = tuple;
|
||||||
|
[$($T,)+]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -148,7 +154,7 @@ macro_rules! tuple_impls {
|
|||||||
// Otherwise, it hides the docs entirely.
|
// Otherwise, it hides the docs entirely.
|
||||||
macro_rules! maybe_tuple_doc {
|
macro_rules! maybe_tuple_doc {
|
||||||
($a:ident @ #[$meta:meta] $item:item) => {
|
($a:ident @ #[$meta:meta] $item:item) => {
|
||||||
#[doc(fake_variadic)]
|
#[cfg_attr(not(bootstrap), doc(fake_variadic))]
|
||||||
#[doc = "This trait is implemented for tuples up to twelve items long."]
|
#[doc = "This trait is implemented for tuples up to twelve items long."]
|
||||||
#[$meta]
|
#[$meta]
|
||||||
$item
|
$item
|
||||||
|
@ -1288,56 +1288,90 @@ impl clean::Impl {
|
|||||||
if self.is_negative_trait_impl() {
|
if self.is_negative_trait_impl() {
|
||||||
write!(f, "!")?;
|
write!(f, "!")?;
|
||||||
}
|
}
|
||||||
ty.print(cx).fmt(f)?;
|
if self.kind.is_fake_variadic()
|
||||||
|
&& let generics = ty.generics()
|
||||||
|
&& let &[inner_type] = generics.as_ref().map_or(&[][..], |v| &v[..])
|
||||||
|
{
|
||||||
|
let last = ty.last();
|
||||||
|
if f.alternate() {
|
||||||
|
write!(f, "{}<", last)?;
|
||||||
|
self.print_type(inner_type, f, use_absolute, cx)?;
|
||||||
|
write!(f, ">")?;
|
||||||
|
} else {
|
||||||
|
write!(f, "{}<", anchor(ty.def_id(), last, cx).to_string())?;
|
||||||
|
self.print_type(inner_type, f, use_absolute, cx)?;
|
||||||
|
write!(f, ">")?;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ty.print(cx).fmt(f)?;
|
||||||
|
}
|
||||||
write!(f, " for ")?;
|
write!(f, " for ")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let clean::Type::Tuple(types) = &self.for_
|
if let Some(ty) = self.kind.as_blanket_ty() {
|
||||||
&& let [clean::Type::Generic(name)] = &types[..]
|
|
||||||
&& (self.kind.is_fake_variadic() || self.kind.is_auto())
|
|
||||||
{
|
|
||||||
// Hardcoded anchor library/core/src/primitive_docs.rs
|
|
||||||
// Link should match `# Trait implementations`
|
|
||||||
primitive_link_fragment(
|
|
||||||
f,
|
|
||||||
PrimitiveType::Tuple,
|
|
||||||
format_args!("({name}₁, {name}₂, …, {name}ₙ)"),
|
|
||||||
"#trait-implementations-1",
|
|
||||||
cx,
|
|
||||||
)?;
|
|
||||||
} else if let clean::BareFunction(bare_fn) = &self.for_
|
|
||||||
&& let [clean::Argument { type_: clean::Type::Generic(name), .. }] =
|
|
||||||
&bare_fn.decl.inputs.values[..]
|
|
||||||
&& (self.kind.is_fake_variadic() || self.kind.is_auto())
|
|
||||||
{
|
|
||||||
// Hardcoded anchor library/core/src/primitive_docs.rs
|
|
||||||
// Link should match `# Trait implementations`
|
|
||||||
|
|
||||||
print_higher_ranked_params_with_space(&bare_fn.generic_params, cx).fmt(f)?;
|
|
||||||
bare_fn.safety.print_with_space().fmt(f)?;
|
|
||||||
print_abi_with_space(bare_fn.abi).fmt(f)?;
|
|
||||||
let ellipsis = if bare_fn.decl.c_variadic { ", ..." } else { "" };
|
|
||||||
primitive_link_fragment(
|
|
||||||
f,
|
|
||||||
PrimitiveType::Tuple,
|
|
||||||
format_args!("fn({name}₁, {name}₂, …, {name}ₙ{ellipsis})"),
|
|
||||||
"#trait-implementations-1",
|
|
||||||
cx,
|
|
||||||
)?;
|
|
||||||
// Write output.
|
|
||||||
if !bare_fn.decl.output.is_unit() {
|
|
||||||
write!(f, " -> ")?;
|
|
||||||
fmt_type(&bare_fn.decl.output, f, use_absolute, cx)?;
|
|
||||||
}
|
|
||||||
} else if let Some(ty) = self.kind.as_blanket_ty() {
|
|
||||||
fmt_type(ty, f, use_absolute, cx)?;
|
fmt_type(ty, f, use_absolute, cx)?;
|
||||||
} else {
|
} else {
|
||||||
fmt_type(&self.for_, f, use_absolute, cx)?;
|
self.print_type(&self.for_, f, use_absolute, cx)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
print_where_clause(&self.generics, cx, 0, Ending::Newline).fmt(f)
|
print_where_clause(&self.generics, cx, 0, Ending::Newline).fmt(f)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
fn print_type<'a, 'tcx: 'a>(
|
||||||
|
&self,
|
||||||
|
type_: &clean::Type,
|
||||||
|
f: &mut fmt::Formatter<'_>,
|
||||||
|
use_absolute: bool,
|
||||||
|
cx: &'a Context<'tcx>,
|
||||||
|
) -> Result<(), fmt::Error> {
|
||||||
|
if let clean::Type::Tuple(types) = type_
|
||||||
|
&& let [clean::Type::Generic(name)] = &types[..]
|
||||||
|
&& (self.kind.is_fake_variadic() || self.kind.is_auto())
|
||||||
|
{
|
||||||
|
// Hardcoded anchor library/core/src/primitive_docs.rs
|
||||||
|
// Link should match `# Trait implementations`
|
||||||
|
primitive_link_fragment(
|
||||||
|
f,
|
||||||
|
PrimitiveType::Tuple,
|
||||||
|
format_args!("({name}₁, {name}₂, …, {name}ₙ)"),
|
||||||
|
"#trait-implementations-1",
|
||||||
|
cx,
|
||||||
|
)?;
|
||||||
|
} else if let clean::Type::Array(ty, len) = type_
|
||||||
|
&& let clean::Type::Generic(name) = &**ty
|
||||||
|
&& &len[..] == "1"
|
||||||
|
&& (self.kind.is_fake_variadic() || self.kind.is_auto())
|
||||||
|
{
|
||||||
|
primitive_link(f, PrimitiveType::Array, format_args!("[{name}; N]"), cx)?;
|
||||||
|
} else if let clean::BareFunction(bare_fn) = &type_
|
||||||
|
&& let [clean::Argument { type_: clean::Type::Generic(name), .. }] =
|
||||||
|
&bare_fn.decl.inputs.values[..]
|
||||||
|
&& (self.kind.is_fake_variadic() || self.kind.is_auto())
|
||||||
|
{
|
||||||
|
// Hardcoded anchor library/core/src/primitive_docs.rs
|
||||||
|
// Link should match `# Trait implementations`
|
||||||
|
|
||||||
|
print_higher_ranked_params_with_space(&bare_fn.generic_params, cx).fmt(f)?;
|
||||||
|
bare_fn.safety.print_with_space().fmt(f)?;
|
||||||
|
print_abi_with_space(bare_fn.abi).fmt(f)?;
|
||||||
|
let ellipsis = if bare_fn.decl.c_variadic { ", ..." } else { "" };
|
||||||
|
primitive_link_fragment(
|
||||||
|
f,
|
||||||
|
PrimitiveType::Tuple,
|
||||||
|
format_args!("fn({name}₁, {name}₂, …, {name}ₙ{ellipsis})"),
|
||||||
|
"#trait-implementations-1",
|
||||||
|
cx,
|
||||||
|
)?;
|
||||||
|
// Write output.
|
||||||
|
if !bare_fn.decl.output.is_unit() {
|
||||||
|
write!(f, " -> ")?;
|
||||||
|
fmt_type(&bare_fn.decl.output, f, use_absolute, cx)?;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fmt_type(&type_, f, use_absolute, cx)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl clean::Arguments {
|
impl clean::Arguments {
|
||||||
|
@ -16,3 +16,20 @@ pub trait Bar {}
|
|||||||
//@ has - '//section[@id="impl-Bar-for-(U,)"]/h3' 'impl<U: Foo> Bar for (U₁, U₂, …, Uₙ)'
|
//@ has - '//section[@id="impl-Bar-for-(U,)"]/h3' 'impl<U: Foo> Bar for (U₁, U₂, …, Uₙ)'
|
||||||
#[doc(fake_variadic)]
|
#[doc(fake_variadic)]
|
||||||
impl<U: Foo> Bar for (U,) {}
|
impl<U: Foo> Bar for (U,) {}
|
||||||
|
|
||||||
|
pub trait Baz<T> { fn baz(&self) -> T { todo!() } }
|
||||||
|
|
||||||
|
//@ has foo/trait.Baz.html
|
||||||
|
//@ has - '//section[@id="impl-Baz%3C(T,)%3E-for-%5BT;+1%5D"]/h3' 'impl<T> Baz<(T₁, T₂, …, Tₙ)> for [T; N]'
|
||||||
|
#[doc(fake_variadic)]
|
||||||
|
impl<T> Baz<(T,)> for [T; 1] {}
|
||||||
|
|
||||||
|
//@ has foo/trait.Baz.html
|
||||||
|
//@ has - '//section[@id="impl-Baz%3C%5BT;+1%5D%3E-for-(T,)"]/h3' 'impl<T> Baz<[T; N]> for (T₁, T₂, …, Tₙ)'
|
||||||
|
#[doc(fake_variadic)]
|
||||||
|
impl<T> Baz<[T; 1]> for (T,) {}
|
||||||
|
|
||||||
|
//@ has foo/trait.Baz.html
|
||||||
|
//@ has - '//section[@id="impl-Baz%3CT%3E-for-(T,)"]/h3' 'impl<T> Baz<T> for (T₁, T₂, …, Tₙ)'
|
||||||
|
#[doc(fake_variadic)]
|
||||||
|
impl<T> Baz<T> for (T,) {}
|
||||||
|
14
tests/ui/coercion/cast-higher-ranked-unsafe-fn-ptr.rs
Normal file
14
tests/ui/coercion/cast-higher-ranked-unsafe-fn-ptr.rs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
//@ check-pass
|
||||||
|
|
||||||
|
fn higher_ranked_fndef(ctx: &mut ()) {}
|
||||||
|
|
||||||
|
fn test(higher_ranked_fnptr: fn(&mut ())) {
|
||||||
|
fn as_unsafe<T>(_: unsafe fn(T)) {}
|
||||||
|
|
||||||
|
// Make sure that we can cast higher-ranked fn items and pointers to
|
||||||
|
// a non-higher-ranked target.
|
||||||
|
as_unsafe(higher_ranked_fndef);
|
||||||
|
as_unsafe(higher_ranked_fnptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
@ -1,6 +1,4 @@
|
|||||||
//@ run-pass
|
//@ run-pass
|
||||||
#![feature(rustc_allow_const_fn_unstable)]
|
|
||||||
|
|
||||||
#![feature(rustc_attrs, staged_api)]
|
#![feature(rustc_attrs, staged_api)]
|
||||||
#![stable(feature = "rust1", since = "1.0.0")]
|
#![stable(feature = "rust1", since = "1.0.0")]
|
||||||
|
|
||||||
|
@ -28,9 +28,11 @@ const fn bar2() -> u32 { foo2() } //~ ERROR not yet stable as a const fn
|
|||||||
// conformity is required
|
// conformity is required
|
||||||
const fn bar3() -> u32 {
|
const fn bar3() -> u32 {
|
||||||
let x = std::cell::Cell::new(0u32);
|
let x = std::cell::Cell::new(0u32);
|
||||||
x.get()
|
x.get();
|
||||||
//~^ ERROR const-stable function cannot use `#[feature(const_refs_to_cell)]`
|
//~^ ERROR const-stable function cannot use `#[feature(const_refs_to_cell)]`
|
||||||
//~| ERROR cannot call non-const fn
|
//~| ERROR cannot call non-const fn
|
||||||
|
foo()
|
||||||
|
//~^ ERROR is not yet stable as a const fn
|
||||||
}
|
}
|
||||||
|
|
||||||
// check whether this function cannot be called even with the feature gate active
|
// check whether this function cannot be called even with the feature gate active
|
||||||
|
@ -17,7 +17,7 @@ LL | const fn bar2() -> u32 { foo2() }
|
|||||||
error: const-stable function cannot use `#[feature(const_refs_to_cell)]`
|
error: const-stable function cannot use `#[feature(const_refs_to_cell)]`
|
||||||
--> $DIR/min_const_fn_libstd_stability.rs:31:5
|
--> $DIR/min_const_fn_libstd_stability.rs:31:5
|
||||||
|
|
|
|
||||||
LL | x.get()
|
LL | x.get();
|
||||||
| ^
|
| ^
|
||||||
|
|
|
|
||||||
help: if it is not part of the public API, make this function unstably const
|
help: if it is not part of the public API, make this function unstably const
|
||||||
@ -25,7 +25,7 @@ help: if it is not part of the public API, make this function unstably const
|
|||||||
LL + #[rustc_const_unstable(feature = "...", issue = "...")]
|
LL + #[rustc_const_unstable(feature = "...", issue = "...")]
|
||||||
LL | const fn bar3() -> u32 {
|
LL | const fn bar3() -> u32 {
|
||||||
|
|
|
|
||||||
help: otherwise `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks
|
help: otherwise `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (but requires team approval)
|
||||||
|
|
|
|
||||||
LL + #[rustc_allow_const_fn_unstable(const_refs_to_cell)]
|
LL + #[rustc_allow_const_fn_unstable(const_refs_to_cell)]
|
||||||
LL | const fn bar3() -> u32 {
|
LL | const fn bar3() -> u32 {
|
||||||
@ -34,19 +34,27 @@ LL | const fn bar3() -> u32 {
|
|||||||
error[E0015]: cannot call non-const fn `Cell::<u32>::get` in constant functions
|
error[E0015]: cannot call non-const fn `Cell::<u32>::get` in constant functions
|
||||||
--> $DIR/min_const_fn_libstd_stability.rs:31:7
|
--> $DIR/min_const_fn_libstd_stability.rs:31:7
|
||||||
|
|
|
|
||||||
LL | x.get()
|
LL | x.get();
|
||||||
| ^^^^^
|
| ^^^^^
|
||||||
|
|
|
|
||||||
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
|
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
|
||||||
|
|
||||||
|
error: `foo` is not yet stable as a const fn
|
||||||
|
--> $DIR/min_const_fn_libstd_stability.rs:34:5
|
||||||
|
|
|
||||||
|
LL | foo()
|
||||||
|
| ^^^^^
|
||||||
|
|
|
||||||
|
= help: const-stable functions can only call other const-stable functions
|
||||||
|
|
||||||
error: `foo2_gated` is not yet stable as a const fn
|
error: `foo2_gated` is not yet stable as a const fn
|
||||||
--> $DIR/min_const_fn_libstd_stability.rs:43:32
|
--> $DIR/min_const_fn_libstd_stability.rs:45:32
|
||||||
|
|
|
|
||||||
LL | const fn bar2_gated() -> u32 { foo2_gated() }
|
LL | const fn bar2_gated() -> u32 { foo2_gated() }
|
||||||
| ^^^^^^^^^^^^
|
| ^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= help: const-stable functions can only call other const-stable functions
|
= help: const-stable functions can only call other const-stable functions
|
||||||
|
|
||||||
error: aborting due to 5 previous errors
|
error: aborting due to 6 previous errors
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0015`.
|
For more information about this error, try `rustc --explain E0015`.
|
||||||
|
14
tests/ui/dyn-keyword/suggest-dyn-on-bare-trait-in-pat.rs
Normal file
14
tests/ui/dyn-keyword/suggest-dyn-on-bare-trait-in-pat.rs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
//@ edition: 2021
|
||||||
|
|
||||||
|
trait Trait {}
|
||||||
|
|
||||||
|
impl dyn Trait {
|
||||||
|
const CONST: () = ();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
match () {
|
||||||
|
Trait::CONST => {}
|
||||||
|
//~^ ERROR trait objects must include the `dyn` keyword
|
||||||
|
}
|
||||||
|
}
|
14
tests/ui/dyn-keyword/suggest-dyn-on-bare-trait-in-pat.stderr
Normal file
14
tests/ui/dyn-keyword/suggest-dyn-on-bare-trait-in-pat.stderr
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
error[E0782]: trait objects must include the `dyn` keyword
|
||||||
|
--> $DIR/suggest-dyn-on-bare-trait-in-pat.rs:11:9
|
||||||
|
|
|
||||||
|
LL | Trait::CONST => {}
|
||||||
|
| ^^^^^
|
||||||
|
|
|
||||||
|
help: add `dyn` keyword before this trait
|
||||||
|
|
|
||||||
|
LL | <dyn Trait>::CONST => {}
|
||||||
|
| ++++ +
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0782`.
|
@ -9,7 +9,6 @@ use std::io::prelude::*;
|
|||||||
fn test1() -> Result<(), Box<dyn std::error::Error>> {
|
fn test1() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let mut _file = File::create("foo.txt")?;
|
let mut _file = File::create("foo.txt")?;
|
||||||
//~^ ERROR the `?` operator can only be used in a function
|
//~^ ERROR the `?` operator can only be used in a function
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -17,7 +16,6 @@ fn test2() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
let mut _file = File::create("foo.txt")?;
|
let mut _file = File::create("foo.txt")?;
|
||||||
//~^ ERROR the `?` operator can only be used in a function
|
//~^ ERROR the `?` operator can only be used in a function
|
||||||
println!();
|
println!();
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -27,9 +25,8 @@ macro_rules! mac {
|
|||||||
let mut _file = File::create("foo.txt")?;
|
let mut _file = File::create("foo.txt")?;
|
||||||
//~^ ERROR the `?` operator can only be used in a function
|
//~^ ERROR the `?` operator can only be used in a function
|
||||||
println!();
|
println!();
|
||||||
|
Ok(())
|
||||||
Ok(())
|
}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -39,23 +36,20 @@ impl A {
|
|||||||
fn test4(&self) -> Result<(), Box<dyn std::error::Error>> {
|
fn test4(&self) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let mut _file = File::create("foo.txt")?;
|
let mut _file = File::create("foo.txt")?;
|
||||||
//~^ ERROR the `?` operator can only be used in a method
|
//~^ ERROR the `?` operator can only be used in a method
|
||||||
|
Ok(())
|
||||||
Ok(())
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fn test5(&self) -> Result<(), Box<dyn std::error::Error>> {
|
fn test5(&self) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let mut _file = File::create("foo.txt")?;
|
let mut _file = File::create("foo.txt")?;
|
||||||
//~^ ERROR the `?` operator can only be used in a method
|
//~^ ERROR the `?` operator can only be used in a method
|
||||||
println!();
|
println!();
|
||||||
|
Ok(())
|
||||||
Ok(())
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let mut _file = File::create("foo.txt")?;
|
let mut _file = File::create("foo.txt")?;
|
||||||
//~^ ERROR the `?` operator can only be used in a function
|
//~^ ERROR the `?` operator can only be used in a function
|
||||||
mac!();
|
mac!();
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -12,9 +12,7 @@ help: consider adding return type
|
|||||||
LL ~ fn test1() -> Result<(), Box<dyn std::error::Error>> {
|
LL ~ fn test1() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
LL | let mut _file = File::create("foo.txt")?;
|
LL | let mut _file = File::create("foo.txt")?;
|
||||||
LL |
|
LL |
|
||||||
LL +
|
|
||||||
LL + Ok(())
|
LL + Ok(())
|
||||||
LL + }
|
|
||||||
|
|
|
|
||||||
|
|
||||||
error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`)
|
error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`)
|
||||||
@ -32,9 +30,7 @@ LL ~ fn test2() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
LL | let mut _file = File::create("foo.txt")?;
|
LL | let mut _file = File::create("foo.txt")?;
|
||||||
LL |
|
LL |
|
||||||
LL | println!();
|
LL | println!();
|
||||||
LL +
|
|
||||||
LL + Ok(())
|
LL + Ok(())
|
||||||
LL + }
|
|
||||||
|
|
|
|
||||||
|
|
||||||
error[E0277]: the `?` operator can only be used in a method that returns `Result` or `Option` (or another type that implements `FromResidual`)
|
error[E0277]: the `?` operator can only be used in a method that returns `Result` or `Option` (or another type that implements `FromResidual`)
|
||||||
@ -51,9 +47,8 @@ help: consider adding return type
|
|||||||
LL ~ fn test4(&self) -> Result<(), Box<dyn std::error::Error>> {
|
LL ~ fn test4(&self) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
LL | let mut _file = File::create("foo.txt")?;
|
LL | let mut _file = File::create("foo.txt")?;
|
||||||
LL |
|
LL |
|
||||||
LL ~
|
LL ~ Ok(())
|
||||||
LL + Ok(())
|
LL ~ }
|
||||||
LL + }
|
|
||||||
|
|
|
|
||||||
|
|
||||||
error[E0277]: the `?` operator can only be used in a method that returns `Result` or `Option` (or another type that implements `FromResidual`)
|
error[E0277]: the `?` operator can only be used in a method that returns `Result` or `Option` (or another type that implements `FromResidual`)
|
||||||
@ -71,9 +66,8 @@ LL ~ fn test5(&self) -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
LL | let mut _file = File::create("foo.txt")?;
|
LL | let mut _file = File::create("foo.txt")?;
|
||||||
LL |
|
LL |
|
||||||
LL | println!();
|
LL | println!();
|
||||||
LL ~
|
LL ~ Ok(())
|
||||||
LL + Ok(())
|
LL ~ }
|
||||||
LL + }
|
|
||||||
|
|
|
|
||||||
|
|
||||||
error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`)
|
error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`)
|
||||||
@ -91,9 +85,7 @@ LL ~ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
LL | let mut _file = File::create("foo.txt")?;
|
LL | let mut _file = File::create("foo.txt")?;
|
||||||
LL |
|
LL |
|
||||||
LL | mac!();
|
LL | mac!();
|
||||||
LL +
|
|
||||||
LL + Ok(())
|
LL + Ok(())
|
||||||
LL + }
|
|
||||||
|
|
|
|
||||||
|
|
||||||
error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`)
|
error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`)
|
||||||
@ -115,9 +107,8 @@ LL ~ fn test3() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
LL | let mut _file = File::create("foo.txt")?;
|
LL | let mut _file = File::create("foo.txt")?;
|
||||||
LL |
|
LL |
|
||||||
LL | println!();
|
LL | println!();
|
||||||
LL ~
|
LL ~ Ok(())
|
||||||
LL + Ok(())
|
LL ~ }
|
||||||
LL + }
|
|
||||||
|
|
|
|
||||||
|
|
||||||
error: aborting due to 6 previous errors
|
error: aborting due to 6 previous errors
|
||||||
|
@ -14,9 +14,7 @@ LL ~ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
LL | // error for a `Try` type on a non-`Try` fn
|
LL | // error for a `Try` type on a non-`Try` fn
|
||||||
...
|
...
|
||||||
LL | try_trait_generic::<()>();
|
LL | try_trait_generic::<()>();
|
||||||
LL +
|
|
||||||
LL + Ok(())
|
LL + Ok(())
|
||||||
LL + }
|
|
||||||
|
|
|
|
||||||
|
|
||||||
error[E0277]: the `?` operator can only be applied to values that implement `Try`
|
error[E0277]: the `?` operator can only be applied to values that implement `Try`
|
||||||
|
Loading…
x
Reference in New Issue
Block a user