Make it a lint for all opaque types
This commit is contained in:
parent
d0d6af9146
commit
426424b320
@ -434,6 +434,6 @@ lint_check_name_warning = {$msg}
|
|||||||
|
|
||||||
lint_check_name_deprecated = lint name `{$lint_name}` is deprecated and does not have an effect anymore. Use: {$new_name}
|
lint_check_name_deprecated = lint name `{$lint_name}` is deprecated and does not have an effect anymore. Use: {$new_name}
|
||||||
|
|
||||||
lint_rpit_hidden_inferred_bound = return-position `{$ty}` does not satisfy its associated type bounds
|
lint_opaque_hidden_inferred_bound = opaque type `{$ty}` does not satisfy its associated type bounds
|
||||||
.specifically = this associated type bound is unsatisfied for `{$proj_ty}`
|
.specifically = this associated type bound is unsatisfied for `{$proj_ty}`
|
||||||
.suggestion = add this bound
|
.suggestion = add this bound
|
||||||
|
@ -62,10 +62,10 @@ mod non_ascii_idents;
|
|||||||
mod non_fmt_panic;
|
mod non_fmt_panic;
|
||||||
mod nonstandard_style;
|
mod nonstandard_style;
|
||||||
mod noop_method_call;
|
mod noop_method_call;
|
||||||
|
mod opaque_hidden_inferred_bound;
|
||||||
mod pass_by_value;
|
mod pass_by_value;
|
||||||
mod passes;
|
mod passes;
|
||||||
mod redundant_semicolon;
|
mod redundant_semicolon;
|
||||||
mod rpit_hidden_inferred_bound;
|
|
||||||
mod traits;
|
mod traits;
|
||||||
mod types;
|
mod types;
|
||||||
mod unused;
|
mod unused;
|
||||||
@ -94,9 +94,9 @@ use non_ascii_idents::*;
|
|||||||
use non_fmt_panic::NonPanicFmt;
|
use non_fmt_panic::NonPanicFmt;
|
||||||
use nonstandard_style::*;
|
use nonstandard_style::*;
|
||||||
use noop_method_call::*;
|
use noop_method_call::*;
|
||||||
|
use opaque_hidden_inferred_bound::*;
|
||||||
use pass_by_value::*;
|
use pass_by_value::*;
|
||||||
use redundant_semicolon::*;
|
use redundant_semicolon::*;
|
||||||
use rpit_hidden_inferred_bound::*;
|
|
||||||
use traits::*;
|
use traits::*;
|
||||||
use types::*;
|
use types::*;
|
||||||
use unused::*;
|
use unused::*;
|
||||||
@ -225,7 +225,7 @@ macro_rules! late_lint_mod_passes {
|
|||||||
EnumIntrinsicsNonEnums: EnumIntrinsicsNonEnums,
|
EnumIntrinsicsNonEnums: EnumIntrinsicsNonEnums,
|
||||||
InvalidAtomicOrdering: InvalidAtomicOrdering,
|
InvalidAtomicOrdering: InvalidAtomicOrdering,
|
||||||
NamedAsmLabels: NamedAsmLabels,
|
NamedAsmLabels: NamedAsmLabels,
|
||||||
RpitHiddenInferredBound: RpitHiddenInferredBound,
|
OpaqueHiddenInferredBound: OpaqueHiddenInferredBound,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
125
compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
Normal file
125
compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
use rustc_hir as hir;
|
||||||
|
use rustc_infer::infer::TyCtxtInferExt;
|
||||||
|
use rustc_macros::LintDiagnostic;
|
||||||
|
use rustc_middle::ty::{self, fold::BottomUpFolder, Ty, TypeFoldable};
|
||||||
|
use rustc_span::Span;
|
||||||
|
use rustc_trait_selection::traits;
|
||||||
|
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
|
||||||
|
|
||||||
|
use crate::{LateContext, LateLintPass, LintContext};
|
||||||
|
|
||||||
|
declare_lint! {
|
||||||
|
/// The `opaque_hidden_inferred_bound` lint detects cases in which nested
|
||||||
|
/// `impl Trait` in associated type bounds are not written generally enough
|
||||||
|
/// to satisfy the bounds of the associated type. This functionality was
|
||||||
|
/// removed in #97346, but then rolled back in #99860 because it was made
|
||||||
|
/// into a hard error too quickly.
|
||||||
|
///
|
||||||
|
/// We plan on reintroducing this as a hard error, but in the mean time, this
|
||||||
|
/// lint serves to warn and suggest fixes for any use-cases which rely on this
|
||||||
|
/// behavior.
|
||||||
|
pub OPAQUE_HIDDEN_INFERRED_BOUND,
|
||||||
|
Warn,
|
||||||
|
"detects the use of nested `impl Trait` types in associated type bounds that are not general enough"
|
||||||
|
}
|
||||||
|
|
||||||
|
declare_lint_pass!(OpaqueHiddenInferredBound => [OPAQUE_HIDDEN_INFERRED_BOUND]);
|
||||||
|
|
||||||
|
impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound {
|
||||||
|
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
|
||||||
|
let hir::ItemKind::OpaqueTy(_) = &item.kind else { return; };
|
||||||
|
let def_id = item.def_id.def_id.to_def_id();
|
||||||
|
cx.tcx.infer_ctxt().enter(|ref infcx| {
|
||||||
|
// For every projection predicate in the opaque type's explicit bounds,
|
||||||
|
// check that the type that we're assigning actually satisfies the bounds
|
||||||
|
// of the associated type.
|
||||||
|
for &(pred, pred_span) in cx.tcx.explicit_item_bounds(def_id) {
|
||||||
|
// Liberate bound regions in the predicate since we
|
||||||
|
// don't actually care about lifetimes in this check.
|
||||||
|
let predicate = cx.tcx.liberate_late_bound_regions(
|
||||||
|
def_id,
|
||||||
|
pred.kind(),
|
||||||
|
);
|
||||||
|
let ty::PredicateKind::Projection(proj) = predicate else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
// Only check types, since those are the only things that may
|
||||||
|
// have opaques in them anyways.
|
||||||
|
let Some(proj_term) = proj.term.ty() else { continue };
|
||||||
|
|
||||||
|
let proj_ty =
|
||||||
|
cx
|
||||||
|
.tcx
|
||||||
|
.mk_projection(proj.projection_ty.item_def_id, proj.projection_ty.substs);
|
||||||
|
// For every instance of the projection type in the bounds,
|
||||||
|
// replace them with the term we're assigning to the associated
|
||||||
|
// type in our opaque type.
|
||||||
|
let proj_replacer = &mut BottomUpFolder {
|
||||||
|
tcx: cx.tcx,
|
||||||
|
ty_op: |ty| if ty == proj_ty { proj_term } else { ty },
|
||||||
|
lt_op: |lt| lt,
|
||||||
|
ct_op: |ct| ct,
|
||||||
|
};
|
||||||
|
// For example, in `impl Trait<Assoc = impl Send>`, for all of the bounds on `Assoc`,
|
||||||
|
// e.g. `type Assoc: OtherTrait`, replace `<impl Trait as Trait>::Assoc: OtherTrait`
|
||||||
|
// with `impl Send: OtherTrait`.
|
||||||
|
for assoc_pred_and_span in cx
|
||||||
|
.tcx
|
||||||
|
.bound_explicit_item_bounds(proj.projection_ty.item_def_id)
|
||||||
|
.transpose_iter()
|
||||||
|
{
|
||||||
|
let assoc_pred_span = assoc_pred_and_span.0.1;
|
||||||
|
let assoc_pred = assoc_pred_and_span
|
||||||
|
.map_bound(|(pred, _)| *pred)
|
||||||
|
.subst(cx.tcx, &proj.projection_ty.substs)
|
||||||
|
.fold_with(proj_replacer);
|
||||||
|
let Ok(assoc_pred) = traits::fully_normalize(infcx, traits::ObligationCause::dummy(), cx.param_env, assoc_pred) else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
// If that predicate doesn't hold modulo regions (but passed during type-check),
|
||||||
|
// then we must've taken advantage of the hack in `project_and_unify_types` where
|
||||||
|
// we replace opaques with inference vars. Emit a warning!
|
||||||
|
if !infcx.predicate_must_hold_modulo_regions(&traits::Obligation::new(
|
||||||
|
traits::ObligationCause::dummy(),
|
||||||
|
cx.param_env,
|
||||||
|
assoc_pred,
|
||||||
|
)) {
|
||||||
|
// If it's a trait bound and an opaque that doesn't satisfy it,
|
||||||
|
// then we can emit a suggestion to add the bound.
|
||||||
|
let (suggestion, suggest_span) =
|
||||||
|
match (proj_term.kind(), assoc_pred.kind().skip_binder()) {
|
||||||
|
(ty::Opaque(def_id, _), ty::PredicateKind::Trait(trait_pred)) => (
|
||||||
|
format!(" + {}", trait_pred.print_modifiers_and_trait_path()),
|
||||||
|
Some(cx.tcx.def_span(def_id).shrink_to_hi()),
|
||||||
|
),
|
||||||
|
_ => (String::new(), None),
|
||||||
|
};
|
||||||
|
cx.emit_spanned_lint(
|
||||||
|
OPAQUE_HIDDEN_INFERRED_BOUND,
|
||||||
|
pred_span,
|
||||||
|
OpaqueHiddenInferredBoundLint {
|
||||||
|
ty: cx.tcx.mk_opaque(def_id, ty::InternalSubsts::identity_for_item(cx.tcx, def_id)),
|
||||||
|
proj_ty: proj_term,
|
||||||
|
assoc_pred_span,
|
||||||
|
suggestion,
|
||||||
|
suggest_span,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(LintDiagnostic)]
|
||||||
|
#[diag(lint::opaque_hidden_inferred_bound)]
|
||||||
|
struct OpaqueHiddenInferredBoundLint<'tcx> {
|
||||||
|
ty: Ty<'tcx>,
|
||||||
|
proj_ty: Ty<'tcx>,
|
||||||
|
#[label(lint::specifically)]
|
||||||
|
assoc_pred_span: Span,
|
||||||
|
#[suggestion_verbose(applicability = "machine-applicable", code = "{suggestion}")]
|
||||||
|
suggest_span: Option<Span>,
|
||||||
|
suggestion: String,
|
||||||
|
}
|
@ -1,143 +0,0 @@
|
|||||||
use hir::def_id::LocalDefId;
|
|
||||||
use rustc_hir as hir;
|
|
||||||
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
|
|
||||||
use rustc_macros::LintDiagnostic;
|
|
||||||
use rustc_middle::ty::{
|
|
||||||
self, fold::BottomUpFolder, Ty, TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitor,
|
|
||||||
};
|
|
||||||
use rustc_span::Span;
|
|
||||||
use rustc_trait_selection::traits;
|
|
||||||
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
|
|
||||||
|
|
||||||
use crate::{LateContext, LateLintPass, LintContext};
|
|
||||||
|
|
||||||
declare_lint! {
|
|
||||||
/// The `rpit_hidden_inferred_bound` lint detects cases in which nested RPITs
|
|
||||||
/// in associated type bounds are not written generally enough to satisfy the
|
|
||||||
/// bounds of the associated type. This functionality was removed in #97346,
|
|
||||||
/// but then rolled back in #99860 because it was made into a hard error too
|
|
||||||
/// quickly.
|
|
||||||
///
|
|
||||||
/// We plan on reintroducing this as a hard error, but in the mean time, this
|
|
||||||
/// lint serves to warn and suggest fixes for any use-cases which rely on this
|
|
||||||
/// behavior.
|
|
||||||
pub RPIT_HIDDEN_INFERRED_BOUND,
|
|
||||||
Warn,
|
|
||||||
"detects the use of nested RPITs in associated type bounds that are not general enough"
|
|
||||||
}
|
|
||||||
|
|
||||||
declare_lint_pass!(RpitHiddenInferredBound => [RPIT_HIDDEN_INFERRED_BOUND]);
|
|
||||||
|
|
||||||
impl<'tcx> LateLintPass<'tcx> for RpitHiddenInferredBound {
|
|
||||||
fn check_fn(
|
|
||||||
&mut self,
|
|
||||||
cx: &LateContext<'tcx>,
|
|
||||||
kind: hir::intravisit::FnKind<'tcx>,
|
|
||||||
_: &'tcx hir::FnDecl<'tcx>,
|
|
||||||
_: &'tcx hir::Body<'tcx>,
|
|
||||||
_: rustc_span::Span,
|
|
||||||
id: hir::HirId,
|
|
||||||
) {
|
|
||||||
if matches!(kind, hir::intravisit::FnKind::Closure) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let fn_def_id = cx.tcx.hir().local_def_id(id);
|
|
||||||
let sig: ty::FnSig<'tcx> =
|
|
||||||
cx.tcx.liberate_late_bound_regions(fn_def_id.to_def_id(), cx.tcx.fn_sig(fn_def_id));
|
|
||||||
cx.tcx.infer_ctxt().enter(|ref infcx| {
|
|
||||||
sig.output().visit_with(&mut VisitOpaqueBounds { infcx, cx, fn_def_id });
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct VisitOpaqueBounds<'a, 'cx, 'tcx> {
|
|
||||||
infcx: &'a InferCtxt<'a, 'tcx>,
|
|
||||||
cx: &'cx LateContext<'tcx>,
|
|
||||||
fn_def_id: LocalDefId,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'tcx> TypeVisitor<'tcx> for VisitOpaqueBounds<'_, '_, 'tcx> {
|
|
||||||
fn visit_ty(&mut self, ty: Ty<'tcx>) -> std::ops::ControlFlow<Self::BreakTy> {
|
|
||||||
if let ty::Opaque(def_id, substs) = *ty.kind()
|
|
||||||
&& let Some(hir::Node::Item(item)) = self.cx.tcx.hir().get_if_local(def_id)
|
|
||||||
&& let hir::ItemKind::OpaqueTy(opaque) = &item.kind
|
|
||||||
&& let hir::OpaqueTyOrigin::FnReturn(origin_def_id) = opaque.origin
|
|
||||||
&& origin_def_id == self.fn_def_id
|
|
||||||
{
|
|
||||||
for pred_and_span in self.cx.tcx.bound_explicit_item_bounds(def_id).transpose_iter() {
|
|
||||||
let pred_span = pred_and_span.0.1;
|
|
||||||
let predicate = self.cx.tcx.liberate_late_bound_regions(
|
|
||||||
def_id,
|
|
||||||
pred_and_span.map_bound(|(pred, _)| *pred).subst(self.cx.tcx, substs).kind(),
|
|
||||||
);
|
|
||||||
let ty::PredicateKind::Projection(proj) = predicate else {
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
let Some(proj_term) = proj.term.ty() else { continue };
|
|
||||||
|
|
||||||
let proj_ty = self
|
|
||||||
.cx
|
|
||||||
.tcx
|
|
||||||
.mk_projection(proj.projection_ty.item_def_id, proj.projection_ty.substs);
|
|
||||||
let proj_replacer = &mut BottomUpFolder {
|
|
||||||
tcx: self.cx.tcx,
|
|
||||||
ty_op: |ty| if ty == proj_ty { proj_term } else { ty },
|
|
||||||
lt_op: |lt| lt,
|
|
||||||
ct_op: |ct| ct,
|
|
||||||
};
|
|
||||||
for assoc_pred_and_span in self
|
|
||||||
.cx
|
|
||||||
.tcx
|
|
||||||
.bound_explicit_item_bounds(proj.projection_ty.item_def_id)
|
|
||||||
.transpose_iter()
|
|
||||||
{
|
|
||||||
let assoc_pred_span = assoc_pred_and_span.0.1;
|
|
||||||
let assoc_pred = assoc_pred_and_span
|
|
||||||
.map_bound(|(pred, _)| *pred)
|
|
||||||
.subst(self.cx.tcx, &proj.projection_ty.substs)
|
|
||||||
.fold_with(proj_replacer);
|
|
||||||
if !self.infcx.predicate_must_hold_modulo_regions(&traits::Obligation::new(
|
|
||||||
traits::ObligationCause::dummy(),
|
|
||||||
self.cx.param_env,
|
|
||||||
assoc_pred,
|
|
||||||
)) {
|
|
||||||
let (suggestion, suggest_span) =
|
|
||||||
match (proj_term.kind(), assoc_pred.kind().skip_binder()) {
|
|
||||||
(ty::Opaque(def_id, _), ty::PredicateKind::Trait(trait_pred)) => (
|
|
||||||
format!(" + {}", trait_pred.print_modifiers_and_trait_path()),
|
|
||||||
Some(self.cx.tcx.def_span(def_id).shrink_to_hi()),
|
|
||||||
),
|
|
||||||
_ => (String::new(), None),
|
|
||||||
};
|
|
||||||
self.cx.emit_spanned_lint(
|
|
||||||
RPIT_HIDDEN_INFERRED_BOUND,
|
|
||||||
pred_span,
|
|
||||||
RpitHiddenInferredBoundLint {
|
|
||||||
ty,
|
|
||||||
proj_ty: proj_term,
|
|
||||||
assoc_pred_span,
|
|
||||||
suggestion,
|
|
||||||
suggest_span,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ty.super_visit_with(self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(LintDiagnostic)]
|
|
||||||
#[diag(lint::rpit_hidden_inferred_bound)]
|
|
||||||
struct RpitHiddenInferredBoundLint<'tcx> {
|
|
||||||
ty: Ty<'tcx>,
|
|
||||||
proj_ty: Ty<'tcx>,
|
|
||||||
#[label(lint::specifically)]
|
|
||||||
assoc_pred_span: Span,
|
|
||||||
#[suggestion_verbose(applicability = "machine-applicable", code = "{suggestion}")]
|
|
||||||
suggest_span: Option<Span>,
|
|
||||||
suggestion: String,
|
|
||||||
}
|
|
@ -26,6 +26,7 @@ type Sendable = impl Send;
|
|||||||
// var to make it uphold the `: Duh` bound on `Trait::Assoc`. The opaque
|
// var to make it uphold the `: Duh` bound on `Trait::Assoc`. The opaque
|
||||||
// type does not implement `Duh`, but if its hidden type does.
|
// type does not implement `Duh`, but if its hidden type does.
|
||||||
fn foo() -> impl Trait<Assoc = Sendable> {
|
fn foo() -> impl Trait<Assoc = Sendable> {
|
||||||
|
//~^ WARN opaque type `impl Trait<Assoc = Sendable>` does not satisfy its associated type bounds
|
||||||
|| 42
|
|| 42
|
||||||
}
|
}
|
||||||
|
|
||||||
|
17
src/test/ui/impl-trait/nested-return-type2-tait.stderr
Normal file
17
src/test/ui/impl-trait/nested-return-type2-tait.stderr
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
warning: opaque type `impl Trait<Assoc = Sendable>` does not satisfy its associated type bounds
|
||||||
|
--> $DIR/nested-return-type2-tait.rs:28:24
|
||||||
|
|
|
||||||
|
LL | type Assoc: Duh;
|
||||||
|
| --- this associated type bound is unsatisfied for `Sendable`
|
||||||
|
...
|
||||||
|
LL | fn foo() -> impl Trait<Assoc = Sendable> {
|
||||||
|
| ^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: `#[warn(opaque_hidden_inferred_bound)]` on by default
|
||||||
|
help: add this bound
|
||||||
|
|
|
||||||
|
LL | type Sendable = impl Send + Duh;
|
||||||
|
| +++++
|
||||||
|
|
||||||
|
warning: 1 warning emitted
|
||||||
|
|
@ -23,6 +23,7 @@ impl<R: Duh, F: FnMut() -> R> Trait for F {
|
|||||||
// Lazy TAIT would error out, but we inserted a hack to make it work again,
|
// Lazy TAIT would error out, but we inserted a hack to make it work again,
|
||||||
// keeping backwards compatibility.
|
// keeping backwards compatibility.
|
||||||
fn foo() -> impl Trait<Assoc = impl Send> {
|
fn foo() -> impl Trait<Assoc = impl Send> {
|
||||||
|
//~^ WARN opaque type `impl Trait<Assoc = impl Send>` does not satisfy its associated type bounds
|
||||||
|| 42
|
|| 42
|
||||||
}
|
}
|
||||||
|
|
||||||
|
17
src/test/ui/impl-trait/nested-return-type2.stderr
Normal file
17
src/test/ui/impl-trait/nested-return-type2.stderr
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
warning: opaque type `impl Trait<Assoc = impl Send>` does not satisfy its associated type bounds
|
||||||
|
--> $DIR/nested-return-type2.rs:25:24
|
||||||
|
|
|
||||||
|
LL | type Assoc: Duh;
|
||||||
|
| --- this associated type bound is unsatisfied for `impl Send`
|
||||||
|
...
|
||||||
|
LL | fn foo() -> impl Trait<Assoc = impl Send> {
|
||||||
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: `#[warn(opaque_hidden_inferred_bound)]` on by default
|
||||||
|
help: add this bound
|
||||||
|
|
|
||||||
|
LL | fn foo() -> impl Trait<Assoc = impl Send + Duh> {
|
||||||
|
| +++++
|
||||||
|
|
||||||
|
warning: 1 warning emitted
|
||||||
|
|
@ -17,6 +17,7 @@ impl<F: Duh> Trait for F {
|
|||||||
type Sendable = impl Send;
|
type Sendable = impl Send;
|
||||||
|
|
||||||
fn foo() -> impl Trait<Assoc = Sendable> {
|
fn foo() -> impl Trait<Assoc = Sendable> {
|
||||||
|
//~^ WARN opaque type `impl Trait<Assoc = Sendable>` does not satisfy its associated type bounds
|
||||||
42
|
42
|
||||||
}
|
}
|
||||||
|
|
||||||
|
17
src/test/ui/impl-trait/nested-return-type3-tait.stderr
Normal file
17
src/test/ui/impl-trait/nested-return-type3-tait.stderr
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
warning: opaque type `impl Trait<Assoc = Sendable>` does not satisfy its associated type bounds
|
||||||
|
--> $DIR/nested-return-type3-tait.rs:19:24
|
||||||
|
|
|
||||||
|
LL | type Assoc: Duh;
|
||||||
|
| --- this associated type bound is unsatisfied for `Sendable`
|
||||||
|
...
|
||||||
|
LL | fn foo() -> impl Trait<Assoc = Sendable> {
|
||||||
|
| ^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: `#[warn(opaque_hidden_inferred_bound)]` on by default
|
||||||
|
help: add this bound
|
||||||
|
|
|
||||||
|
LL | type Sendable = impl Send + Duh;
|
||||||
|
| +++++
|
||||||
|
|
||||||
|
warning: 1 warning emitted
|
||||||
|
|
@ -16,6 +16,7 @@ impl<F: Duh> Trait for F {
|
|||||||
|
|
||||||
type Sendable = impl Send;
|
type Sendable = impl Send;
|
||||||
type Traitable = impl Trait<Assoc = Sendable>;
|
type Traitable = impl Trait<Assoc = Sendable>;
|
||||||
|
//~^ WARN opaque type `Traitable` does not satisfy its associated type bounds
|
||||||
|
|
||||||
fn foo() -> Traitable {
|
fn foo() -> Traitable {
|
||||||
42
|
42
|
||||||
|
17
src/test/ui/impl-trait/nested-return-type3-tait2.stderr
Normal file
17
src/test/ui/impl-trait/nested-return-type3-tait2.stderr
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
warning: opaque type `Traitable` does not satisfy its associated type bounds
|
||||||
|
--> $DIR/nested-return-type3-tait2.rs:18:29
|
||||||
|
|
|
||||||
|
LL | type Assoc: Duh;
|
||||||
|
| --- this associated type bound is unsatisfied for `Sendable`
|
||||||
|
...
|
||||||
|
LL | type Traitable = impl Trait<Assoc = Sendable>;
|
||||||
|
| ^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: `#[warn(opaque_hidden_inferred_bound)]` on by default
|
||||||
|
help: add this bound
|
||||||
|
|
|
||||||
|
LL | type Sendable = impl Send + Duh;
|
||||||
|
| +++++
|
||||||
|
|
||||||
|
warning: 1 warning emitted
|
||||||
|
|
@ -15,6 +15,7 @@ impl<F: Duh> Trait for F {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Traitable = impl Trait<Assoc = impl Send>;
|
type Traitable = impl Trait<Assoc = impl Send>;
|
||||||
|
//~^ WARN opaque type `Traitable` does not satisfy its associated type bounds
|
||||||
|
|
||||||
fn foo() -> Traitable {
|
fn foo() -> Traitable {
|
||||||
42
|
42
|
||||||
|
17
src/test/ui/impl-trait/nested-return-type3-tait3.stderr
Normal file
17
src/test/ui/impl-trait/nested-return-type3-tait3.stderr
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
warning: opaque type `Traitable` does not satisfy its associated type bounds
|
||||||
|
--> $DIR/nested-return-type3-tait3.rs:17:29
|
||||||
|
|
|
||||||
|
LL | type Assoc: Duh;
|
||||||
|
| --- this associated type bound is unsatisfied for `impl Send`
|
||||||
|
...
|
||||||
|
LL | type Traitable = impl Trait<Assoc = impl Send>;
|
||||||
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: `#[warn(opaque_hidden_inferred_bound)]` on by default
|
||||||
|
help: add this bound
|
||||||
|
|
|
||||||
|
LL | type Traitable = impl Trait<Assoc = impl Send + Duh>;
|
||||||
|
| +++++
|
||||||
|
|
||||||
|
warning: 1 warning emitted
|
||||||
|
|
@ -13,6 +13,7 @@ impl<F: Duh> Trait for F {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn foo() -> impl Trait<Assoc = impl Send> {
|
fn foo() -> impl Trait<Assoc = impl Send> {
|
||||||
|
//~^ WARN opaque type `impl Trait<Assoc = impl Send>` does not satisfy its associated type bounds
|
||||||
42
|
42
|
||||||
}
|
}
|
||||||
|
|
||||||
|
17
src/test/ui/impl-trait/nested-return-type3.stderr
Normal file
17
src/test/ui/impl-trait/nested-return-type3.stderr
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
warning: opaque type `impl Trait<Assoc = impl Send>` does not satisfy its associated type bounds
|
||||||
|
--> $DIR/nested-return-type3.rs:15:24
|
||||||
|
|
|
||||||
|
LL | type Assoc: Duh;
|
||||||
|
| --- this associated type bound is unsatisfied for `impl Send`
|
||||||
|
...
|
||||||
|
LL | fn foo() -> impl Trait<Assoc = impl Send> {
|
||||||
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: `#[warn(opaque_hidden_inferred_bound)]` on by default
|
||||||
|
help: add this bound
|
||||||
|
|
|
||||||
|
LL | fn foo() -> impl Trait<Assoc = impl Send + Duh> {
|
||||||
|
| +++++
|
||||||
|
|
||||||
|
warning: 1 warning emitted
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user